Fossil SCM
Merge the latest trunk changes into the arjen-doc-updates branch.
Commit
5d4ef37a9d222f11ee972ac7734e9c1154ade5cc
Parent
7df226540de7632…
89 files changed
+1
-1
+140
-243
+4
-4
+4
-4
+8
-8
+8
-8
+43
-5
+25
-11
+25
-11
+1
-1
+29
-8
+41
-102
+41
-102
+6
-6
+6
-6
+2
-2
+12
-12
+12
-12
+6
-6
+7
-15
+479
-91
+479
-91
+9
-5
+60
-47
+7
-13
+26
-11
+88
-18
+5
-5
+4
-4
+4
-4
+176
-28
+34
-11
+88
+35
-15
+15
-13
+9
+6
-5
+8
-8
+35
-26
+51
-3
+26
-16
+42
-35
+12
-2
+6
-8
+18
-16
+2
-2
+19
-17
+19
-20
+5
-5
+10
-9
+27
-1
+127
-40
+18
-12
+41
-21
+7
-6
+2
-2
+11
-8
+15
-1
+27
-18
+59
+1584
-416
+341
-77
+14
-14
+11
+5
-5
+5
-5
+19
-33
+2
-1
+15
-14
+30
-24
+15
-15
+15
-14
+70
-15
+5
-5
+1
+8
-8
+53
-75
+3
-3
+63
-22
+44
-18
+30
-28
+1
-1
+11
-7
+12
-2
+11
-7
+52
-26
+1
-1
+8
-3
~
Makefile
~
src/add.c
~
src/allrepo.c
~
src/allrepo.c
~
src/bisect.c
~
src/bisect.c
~
src/blob.c
~
src/branch.c
~
src/branch.c
~
src/captcha.c
~
src/cgi.c
~
src/checkin.c
~
src/checkin.c
~
src/checkout.c
~
src/checkout.c
~
src/clearsign.c
~
src/clone.c
~
src/clone.c
~
src/comformat.c
~
src/config.h
~
src/configure.c
~
src/configure.c
~
src/content.c
~
src/db.c
~
src/deltacmd.c
~
src/descendants.c
~
src/diff.c
~
src/diffcmd.c
~
src/encode.c
~
src/export.c
~
src/file.c
~
src/finfo.c
~
src/glob.c
~
src/graph.c
~
src/http.c
~
src/http_ssl.c
~
src/http_transport.c
~
src/import.c
~
src/info.c
~
src/leaf.c
~
src/login.c
~
src/main.c
~
src/main.mk
~
src/makemake.tcl
~
src/manifest.c
~
src/md5.c
~
src/merge.c
~
src/merge3.c
~
src/name.c
~
src/path.c
~
src/printf.c
~
src/rebuild.c
~
src/report.c
~
src/schema.c
~
src/setup.c
~
src/sha1.c
~
src/shell.c
~
src/shun.c
~
src/skins.c
~
src/sqlcmd.c
~
src/sqlite3.c
~
src/sqlite3.h
~
src/stash.c
~
src/style.c
~
src/sync.c
~
src/tag.c
~
src/timeline.c
~
src/tkt.c
~
src/undo.c
~
src/update.c
~
src/url.c
~
src/user.c
~
src/vfile.c
~
src/wiki.c
~
src/wikiformat.c
~
src/winhttp.c
~
src/xfer.c
~
test/file1.test
~
test/graph-test-1.wiki
~
test/merge1.test
~
test/merge3.test
~
win/Makefile.PellesCGMake
~
win/Makefile.dmc
~
win/Makefile.mingw
~
win/Makefile.msc
~
www/fossil_logo_small.gif
~
www/mkdownload.tcl
~
www/selfhost.wiki
~
www/server.wiki
M
Makefile
+1
-1
| --- Makefile | ||
| +++ Makefile | ||
| @@ -58,11 +58,11 @@ | ||
| 58 | 58 | |
| 59 | 59 | # You should not need to change anything below this line |
| 60 | 60 | ############################################################################### |
| 61 | 61 | # |
| 62 | 62 | # Automatic platform-specific options. |
| 63 | -HOST_OS!= uname -s | |
| 63 | +HOST_OS :sh = uname -s | |
| 64 | 64 | |
| 65 | 65 | LIB.SunOS= -lsocket -lnsl |
| 66 | 66 | LIB += $(LIB.$(HOST_OS)) |
| 67 | 67 | |
| 68 | 68 | TCC.DragonFly += -DUSE_PREAD |
| 69 | 69 |
| --- Makefile | |
| +++ Makefile | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # You should not need to change anything below this line |
| 60 | ############################################################################### |
| 61 | # |
| 62 | # Automatic platform-specific options. |
| 63 | HOST_OS!= uname -s |
| 64 | |
| 65 | LIB.SunOS= -lsocket -lnsl |
| 66 | LIB += $(LIB.$(HOST_OS)) |
| 67 | |
| 68 | TCC.DragonFly += -DUSE_PREAD |
| 69 |
| --- Makefile | |
| +++ Makefile | |
| @@ -58,11 +58,11 @@ | |
| 58 | |
| 59 | # You should not need to change anything below this line |
| 60 | ############################################################################### |
| 61 | # |
| 62 | # Automatic platform-specific options. |
| 63 | HOST_OS :sh = uname -s |
| 64 | |
| 65 | LIB.SunOS= -lsocket -lnsl |
| 66 | LIB += $(LIB.$(HOST_OS)) |
| 67 | |
| 68 | TCC.DragonFly += -DUSE_PREAD |
| 69 |
+140
-243
| --- src/add.c | ||
| +++ src/add.c | ||
| @@ -85,132 +85,77 @@ | ||
| 85 | 85 | zAll = blob_str(&x); |
| 86 | 86 | } |
| 87 | 87 | return zAll; |
| 88 | 88 | } |
| 89 | 89 | |
| 90 | - | |
| 91 | -/* | |
| 92 | -** The pIgnore statement is query of the form: | |
| 93 | -** | |
| 94 | -** SELECT (:x GLOB ... OR :x GLOB ... OR ...) | |
| 95 | -** | |
| 96 | -** In other words, it is a query that returns true if the :x value | |
| 97 | -** should be ignored. Evaluate the query and return true to ignore | |
| 98 | -** and false to not ignore. | |
| 99 | -** | |
| 100 | -** If pIgnore is NULL, then do not ignore. | |
| 101 | -*/ | |
| 102 | -static int shouldBeIgnored(Stmt *pIgnore, const char *zName){ | |
| 103 | - int rc = 0; | |
| 104 | - if( pIgnore ){ | |
| 105 | - db_bind_text(pIgnore, ":x", zName); | |
| 106 | - db_step(pIgnore); | |
| 107 | - rc = db_column_int(pIgnore, 0); | |
| 108 | - db_reset(pIgnore); | |
| 109 | - } | |
| 110 | - return rc; | |
| 111 | -} | |
| 112 | - | |
| 113 | - | |
| 114 | 90 | /* |
| 115 | 91 | ** Add a single file named zName to the VFILE table with vid. |
| 116 | 92 | ** |
| 117 | 93 | ** Omit any file whose name is pOmit. |
| 118 | 94 | */ |
| 119 | -static void add_one_file( | |
| 120 | - const char *zName, /* Name of file to add */ | |
| 121 | - int vid, /* Add to this VFILE */ | |
| 122 | - Blob *pOmit | |
| 123 | -){ | |
| 124 | - Blob pathname; | |
| 125 | - const char *zPath; | |
| 126 | - int i; | |
| 127 | - const char *zReserved; | |
| 128 | - | |
| 129 | - file_tree_name(zName, &pathname, 1); | |
| 130 | - zPath = blob_str(&pathname); | |
| 131 | - for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ | |
| 132 | - if( fossil_strcmp(zPath, zReserved)==0 ) break; | |
| 133 | - } | |
| 134 | - if( zReserved || (pOmit && blob_compare(&pathname, pOmit)==0) ){ | |
| 135 | - fossil_warning("cannot add %s", zPath); | |
| 136 | - }else{ | |
| 137 | - if( !file_is_simple_pathname(zPath) ){ | |
| 138 | - fossil_fatal("filename contains illegal characters: %s", zPath); | |
| 139 | - } | |
| 140 | -#if defined(_WIN32) | |
| 141 | - if( db_exists("SELECT 1 FROM vfile" | |
| 142 | - " WHERE pathname=%Q COLLATE nocase", zPath) ){ | |
| 143 | - db_multi_exec("UPDATE vfile SET deleted=0" | |
| 144 | - " WHERE pathname=%Q COLLATE nocase", zPath); | |
| 145 | - } | |
| 146 | -#else | |
| 147 | - if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ | |
| 148 | - db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); | |
| 149 | - } | |
| 150 | -#endif | |
| 151 | - else{ | |
| 152 | - db_multi_exec( | |
| 153 | - "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)" | |
| 154 | - "VALUES(%d,0,0,0,%Q,%d)", | |
| 155 | - vid, zPath,file_isexe(zName)); | |
| 156 | - } | |
| 157 | - printf("ADDED %s\n", zPath); | |
| 158 | - } | |
| 159 | - blob_reset(&pathname); | |
| 160 | -} | |
| 161 | - | |
| 162 | -/* | |
| 163 | -** All content of the zDir directory to the SFILE table. | |
| 164 | -*/ | |
| 165 | -void add_directory_content(const char *zDir, Stmt *pIgnore){ | |
| 166 | - DIR *d; | |
| 167 | - int origSize; | |
| 168 | - struct dirent *pEntry; | |
| 169 | - Blob path; | |
| 170 | - | |
| 171 | - blob_zero(&path); | |
| 172 | - blob_append(&path, zDir, -1); | |
| 173 | - origSize = blob_size(&path); | |
| 174 | - d = opendir(zDir); | |
| 175 | - if( d ){ | |
| 176 | - while( (pEntry=readdir(d))!=0 ){ | |
| 177 | - char *zPath; | |
| 178 | - if( pEntry->d_name[0]=='.' ){ | |
| 179 | - if( !includeDotFiles ) continue; | |
| 180 | - if( pEntry->d_name[1]==0 ) continue; | |
| 181 | - if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; | |
| 182 | - } | |
| 183 | - blob_appendf(&path, "/%s", pEntry->d_name); | |
| 184 | - zPath = blob_str(&path); | |
| 185 | - if( shouldBeIgnored(pIgnore, zPath) ){ | |
| 186 | - /* Noop */ | |
| 187 | - }else if( file_isdir(zPath)==1 ){ | |
| 188 | - add_directory_content(zPath, pIgnore); | |
| 189 | - }else if( file_isfile(zPath) ){ | |
| 190 | - db_multi_exec("INSERT INTO sfile VALUES(%Q)", zPath); | |
| 191 | - } | |
| 192 | - blob_resize(&path, origSize); | |
| 193 | - } | |
| 194 | - closedir(d); | |
| 195 | - } | |
| 196 | - blob_reset(&path); | |
| 197 | -} | |
| 198 | - | |
| 199 | -/* | |
| 200 | -** Add all content of a directory. | |
| 201 | -*/ | |
| 202 | -void add_directory(const char *zDir, int vid, Blob *pOmit, Stmt *pIgnore){ | |
| 203 | - Stmt q; | |
| 204 | - add_directory_content(zDir, pIgnore); | |
| 205 | - db_prepare(&q, "SELECT x FROM sfile ORDER BY x"); | |
| 206 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 207 | - const char *zName = db_column_text(&q, 0); | |
| 208 | - add_one_file(zName, vid, pOmit); | |
| 209 | - } | |
| 210 | - db_finalize(&q); | |
| 211 | - db_multi_exec("DELETE FROM sfile"); | |
| 95 | +static int add_one_file( | |
| 96 | + const char *zPath, /* Tree-name of file to add. */ | |
| 97 | + int vid /* Add to this VFILE */ | |
| 98 | +){ | |
| 99 | + if( !file_is_simple_pathname(zPath) ){ | |
| 100 | + fossil_fatal("filename contains illegal characters: %s", zPath); | |
| 101 | + } | |
| 102 | +#if defined(_WIN32) | |
| 103 | + if( db_exists("SELECT 1 FROM vfile" | |
| 104 | + " WHERE pathname=%Q COLLATE nocase", zPath) ){ | |
| 105 | + db_multi_exec("UPDATE vfile SET deleted=0" | |
| 106 | + " WHERE pathname=%Q COLLATE nocase", zPath); | |
| 107 | + } | |
| 108 | +#else | |
| 109 | + if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ | |
| 110 | + db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); | |
| 111 | + } | |
| 112 | +#endif | |
| 113 | + else{ | |
| 114 | + char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); | |
| 115 | + db_multi_exec( | |
| 116 | + "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)" | |
| 117 | + "VALUES(%d,0,0,0,%Q,%d)", | |
| 118 | + vid, zPath, file_isexe(zFullname)); | |
| 119 | + fossil_free(zFullname); | |
| 120 | + } | |
| 121 | + fossil_print("ADDED %s\n", zPath); | |
| 122 | + return 1; | |
| 123 | +} | |
| 124 | + | |
| 125 | +/* | |
| 126 | +** Add all files in the sfile temp table. | |
| 127 | +** | |
| 128 | +** Automatically exclude the repository file. | |
| 129 | +*/ | |
| 130 | +static int add_files_in_sfile(int vid){ | |
| 131 | + const char *zRepo; /* Name of the repository database file */ | |
| 132 | + int nAdd = 0; /* Number of files added */ | |
| 133 | + int i; /* Loop counter */ | |
| 134 | + const char *zReserved; /* Name of a reserved file */ | |
| 135 | + Blob repoName; /* Treename of the repository */ | |
| 136 | + Stmt loop; /* SQL to loop over all files to add */ | |
| 137 | + | |
| 138 | + if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){ | |
| 139 | + blob_zero(&repoName); | |
| 140 | + zRepo = ""; | |
| 141 | + }else{ | |
| 142 | + zRepo = blob_str(&repoName); | |
| 143 | + } | |
| 144 | + db_prepare(&loop, "SELECT x FROM sfile ORDER BY x"); | |
| 145 | + while( db_step(&loop)==SQLITE_ROW ){ | |
| 146 | + const char *zToAdd = db_column_text(&loop, 0); | |
| 147 | + if( fossil_strcmp(zToAdd, zRepo)==0 ) continue; | |
| 148 | + for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ | |
| 149 | + if( fossil_strcmp(zToAdd, zReserved)==0 ) break; | |
| 150 | + } | |
| 151 | + if( zReserved ) continue; | |
| 152 | + nAdd += add_one_file(zToAdd, vid); | |
| 153 | + } | |
| 154 | + db_finalize(&loop); | |
| 155 | + blob_reset(&repoName); | |
| 156 | + return nAdd; | |
| 212 | 157 | } |
| 213 | 158 | |
| 214 | 159 | /* |
| 215 | 160 | ** COMMAND: add |
| 216 | 161 | ** |
| @@ -221,26 +166,24 @@ | ||
| 221 | 166 | ** |
| 222 | 167 | ** When adding files or directories recursively, filenames that begin |
| 223 | 168 | ** with "." are excluded by default. To include such files, add |
| 224 | 169 | ** the "--dotfiles" option to the command-line. |
| 225 | 170 | ** |
| 226 | -** The --ignore option specifies the patterns for files to be excluded, | |
| 227 | -** like *.o,*.obj,*.exe. If not specified, the "ignore-glob" setting is | |
| 228 | -** used. See ** documentation on the "settings" command for further | |
| 229 | -** information. | |
| 230 | -** | |
| 171 | +** The --ignore option is a comma-separate list of glob patterns for files | |
| 172 | +** to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore option | |
| 173 | +** does not appear on the command line then the "ignore-glob" setting is | |
| 174 | +** used. | |
| 231 | 175 | ** |
| 232 | 176 | ** SUMMARY: fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| 233 | 177 | ** Options: --dotfiles, --ignore |
| 234 | 178 | */ |
| 235 | 179 | void add_cmd(void){ |
| 236 | - int i; | |
| 237 | - int vid; | |
| 238 | - const char *zIgnoreFlag; | |
| 239 | - Blob repo; | |
| 240 | - Stmt ignoreTest; /* Test to see if a name should be ignored */ | |
| 241 | - Stmt *pIgnore; /* Pointer to ignoreTest or to NULL */ | |
| 180 | + int i; /* Loop counter */ | |
| 181 | + int vid; /* Currently checked out version */ | |
| 182 | + int nRoot; /* Full path characters in g.zLocalRoot */ | |
| 183 | + const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ | |
| 184 | + Glob *pIgnore; /* Ignore everything matching this glob pattern */ | |
| 242 | 185 | |
| 243 | 186 | zIgnoreFlag = find_option("ignore",0,1); |
| 244 | 187 | includeDotFiles = find_option("dotfiles",0,0)!=0; |
| 245 | 188 | db_must_be_within_tree(); |
| 246 | 189 | if( zIgnoreFlag==0 ){ |
| @@ -249,101 +192,49 @@ | ||
| 249 | 192 | vid = db_lget_int("checkout",0); |
| 250 | 193 | if( vid==0 ){ |
| 251 | 194 | fossil_panic("no checkout to add to"); |
| 252 | 195 | } |
| 253 | 196 | db_begin_transaction(); |
| 254 | - if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ | |
| 255 | - blob_zero(&repo); | |
| 256 | - } | |
| 257 | 197 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 258 | 198 | #if defined(_WIN32) |
| 259 | 199 | db_multi_exec( |
| 260 | 200 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 261 | 201 | " ON vfile(pathname COLLATE nocase)" |
| 262 | 202 | ); |
| 263 | 203 | #endif |
| 264 | - if( zIgnoreFlag && zIgnoreFlag[0] ){ | |
| 265 | - db_prepare(&ignoreTest, "SELECT %s", glob_expr(":x", zIgnoreFlag)); | |
| 266 | - pIgnore = &ignoreTest; | |
| 267 | - }else{ | |
| 268 | - pIgnore = 0; | |
| 269 | - } | |
| 204 | + pIgnore = glob_create(zIgnoreFlag); | |
| 205 | + nRoot = strlen(g.zLocalRoot); | |
| 206 | + | |
| 207 | + /* Load the names of all files that are to be added into sfile temp table */ | |
| 270 | 208 | for(i=2; i<g.argc; i++){ |
| 271 | 209 | char *zName; |
| 272 | 210 | int isDir; |
| 211 | + Blob fullName; | |
| 273 | 212 | |
| 274 | - zName = mprintf("%/", g.argv[i]); | |
| 213 | + file_canonical_name(g.argv[i], &fullName); | |
| 214 | + zName = blob_str(&fullName); | |
| 275 | 215 | isDir = file_isdir(zName); |
| 276 | 216 | if( isDir==1 ){ |
| 277 | - int sz = strlen(zName); | |
| 278 | - if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; } | |
| 279 | - add_directory(zName, vid, &repo, pIgnore); | |
| 217 | + vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore); | |
| 280 | 218 | }else if( isDir==0 ){ |
| 281 | 219 | fossil_fatal("not found: %s", zName); |
| 282 | - }else if( access(zName, R_OK) ){ | |
| 220 | + }else if( file_access(zName, R_OK) ){ | |
| 283 | 221 | fossil_fatal("cannot open %s", zName); |
| 284 | 222 | }else{ |
| 285 | - add_one_file(zName, vid, &repo); | |
| 286 | - } | |
| 287 | - free(zName); | |
| 288 | - } | |
| 289 | - if( pIgnore ) db_finalize(pIgnore); | |
| 290 | - db_end_transaction(0); | |
| 291 | -} | |
| 292 | - | |
| 293 | - | |
| 294 | -/* | |
| 295 | -** Unmangage a single file. | |
| 296 | -*/ | |
| 297 | -void delete_one_file(const char *zName){ | |
| 298 | - char *zPath; | |
| 299 | - Blob pathname; | |
| 300 | - file_tree_name(zName, &pathname, 1); | |
| 301 | - zPath = blob_str(&pathname); | |
| 302 | - if( !db_exists( | |
| 303 | - "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){ | |
| 304 | - fossil_fatal("not in the repository: %s", zName); | |
| 305 | - }else{ | |
| 306 | - db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath); | |
| 307 | - printf("DELETED %s\n", zPath); | |
| 308 | - } | |
| 309 | - blob_reset(&pathname); | |
| 310 | -} | |
| 311 | - | |
| 312 | -/* | |
| 313 | -** Remove all contents of zDir | |
| 314 | -*/ | |
| 315 | -void del_directory_content(const char *zDir){ | |
| 316 | - DIR *d; | |
| 317 | - int origSize; | |
| 318 | - struct dirent *pEntry; | |
| 319 | - Blob path; | |
| 320 | - | |
| 321 | - blob_zero(&path); | |
| 322 | - blob_append(&path, zDir, -1); | |
| 323 | - origSize = blob_size(&path); | |
| 324 | - d = opendir(zDir); | |
| 325 | - if( d ){ | |
| 326 | - while( (pEntry=readdir(d))!=0 ){ | |
| 327 | - char *zPath; | |
| 328 | - if( pEntry->d_name[0]=='.'){ | |
| 329 | - if( !includeDotFiles ) continue; | |
| 330 | - if( pEntry->d_name[1]==0 ) continue; | |
| 331 | - if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; | |
| 332 | - } | |
| 333 | - blob_appendf(&path, "/%s", pEntry->d_name); | |
| 334 | - zPath = blob_str(&path); | |
| 335 | - if( file_isdir(zPath)==1 ){ | |
| 336 | - del_directory_content(zPath); | |
| 337 | - }else if( file_isfile(zPath) ){ | |
| 338 | - delete_one_file(zPath); | |
| 339 | - } | |
| 340 | - blob_resize(&path, origSize); | |
| 341 | - } | |
| 342 | - closedir(d); | |
| 343 | - } | |
| 344 | - blob_reset(&path); | |
| 223 | + char *zTreeName = &zName[nRoot]; | |
| 224 | + db_multi_exec( | |
| 225 | + "INSERT OR IGNORE INTO sfile(x)" | |
| 226 | + " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=%Q)", | |
| 227 | + zTreeName, zTreeName | |
| 228 | + ); | |
| 229 | + } | |
| 230 | + blob_reset(&fullName); | |
| 231 | + } | |
| 232 | + glob_free(pIgnore); | |
| 233 | + | |
| 234 | + add_files_in_sfile(vid); | |
| 235 | + db_end_transaction(0); | |
| 345 | 236 | } |
| 346 | 237 | |
| 347 | 238 | /* |
| 348 | 239 | ** COMMAND: rm |
| 349 | 240 | ** COMMAND: delete |
| @@ -361,31 +252,45 @@ | ||
| 361 | 252 | ** or: fossil delete FILE1 ?FILE2 ...? |
| 362 | 253 | */ |
| 363 | 254 | void delete_cmd(void){ |
| 364 | 255 | int i; |
| 365 | 256 | int vid; |
| 257 | + Stmt loop; | |
| 366 | 258 | |
| 367 | 259 | db_must_be_within_tree(); |
| 368 | 260 | vid = db_lget_int("checkout", 0); |
| 369 | 261 | if( vid==0 ){ |
| 370 | 262 | fossil_panic("no checkout to remove from"); |
| 371 | 263 | } |
| 372 | 264 | db_begin_transaction(); |
| 265 | + db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); | |
| 373 | 266 | for(i=2; i<g.argc; i++){ |
| 374 | - char *zName; | |
| 375 | - | |
| 376 | - zName = mprintf("%/", g.argv[i]); | |
| 377 | - if( file_isdir(zName) == 1 ){ | |
| 378 | - int sz = strlen(zName); | |
| 379 | - if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; } | |
| 380 | - del_directory_content(zName); | |
| 381 | - } else { | |
| 382 | - delete_one_file(zName); | |
| 383 | - } | |
| 384 | - free(zName); | |
| 385 | - } | |
| 386 | - db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0"); | |
| 267 | + Blob treeName; | |
| 268 | + char *zTreeName; | |
| 269 | + | |
| 270 | + file_tree_name(g.argv[i], &treeName, 1); | |
| 271 | + zTreeName = blob_str(&treeName); | |
| 272 | + db_multi_exec( | |
| 273 | + "INSERT OR IGNORE INTO sfile" | |
| 274 | + " SELECT pathname FROM vfile" | |
| 275 | + " WHERE (pathname=%Q" | |
| 276 | + " OR (pathname>'%q/' AND pathname<'%q0'))" | |
| 277 | + " AND NOT deleted", | |
| 278 | + zTreeName, zTreeName, zTreeName | |
| 279 | + ); | |
| 280 | + blob_reset(&treeName); | |
| 281 | + } | |
| 282 | + | |
| 283 | + db_prepare(&loop, "SELECT x FROM sfile"); | |
| 284 | + while( db_step(&loop)==SQLITE_ROW ){ | |
| 285 | + fossil_print("DELETED %s\n", db_column_text(&loop, 0)); | |
| 286 | + } | |
| 287 | + db_finalize(&loop); | |
| 288 | + db_multi_exec( | |
| 289 | + "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;" | |
| 290 | + "DELETE FROM vfile WHERE rid=0 AND deleted;" | |
| 291 | + ); | |
| 387 | 292 | db_end_transaction(0); |
| 388 | 293 | } |
| 389 | 294 | |
| 390 | 295 | /* |
| 391 | 296 | ** COMMAND: addremove |
| @@ -426,13 +331,13 @@ | ||
| 426 | 331 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 427 | 332 | int isTest = find_option("test",0,0)!=0; |
| 428 | 333 | int n; |
| 429 | 334 | Stmt q; |
| 430 | 335 | int vid; |
| 431 | - Blob repo; | |
| 432 | 336 | int nAdd = 0; |
| 433 | 337 | int nDelete = 0; |
| 338 | + Glob *pIgnore; | |
| 434 | 339 | |
| 435 | 340 | db_must_be_within_tree(); |
| 436 | 341 | if( zIgnoreFlag==0 ){ |
| 437 | 342 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 438 | 343 | } |
| @@ -439,38 +344,30 @@ | ||
| 439 | 344 | vid = db_lget_int("checkout",0); |
| 440 | 345 | if( vid==0 ){ |
| 441 | 346 | fossil_panic("no checkout to add to"); |
| 442 | 347 | } |
| 443 | 348 | db_begin_transaction(); |
| 349 | + | |
| 350 | + /* step 1: | |
| 351 | + ** Populate the temp table "sfile" with the names of all unmanged | |
| 352 | + ** files currently in the check-out, except for files that match the | |
| 353 | + ** --ignore or ignore-glob patterns and dot-files. Then add all of | |
| 354 | + ** the files in the sfile temp table to the set of managed files. | |
| 355 | + */ | |
| 444 | 356 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 445 | 357 | n = strlen(g.zLocalRoot); |
| 446 | 358 | blob_init(&path, g.zLocalRoot, n-1); |
| 447 | 359 | /* now we read the complete file structure into a temp table */ |
| 448 | - vfile_scan(0, &path, blob_size(&path), allFlag); | |
| 449 | - if( file_tree_name(g.zRepositoryName, &repo, 0) ){ | |
| 450 | - db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); | |
| 451 | - } | |
| 452 | - | |
| 453 | - /* step 1: search for extra files */ | |
| 454 | - db_prepare(&q, | |
| 455 | - "SELECT x, %Q || x FROM sfile" | |
| 456 | - " WHERE x NOT IN (%s)" | |
| 457 | - " AND NOT %s" | |
| 458 | - " ORDER BY 1", | |
| 459 | - g.zLocalRoot, | |
| 460 | - fossil_all_reserved_names(), | |
| 461 | - glob_expr("x", zIgnoreFlag) | |
| 462 | - ); | |
| 463 | - while( db_step(&q)==SQLITE_ROW ){ | |
| 464 | - add_one_file(db_column_text(&q, 1), vid, 0); | |
| 465 | - nAdd++; | |
| 466 | - } | |
| 467 | - db_finalize(&q); | |
| 360 | + pIgnore = glob_create(zIgnoreFlag); | |
| 361 | + vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 362 | + glob_free(pIgnore); | |
| 363 | + nAdd = add_files_in_sfile(vid); | |
| 364 | + | |
| 468 | 365 | /* step 2: search for missing files */ |
| 469 | 366 | db_prepare(&q, |
| 470 | - "SELECT pathname,%Q || pathname,deleted FROM vfile" | |
| 471 | - " WHERE deleted!=1" | |
| 367 | + "SELECT pathname, %Q || pathname, deleted FROM vfile" | |
| 368 | + " WHERE NOT deleted" | |
| 472 | 369 | " ORDER BY 1", |
| 473 | 370 | g.zLocalRoot |
| 474 | 371 | ); |
| 475 | 372 | while( db_step(&q)==SQLITE_ROW ){ |
| 476 | 373 | const char * zFile; |
| @@ -480,17 +377,17 @@ | ||
| 480 | 377 | zPath = db_column_text(&q, 1); |
| 481 | 378 | if( !file_isfile(zPath) ){ |
| 482 | 379 | if( !isTest ){ |
| 483 | 380 | db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile); |
| 484 | 381 | } |
| 485 | - printf("DELETED %s\n", zFile); | |
| 382 | + fossil_print("DELETED %s\n", zFile); | |
| 486 | 383 | nDelete++; |
| 487 | 384 | } |
| 488 | 385 | } |
| 489 | 386 | db_finalize(&q); |
| 490 | 387 | /* show cmmand summary */ |
| 491 | - printf("added %d files, deleted %d files\n", nAdd, nDelete); | |
| 388 | + fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); | |
| 492 | 389 | |
| 493 | 390 | db_end_transaction(isTest); |
| 494 | 391 | } |
| 495 | 392 | |
| 496 | 393 | |
| @@ -498,11 +395,11 @@ | ||
| 498 | 395 | ** Rename a single file. |
| 499 | 396 | ** |
| 500 | 397 | ** The original name of the file is zOrig. The new filename is zNew. |
| 501 | 398 | */ |
| 502 | 399 | static void mv_one_file(int vid, const char *zOrig, const char *zNew){ |
| 503 | - printf("RENAME %s %s\n", zOrig, zNew); | |
| 400 | + fossil_print("RENAME %s %s\n", zOrig, zNew); | |
| 504 | 401 | db_multi_exec( |
| 505 | 402 | "UPDATE vfile SET pathname='%s' WHERE pathname='%s' AND vid=%d", |
| 506 | 403 | zNew, zOrig, vid |
| 507 | 404 | ); |
| 508 | 405 | } |
| @@ -572,13 +469,13 @@ | ||
| 572 | 469 | zOrig = blob_str(&orig); |
| 573 | 470 | nOrig = blob_size(&orig); |
| 574 | 471 | db_prepare(&q, |
| 575 | 472 | "SELECT pathname FROM vfile" |
| 576 | 473 | " WHERE vid=%d" |
| 577 | - " AND (pathname='%s' OR pathname GLOB '%s/*')" | |
| 474 | + " AND (pathname='%q' OR (pathname>'%q/' AND pathname<'%q0'))" | |
| 578 | 475 | " ORDER BY 1", |
| 579 | - vid, zOrig, zOrig | |
| 476 | + vid, zOrig, zOrig, zOrig | |
| 580 | 477 | ); |
| 581 | 478 | while( db_step(&q)==SQLITE_ROW ){ |
| 582 | 479 | const char *zPath = db_column_text(&q, 0); |
| 583 | 480 | int nPath = db_column_bytes(&q, 0); |
| 584 | 481 | const char *zTail; |
| 585 | 482 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -85,132 +85,77 @@ | |
| 85 | zAll = blob_str(&x); |
| 86 | } |
| 87 | return zAll; |
| 88 | } |
| 89 | |
| 90 | |
| 91 | /* |
| 92 | ** The pIgnore statement is query of the form: |
| 93 | ** |
| 94 | ** SELECT (:x GLOB ... OR :x GLOB ... OR ...) |
| 95 | ** |
| 96 | ** In other words, it is a query that returns true if the :x value |
| 97 | ** should be ignored. Evaluate the query and return true to ignore |
| 98 | ** and false to not ignore. |
| 99 | ** |
| 100 | ** If pIgnore is NULL, then do not ignore. |
| 101 | */ |
| 102 | static int shouldBeIgnored(Stmt *pIgnore, const char *zName){ |
| 103 | int rc = 0; |
| 104 | if( pIgnore ){ |
| 105 | db_bind_text(pIgnore, ":x", zName); |
| 106 | db_step(pIgnore); |
| 107 | rc = db_column_int(pIgnore, 0); |
| 108 | db_reset(pIgnore); |
| 109 | } |
| 110 | return rc; |
| 111 | } |
| 112 | |
| 113 | |
| 114 | /* |
| 115 | ** Add a single file named zName to the VFILE table with vid. |
| 116 | ** |
| 117 | ** Omit any file whose name is pOmit. |
| 118 | */ |
| 119 | static void add_one_file( |
| 120 | const char *zName, /* Name of file to add */ |
| 121 | int vid, /* Add to this VFILE */ |
| 122 | Blob *pOmit |
| 123 | ){ |
| 124 | Blob pathname; |
| 125 | const char *zPath; |
| 126 | int i; |
| 127 | const char *zReserved; |
| 128 | |
| 129 | file_tree_name(zName, &pathname, 1); |
| 130 | zPath = blob_str(&pathname); |
| 131 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 132 | if( fossil_strcmp(zPath, zReserved)==0 ) break; |
| 133 | } |
| 134 | if( zReserved || (pOmit && blob_compare(&pathname, pOmit)==0) ){ |
| 135 | fossil_warning("cannot add %s", zPath); |
| 136 | }else{ |
| 137 | if( !file_is_simple_pathname(zPath) ){ |
| 138 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 139 | } |
| 140 | #if defined(_WIN32) |
| 141 | if( db_exists("SELECT 1 FROM vfile" |
| 142 | " WHERE pathname=%Q COLLATE nocase", zPath) ){ |
| 143 | db_multi_exec("UPDATE vfile SET deleted=0" |
| 144 | " WHERE pathname=%Q COLLATE nocase", zPath); |
| 145 | } |
| 146 | #else |
| 147 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 148 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 149 | } |
| 150 | #endif |
| 151 | else{ |
| 152 | db_multi_exec( |
| 153 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)" |
| 154 | "VALUES(%d,0,0,0,%Q,%d)", |
| 155 | vid, zPath,file_isexe(zName)); |
| 156 | } |
| 157 | printf("ADDED %s\n", zPath); |
| 158 | } |
| 159 | blob_reset(&pathname); |
| 160 | } |
| 161 | |
| 162 | /* |
| 163 | ** All content of the zDir directory to the SFILE table. |
| 164 | */ |
| 165 | void add_directory_content(const char *zDir, Stmt *pIgnore){ |
| 166 | DIR *d; |
| 167 | int origSize; |
| 168 | struct dirent *pEntry; |
| 169 | Blob path; |
| 170 | |
| 171 | blob_zero(&path); |
| 172 | blob_append(&path, zDir, -1); |
| 173 | origSize = blob_size(&path); |
| 174 | d = opendir(zDir); |
| 175 | if( d ){ |
| 176 | while( (pEntry=readdir(d))!=0 ){ |
| 177 | char *zPath; |
| 178 | if( pEntry->d_name[0]=='.' ){ |
| 179 | if( !includeDotFiles ) continue; |
| 180 | if( pEntry->d_name[1]==0 ) continue; |
| 181 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 182 | } |
| 183 | blob_appendf(&path, "/%s", pEntry->d_name); |
| 184 | zPath = blob_str(&path); |
| 185 | if( shouldBeIgnored(pIgnore, zPath) ){ |
| 186 | /* Noop */ |
| 187 | }else if( file_isdir(zPath)==1 ){ |
| 188 | add_directory_content(zPath, pIgnore); |
| 189 | }else if( file_isfile(zPath) ){ |
| 190 | db_multi_exec("INSERT INTO sfile VALUES(%Q)", zPath); |
| 191 | } |
| 192 | blob_resize(&path, origSize); |
| 193 | } |
| 194 | closedir(d); |
| 195 | } |
| 196 | blob_reset(&path); |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ** Add all content of a directory. |
| 201 | */ |
| 202 | void add_directory(const char *zDir, int vid, Blob *pOmit, Stmt *pIgnore){ |
| 203 | Stmt q; |
| 204 | add_directory_content(zDir, pIgnore); |
| 205 | db_prepare(&q, "SELECT x FROM sfile ORDER BY x"); |
| 206 | while( db_step(&q)==SQLITE_ROW ){ |
| 207 | const char *zName = db_column_text(&q, 0); |
| 208 | add_one_file(zName, vid, pOmit); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | db_multi_exec("DELETE FROM sfile"); |
| 212 | } |
| 213 | |
| 214 | /* |
| 215 | ** COMMAND: add |
| 216 | ** |
| @@ -221,26 +166,24 @@ | |
| 221 | ** |
| 222 | ** When adding files or directories recursively, filenames that begin |
| 223 | ** with "." are excluded by default. To include such files, add |
| 224 | ** the "--dotfiles" option to the command-line. |
| 225 | ** |
| 226 | ** The --ignore option specifies the patterns for files to be excluded, |
| 227 | ** like *.o,*.obj,*.exe. If not specified, the "ignore-glob" setting is |
| 228 | ** used. See ** documentation on the "settings" command for further |
| 229 | ** information. |
| 230 | ** |
| 231 | ** |
| 232 | ** SUMMARY: fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| 233 | ** Options: --dotfiles, --ignore |
| 234 | */ |
| 235 | void add_cmd(void){ |
| 236 | int i; |
| 237 | int vid; |
| 238 | const char *zIgnoreFlag; |
| 239 | Blob repo; |
| 240 | Stmt ignoreTest; /* Test to see if a name should be ignored */ |
| 241 | Stmt *pIgnore; /* Pointer to ignoreTest or to NULL */ |
| 242 | |
| 243 | zIgnoreFlag = find_option("ignore",0,1); |
| 244 | includeDotFiles = find_option("dotfiles",0,0)!=0; |
| 245 | db_must_be_within_tree(); |
| 246 | if( zIgnoreFlag==0 ){ |
| @@ -249,101 +192,49 @@ | |
| 249 | vid = db_lget_int("checkout",0); |
| 250 | if( vid==0 ){ |
| 251 | fossil_panic("no checkout to add to"); |
| 252 | } |
| 253 | db_begin_transaction(); |
| 254 | if( !file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 255 | blob_zero(&repo); |
| 256 | } |
| 257 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 258 | #if defined(_WIN32) |
| 259 | db_multi_exec( |
| 260 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 261 | " ON vfile(pathname COLLATE nocase)" |
| 262 | ); |
| 263 | #endif |
| 264 | if( zIgnoreFlag && zIgnoreFlag[0] ){ |
| 265 | db_prepare(&ignoreTest, "SELECT %s", glob_expr(":x", zIgnoreFlag)); |
| 266 | pIgnore = &ignoreTest; |
| 267 | }else{ |
| 268 | pIgnore = 0; |
| 269 | } |
| 270 | for(i=2; i<g.argc; i++){ |
| 271 | char *zName; |
| 272 | int isDir; |
| 273 | |
| 274 | zName = mprintf("%/", g.argv[i]); |
| 275 | isDir = file_isdir(zName); |
| 276 | if( isDir==1 ){ |
| 277 | int sz = strlen(zName); |
| 278 | if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; } |
| 279 | add_directory(zName, vid, &repo, pIgnore); |
| 280 | }else if( isDir==0 ){ |
| 281 | fossil_fatal("not found: %s", zName); |
| 282 | }else if( access(zName, R_OK) ){ |
| 283 | fossil_fatal("cannot open %s", zName); |
| 284 | }else{ |
| 285 | add_one_file(zName, vid, &repo); |
| 286 | } |
| 287 | free(zName); |
| 288 | } |
| 289 | if( pIgnore ) db_finalize(pIgnore); |
| 290 | db_end_transaction(0); |
| 291 | } |
| 292 | |
| 293 | |
| 294 | /* |
| 295 | ** Unmangage a single file. |
| 296 | */ |
| 297 | void delete_one_file(const char *zName){ |
| 298 | char *zPath; |
| 299 | Blob pathname; |
| 300 | file_tree_name(zName, &pathname, 1); |
| 301 | zPath = blob_str(&pathname); |
| 302 | if( !db_exists( |
| 303 | "SELECT 1 FROM vfile WHERE pathname=%Q AND NOT deleted", zPath) ){ |
| 304 | fossil_fatal("not in the repository: %s", zName); |
| 305 | }else{ |
| 306 | db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zPath); |
| 307 | printf("DELETED %s\n", zPath); |
| 308 | } |
| 309 | blob_reset(&pathname); |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | ** Remove all contents of zDir |
| 314 | */ |
| 315 | void del_directory_content(const char *zDir){ |
| 316 | DIR *d; |
| 317 | int origSize; |
| 318 | struct dirent *pEntry; |
| 319 | Blob path; |
| 320 | |
| 321 | blob_zero(&path); |
| 322 | blob_append(&path, zDir, -1); |
| 323 | origSize = blob_size(&path); |
| 324 | d = opendir(zDir); |
| 325 | if( d ){ |
| 326 | while( (pEntry=readdir(d))!=0 ){ |
| 327 | char *zPath; |
| 328 | if( pEntry->d_name[0]=='.'){ |
| 329 | if( !includeDotFiles ) continue; |
| 330 | if( pEntry->d_name[1]==0 ) continue; |
| 331 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 332 | } |
| 333 | blob_appendf(&path, "/%s", pEntry->d_name); |
| 334 | zPath = blob_str(&path); |
| 335 | if( file_isdir(zPath)==1 ){ |
| 336 | del_directory_content(zPath); |
| 337 | }else if( file_isfile(zPath) ){ |
| 338 | delete_one_file(zPath); |
| 339 | } |
| 340 | blob_resize(&path, origSize); |
| 341 | } |
| 342 | closedir(d); |
| 343 | } |
| 344 | blob_reset(&path); |
| 345 | } |
| 346 | |
| 347 | /* |
| 348 | ** COMMAND: rm |
| 349 | ** COMMAND: delete |
| @@ -361,31 +252,45 @@ | |
| 361 | ** or: fossil delete FILE1 ?FILE2 ...? |
| 362 | */ |
| 363 | void delete_cmd(void){ |
| 364 | int i; |
| 365 | int vid; |
| 366 | |
| 367 | db_must_be_within_tree(); |
| 368 | vid = db_lget_int("checkout", 0); |
| 369 | if( vid==0 ){ |
| 370 | fossil_panic("no checkout to remove from"); |
| 371 | } |
| 372 | db_begin_transaction(); |
| 373 | for(i=2; i<g.argc; i++){ |
| 374 | char *zName; |
| 375 | |
| 376 | zName = mprintf("%/", g.argv[i]); |
| 377 | if( file_isdir(zName) == 1 ){ |
| 378 | int sz = strlen(zName); |
| 379 | if( sz>0 && zName[sz-1]=='/' ){ zName[sz-1] = 0; } |
| 380 | del_directory_content(zName); |
| 381 | } else { |
| 382 | delete_one_file(zName); |
| 383 | } |
| 384 | free(zName); |
| 385 | } |
| 386 | db_multi_exec("DELETE FROM vfile WHERE deleted AND rid=0"); |
| 387 | db_end_transaction(0); |
| 388 | } |
| 389 | |
| 390 | /* |
| 391 | ** COMMAND: addremove |
| @@ -426,13 +331,13 @@ | |
| 426 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 427 | int isTest = find_option("test",0,0)!=0; |
| 428 | int n; |
| 429 | Stmt q; |
| 430 | int vid; |
| 431 | Blob repo; |
| 432 | int nAdd = 0; |
| 433 | int nDelete = 0; |
| 434 | |
| 435 | db_must_be_within_tree(); |
| 436 | if( zIgnoreFlag==0 ){ |
| 437 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 438 | } |
| @@ -439,38 +344,30 @@ | |
| 439 | vid = db_lget_int("checkout",0); |
| 440 | if( vid==0 ){ |
| 441 | fossil_panic("no checkout to add to"); |
| 442 | } |
| 443 | db_begin_transaction(); |
| 444 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 445 | n = strlen(g.zLocalRoot); |
| 446 | blob_init(&path, g.zLocalRoot, n-1); |
| 447 | /* now we read the complete file structure into a temp table */ |
| 448 | vfile_scan(0, &path, blob_size(&path), allFlag); |
| 449 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 450 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 451 | } |
| 452 | |
| 453 | /* step 1: search for extra files */ |
| 454 | db_prepare(&q, |
| 455 | "SELECT x, %Q || x FROM sfile" |
| 456 | " WHERE x NOT IN (%s)" |
| 457 | " AND NOT %s" |
| 458 | " ORDER BY 1", |
| 459 | g.zLocalRoot, |
| 460 | fossil_all_reserved_names(), |
| 461 | glob_expr("x", zIgnoreFlag) |
| 462 | ); |
| 463 | while( db_step(&q)==SQLITE_ROW ){ |
| 464 | add_one_file(db_column_text(&q, 1), vid, 0); |
| 465 | nAdd++; |
| 466 | } |
| 467 | db_finalize(&q); |
| 468 | /* step 2: search for missing files */ |
| 469 | db_prepare(&q, |
| 470 | "SELECT pathname,%Q || pathname,deleted FROM vfile" |
| 471 | " WHERE deleted!=1" |
| 472 | " ORDER BY 1", |
| 473 | g.zLocalRoot |
| 474 | ); |
| 475 | while( db_step(&q)==SQLITE_ROW ){ |
| 476 | const char * zFile; |
| @@ -480,17 +377,17 @@ | |
| 480 | zPath = db_column_text(&q, 1); |
| 481 | if( !file_isfile(zPath) ){ |
| 482 | if( !isTest ){ |
| 483 | db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile); |
| 484 | } |
| 485 | printf("DELETED %s\n", zFile); |
| 486 | nDelete++; |
| 487 | } |
| 488 | } |
| 489 | db_finalize(&q); |
| 490 | /* show cmmand summary */ |
| 491 | printf("added %d files, deleted %d files\n", nAdd, nDelete); |
| 492 | |
| 493 | db_end_transaction(isTest); |
| 494 | } |
| 495 | |
| 496 | |
| @@ -498,11 +395,11 @@ | |
| 498 | ** Rename a single file. |
| 499 | ** |
| 500 | ** The original name of the file is zOrig. The new filename is zNew. |
| 501 | */ |
| 502 | static void mv_one_file(int vid, const char *zOrig, const char *zNew){ |
| 503 | printf("RENAME %s %s\n", zOrig, zNew); |
| 504 | db_multi_exec( |
| 505 | "UPDATE vfile SET pathname='%s' WHERE pathname='%s' AND vid=%d", |
| 506 | zNew, zOrig, vid |
| 507 | ); |
| 508 | } |
| @@ -572,13 +469,13 @@ | |
| 572 | zOrig = blob_str(&orig); |
| 573 | nOrig = blob_size(&orig); |
| 574 | db_prepare(&q, |
| 575 | "SELECT pathname FROM vfile" |
| 576 | " WHERE vid=%d" |
| 577 | " AND (pathname='%s' OR pathname GLOB '%s/*')" |
| 578 | " ORDER BY 1", |
| 579 | vid, zOrig, zOrig |
| 580 | ); |
| 581 | while( db_step(&q)==SQLITE_ROW ){ |
| 582 | const char *zPath = db_column_text(&q, 0); |
| 583 | int nPath = db_column_bytes(&q, 0); |
| 584 | const char *zTail; |
| 585 |
| --- src/add.c | |
| +++ src/add.c | |
| @@ -85,132 +85,77 @@ | |
| 85 | zAll = blob_str(&x); |
| 86 | } |
| 87 | return zAll; |
| 88 | } |
| 89 | |
| 90 | /* |
| 91 | ** Add a single file named zName to the VFILE table with vid. |
| 92 | ** |
| 93 | ** Omit any file whose name is pOmit. |
| 94 | */ |
| 95 | static int add_one_file( |
| 96 | const char *zPath, /* Tree-name of file to add. */ |
| 97 | int vid /* Add to this VFILE */ |
| 98 | ){ |
| 99 | if( !file_is_simple_pathname(zPath) ){ |
| 100 | fossil_fatal("filename contains illegal characters: %s", zPath); |
| 101 | } |
| 102 | #if defined(_WIN32) |
| 103 | if( db_exists("SELECT 1 FROM vfile" |
| 104 | " WHERE pathname=%Q COLLATE nocase", zPath) ){ |
| 105 | db_multi_exec("UPDATE vfile SET deleted=0" |
| 106 | " WHERE pathname=%Q COLLATE nocase", zPath); |
| 107 | } |
| 108 | #else |
| 109 | if( db_exists("SELECT 1 FROM vfile WHERE pathname=%Q", zPath) ){ |
| 110 | db_multi_exec("UPDATE vfile SET deleted=0 WHERE pathname=%Q", zPath); |
| 111 | } |
| 112 | #endif |
| 113 | else{ |
| 114 | char *zFullname = mprintf("%s%s", g.zLocalRoot, zPath); |
| 115 | db_multi_exec( |
| 116 | "INSERT INTO vfile(vid,deleted,rid,mrid,pathname,isexe)" |
| 117 | "VALUES(%d,0,0,0,%Q,%d)", |
| 118 | vid, zPath, file_isexe(zFullname)); |
| 119 | fossil_free(zFullname); |
| 120 | } |
| 121 | fossil_print("ADDED %s\n", zPath); |
| 122 | return 1; |
| 123 | } |
| 124 | |
| 125 | /* |
| 126 | ** Add all files in the sfile temp table. |
| 127 | ** |
| 128 | ** Automatically exclude the repository file. |
| 129 | */ |
| 130 | static int add_files_in_sfile(int vid){ |
| 131 | const char *zRepo; /* Name of the repository database file */ |
| 132 | int nAdd = 0; /* Number of files added */ |
| 133 | int i; /* Loop counter */ |
| 134 | const char *zReserved; /* Name of a reserved file */ |
| 135 | Blob repoName; /* Treename of the repository */ |
| 136 | Stmt loop; /* SQL to loop over all files to add */ |
| 137 | |
| 138 | if( !file_tree_name(g.zRepositoryName, &repoName, 0) ){ |
| 139 | blob_zero(&repoName); |
| 140 | zRepo = ""; |
| 141 | }else{ |
| 142 | zRepo = blob_str(&repoName); |
| 143 | } |
| 144 | db_prepare(&loop, "SELECT x FROM sfile ORDER BY x"); |
| 145 | while( db_step(&loop)==SQLITE_ROW ){ |
| 146 | const char *zToAdd = db_column_text(&loop, 0); |
| 147 | if( fossil_strcmp(zToAdd, zRepo)==0 ) continue; |
| 148 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 149 | if( fossil_strcmp(zToAdd, zReserved)==0 ) break; |
| 150 | } |
| 151 | if( zReserved ) continue; |
| 152 | nAdd += add_one_file(zToAdd, vid); |
| 153 | } |
| 154 | db_finalize(&loop); |
| 155 | blob_reset(&repoName); |
| 156 | return nAdd; |
| 157 | } |
| 158 | |
| 159 | /* |
| 160 | ** COMMAND: add |
| 161 | ** |
| @@ -221,26 +166,24 @@ | |
| 166 | ** |
| 167 | ** When adding files or directories recursively, filenames that begin |
| 168 | ** with "." are excluded by default. To include such files, add |
| 169 | ** the "--dotfiles" option to the command-line. |
| 170 | ** |
| 171 | ** The --ignore option is a comma-separate list of glob patterns for files |
| 172 | ** to be excluded. Example: '*.o,*.obj,*.exe' If the --ignore option |
| 173 | ** does not appear on the command line then the "ignore-glob" setting is |
| 174 | ** used. |
| 175 | ** |
| 176 | ** SUMMARY: fossil add ?OPTIONS? FILE1 ?FILE2 ...? |
| 177 | ** Options: --dotfiles, --ignore |
| 178 | */ |
| 179 | void add_cmd(void){ |
| 180 | int i; /* Loop counter */ |
| 181 | int vid; /* Currently checked out version */ |
| 182 | int nRoot; /* Full path characters in g.zLocalRoot */ |
| 183 | const char *zIgnoreFlag; /* The --ignore option or ignore-glob setting */ |
| 184 | Glob *pIgnore; /* Ignore everything matching this glob pattern */ |
| 185 | |
| 186 | zIgnoreFlag = find_option("ignore",0,1); |
| 187 | includeDotFiles = find_option("dotfiles",0,0)!=0; |
| 188 | db_must_be_within_tree(); |
| 189 | if( zIgnoreFlag==0 ){ |
| @@ -249,101 +192,49 @@ | |
| 192 | vid = db_lget_int("checkout",0); |
| 193 | if( vid==0 ){ |
| 194 | fossil_panic("no checkout to add to"); |
| 195 | } |
| 196 | db_begin_transaction(); |
| 197 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 198 | #if defined(_WIN32) |
| 199 | db_multi_exec( |
| 200 | "CREATE INDEX IF NOT EXISTS vfile_pathname " |
| 201 | " ON vfile(pathname COLLATE nocase)" |
| 202 | ); |
| 203 | #endif |
| 204 | pIgnore = glob_create(zIgnoreFlag); |
| 205 | nRoot = strlen(g.zLocalRoot); |
| 206 | |
| 207 | /* Load the names of all files that are to be added into sfile temp table */ |
| 208 | for(i=2; i<g.argc; i++){ |
| 209 | char *zName; |
| 210 | int isDir; |
| 211 | Blob fullName; |
| 212 | |
| 213 | file_canonical_name(g.argv[i], &fullName); |
| 214 | zName = blob_str(&fullName); |
| 215 | isDir = file_isdir(zName); |
| 216 | if( isDir==1 ){ |
| 217 | vfile_scan(&fullName, nRoot-1, includeDotFiles, pIgnore); |
| 218 | }else if( isDir==0 ){ |
| 219 | fossil_fatal("not found: %s", zName); |
| 220 | }else if( file_access(zName, R_OK) ){ |
| 221 | fossil_fatal("cannot open %s", zName); |
| 222 | }else{ |
| 223 | char *zTreeName = &zName[nRoot]; |
| 224 | db_multi_exec( |
| 225 | "INSERT OR IGNORE INTO sfile(x)" |
| 226 | " SELECT %Q WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=%Q)", |
| 227 | zTreeName, zTreeName |
| 228 | ); |
| 229 | } |
| 230 | blob_reset(&fullName); |
| 231 | } |
| 232 | glob_free(pIgnore); |
| 233 | |
| 234 | add_files_in_sfile(vid); |
| 235 | db_end_transaction(0); |
| 236 | } |
| 237 | |
| 238 | /* |
| 239 | ** COMMAND: rm |
| 240 | ** COMMAND: delete |
| @@ -361,31 +252,45 @@ | |
| 252 | ** or: fossil delete FILE1 ?FILE2 ...? |
| 253 | */ |
| 254 | void delete_cmd(void){ |
| 255 | int i; |
| 256 | int vid; |
| 257 | Stmt loop; |
| 258 | |
| 259 | db_must_be_within_tree(); |
| 260 | vid = db_lget_int("checkout", 0); |
| 261 | if( vid==0 ){ |
| 262 | fossil_panic("no checkout to remove from"); |
| 263 | } |
| 264 | db_begin_transaction(); |
| 265 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 266 | for(i=2; i<g.argc; i++){ |
| 267 | Blob treeName; |
| 268 | char *zTreeName; |
| 269 | |
| 270 | file_tree_name(g.argv[i], &treeName, 1); |
| 271 | zTreeName = blob_str(&treeName); |
| 272 | db_multi_exec( |
| 273 | "INSERT OR IGNORE INTO sfile" |
| 274 | " SELECT pathname FROM vfile" |
| 275 | " WHERE (pathname=%Q" |
| 276 | " OR (pathname>'%q/' AND pathname<'%q0'))" |
| 277 | " AND NOT deleted", |
| 278 | zTreeName, zTreeName, zTreeName |
| 279 | ); |
| 280 | blob_reset(&treeName); |
| 281 | } |
| 282 | |
| 283 | db_prepare(&loop, "SELECT x FROM sfile"); |
| 284 | while( db_step(&loop)==SQLITE_ROW ){ |
| 285 | fossil_print("DELETED %s\n", db_column_text(&loop, 0)); |
| 286 | } |
| 287 | db_finalize(&loop); |
| 288 | db_multi_exec( |
| 289 | "UPDATE vfile SET deleted=1 WHERE pathname IN sfile;" |
| 290 | "DELETE FROM vfile WHERE rid=0 AND deleted;" |
| 291 | ); |
| 292 | db_end_transaction(0); |
| 293 | } |
| 294 | |
| 295 | /* |
| 296 | ** COMMAND: addremove |
| @@ -426,13 +331,13 @@ | |
| 331 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 332 | int isTest = find_option("test",0,0)!=0; |
| 333 | int n; |
| 334 | Stmt q; |
| 335 | int vid; |
| 336 | int nAdd = 0; |
| 337 | int nDelete = 0; |
| 338 | Glob *pIgnore; |
| 339 | |
| 340 | db_must_be_within_tree(); |
| 341 | if( zIgnoreFlag==0 ){ |
| 342 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 343 | } |
| @@ -439,38 +344,30 @@ | |
| 344 | vid = db_lget_int("checkout",0); |
| 345 | if( vid==0 ){ |
| 346 | fossil_panic("no checkout to add to"); |
| 347 | } |
| 348 | db_begin_transaction(); |
| 349 | |
| 350 | /* step 1: |
| 351 | ** Populate the temp table "sfile" with the names of all unmanged |
| 352 | ** files currently in the check-out, except for files that match the |
| 353 | ** --ignore or ignore-glob patterns and dot-files. Then add all of |
| 354 | ** the files in the sfile temp table to the set of managed files. |
| 355 | */ |
| 356 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 357 | n = strlen(g.zLocalRoot); |
| 358 | blob_init(&path, g.zLocalRoot, n-1); |
| 359 | /* now we read the complete file structure into a temp table */ |
| 360 | pIgnore = glob_create(zIgnoreFlag); |
| 361 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 362 | glob_free(pIgnore); |
| 363 | nAdd = add_files_in_sfile(vid); |
| 364 | |
| 365 | /* step 2: search for missing files */ |
| 366 | db_prepare(&q, |
| 367 | "SELECT pathname, %Q || pathname, deleted FROM vfile" |
| 368 | " WHERE NOT deleted" |
| 369 | " ORDER BY 1", |
| 370 | g.zLocalRoot |
| 371 | ); |
| 372 | while( db_step(&q)==SQLITE_ROW ){ |
| 373 | const char * zFile; |
| @@ -480,17 +377,17 @@ | |
| 377 | zPath = db_column_text(&q, 1); |
| 378 | if( !file_isfile(zPath) ){ |
| 379 | if( !isTest ){ |
| 380 | db_multi_exec("UPDATE vfile SET deleted=1 WHERE pathname=%Q", zFile); |
| 381 | } |
| 382 | fossil_print("DELETED %s\n", zFile); |
| 383 | nDelete++; |
| 384 | } |
| 385 | } |
| 386 | db_finalize(&q); |
| 387 | /* show cmmand summary */ |
| 388 | fossil_print("added %d files, deleted %d files\n", nAdd, nDelete); |
| 389 | |
| 390 | db_end_transaction(isTest); |
| 391 | } |
| 392 | |
| 393 | |
| @@ -498,11 +395,11 @@ | |
| 395 | ** Rename a single file. |
| 396 | ** |
| 397 | ** The original name of the file is zOrig. The new filename is zNew. |
| 398 | */ |
| 399 | static void mv_one_file(int vid, const char *zOrig, const char *zNew){ |
| 400 | fossil_print("RENAME %s %s\n", zOrig, zNew); |
| 401 | db_multi_exec( |
| 402 | "UPDATE vfile SET pathname='%s' WHERE pathname='%s' AND vid=%d", |
| 403 | zNew, zOrig, vid |
| 404 | ); |
| 405 | } |
| @@ -572,13 +469,13 @@ | |
| 469 | zOrig = blob_str(&orig); |
| 470 | nOrig = blob_size(&orig); |
| 471 | db_prepare(&q, |
| 472 | "SELECT pathname FROM vfile" |
| 473 | " WHERE vid=%d" |
| 474 | " AND (pathname='%q' OR (pathname>'%q/' AND pathname<'%q0'))" |
| 475 | " ORDER BY 1", |
| 476 | vid, zOrig, zOrig, zOrig |
| 477 | ); |
| 478 | while( db_step(&q)==SQLITE_ROW ){ |
| 479 | const char *zPath = db_column_text(&q, 0); |
| 480 | int nPath = db_column_bytes(&q, 0); |
| 481 | const char *zTail; |
| 482 |
+4
-4
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -137,22 +137,22 @@ | ||
| 137 | 137 | " FROM global_config" |
| 138 | 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | 139 | ); |
| 140 | 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | - if( access(zFilename, 0) ){ | |
| 142 | + if( file_access(zFilename, 0) ){ | |
| 143 | 143 | nMissing++; |
| 144 | 144 | continue; |
| 145 | 145 | } |
| 146 | 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | 147 | if( zCmd[0]=='l' ){ |
| 148 | - printf("%s\n", zFilename); | |
| 148 | + fossil_print("%s\n", zFilename); | |
| 149 | 149 | continue; |
| 150 | 150 | } |
| 151 | 151 | zQFilename = quoteFilename(zFilename); |
| 152 | 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | - printf("%s\n", zSyscmd); | |
| 153 | + fossil_print("%s\n", zSyscmd); | |
| 154 | 154 | fflush(stdout); |
| 155 | 155 | rc = fossil_system(zSyscmd); |
| 156 | 156 | free(zSyscmd); |
| 157 | 157 | free(zQFilename); |
| 158 | 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | ||
| 167 | 167 | if( nMissing ){ |
| 168 | 168 | db_begin_transaction(); |
| 169 | 169 | db_reset(&q); |
| 170 | 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | - if( access(zFilename, 0) ){ | |
| 172 | + if( file_access(zFilename, 0) ){ | |
| 173 | 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | 174 | db_unset(zRepo, 1); |
| 175 | 175 | free(zRepo); |
| 176 | 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | 177 | Blob cname; |
| 178 | 178 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -137,22 +137,22 @@ | |
| 137 | " FROM global_config" |
| 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | ); |
| 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | if( access(zFilename, 0) ){ |
| 143 | nMissing++; |
| 144 | continue; |
| 145 | } |
| 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | if( zCmd[0]=='l' ){ |
| 148 | printf("%s\n", zFilename); |
| 149 | continue; |
| 150 | } |
| 151 | zQFilename = quoteFilename(zFilename); |
| 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | printf("%s\n", zSyscmd); |
| 154 | fflush(stdout); |
| 155 | rc = fossil_system(zSyscmd); |
| 156 | free(zSyscmd); |
| 157 | free(zQFilename); |
| 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | |
| 167 | if( nMissing ){ |
| 168 | db_begin_transaction(); |
| 169 | db_reset(&q); |
| 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | if( access(zFilename, 0) ){ |
| 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | db_unset(zRepo, 1); |
| 175 | free(zRepo); |
| 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | Blob cname; |
| 178 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -137,22 +137,22 @@ | |
| 137 | " FROM global_config" |
| 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | ); |
| 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | if( file_access(zFilename, 0) ){ |
| 143 | nMissing++; |
| 144 | continue; |
| 145 | } |
| 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | if( zCmd[0]=='l' ){ |
| 148 | fossil_print("%s\n", zFilename); |
| 149 | continue; |
| 150 | } |
| 151 | zQFilename = quoteFilename(zFilename); |
| 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | fossil_print("%s\n", zSyscmd); |
| 154 | fflush(stdout); |
| 155 | rc = fossil_system(zSyscmd); |
| 156 | free(zSyscmd); |
| 157 | free(zQFilename); |
| 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | |
| 167 | if( nMissing ){ |
| 168 | db_begin_transaction(); |
| 169 | db_reset(&q); |
| 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | if( file_access(zFilename, 0) ){ |
| 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | db_unset(zRepo, 1); |
| 175 | free(zRepo); |
| 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | Blob cname; |
| 178 |
+4
-4
| --- src/allrepo.c | ||
| +++ src/allrepo.c | ||
| @@ -137,22 +137,22 @@ | ||
| 137 | 137 | " FROM global_config" |
| 138 | 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | 139 | ); |
| 140 | 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | - if( access(zFilename, 0) ){ | |
| 142 | + if( file_access(zFilename, 0) ){ | |
| 143 | 143 | nMissing++; |
| 144 | 144 | continue; |
| 145 | 145 | } |
| 146 | 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | 147 | if( zCmd[0]=='l' ){ |
| 148 | - printf("%s\n", zFilename); | |
| 148 | + fossil_print("%s\n", zFilename); | |
| 149 | 149 | continue; |
| 150 | 150 | } |
| 151 | 151 | zQFilename = quoteFilename(zFilename); |
| 152 | 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | - printf("%s\n", zSyscmd); | |
| 153 | + fossil_print("%s\n", zSyscmd); | |
| 154 | 154 | fflush(stdout); |
| 155 | 155 | rc = fossil_system(zSyscmd); |
| 156 | 156 | free(zSyscmd); |
| 157 | 157 | free(zQFilename); |
| 158 | 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | ||
| 167 | 167 | if( nMissing ){ |
| 168 | 168 | db_begin_transaction(); |
| 169 | 169 | db_reset(&q); |
| 170 | 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | - if( access(zFilename, 0) ){ | |
| 172 | + if( file_access(zFilename, 0) ){ | |
| 173 | 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | 174 | db_unset(zRepo, 1); |
| 175 | 175 | free(zRepo); |
| 176 | 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | 177 | Blob cname; |
| 178 | 178 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -137,22 +137,22 @@ | |
| 137 | " FROM global_config" |
| 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | ); |
| 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | if( access(zFilename, 0) ){ |
| 143 | nMissing++; |
| 144 | continue; |
| 145 | } |
| 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | if( zCmd[0]=='l' ){ |
| 148 | printf("%s\n", zFilename); |
| 149 | continue; |
| 150 | } |
| 151 | zQFilename = quoteFilename(zFilename); |
| 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | printf("%s\n", zSyscmd); |
| 154 | fflush(stdout); |
| 155 | rc = fossil_system(zSyscmd); |
| 156 | free(zSyscmd); |
| 157 | free(zQFilename); |
| 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | |
| 167 | if( nMissing ){ |
| 168 | db_begin_transaction(); |
| 169 | db_reset(&q); |
| 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | if( access(zFilename, 0) ){ |
| 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | db_unset(zRepo, 1); |
| 175 | free(zRepo); |
| 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | Blob cname; |
| 178 |
| --- src/allrepo.c | |
| +++ src/allrepo.c | |
| @@ -137,22 +137,22 @@ | |
| 137 | " FROM global_config" |
| 138 | " WHERE substr(name, 1, 5)=='repo:' ORDER BY 1" |
| 139 | ); |
| 140 | while( db_step(&q)==SQLITE_ROW ){ |
| 141 | const char *zFilename = db_column_text(&q, 0); |
| 142 | if( file_access(zFilename, 0) ){ |
| 143 | nMissing++; |
| 144 | continue; |
| 145 | } |
| 146 | if( !file_is_canonical(zFilename) ) nMissing++; |
| 147 | if( zCmd[0]=='l' ){ |
| 148 | fossil_print("%s\n", zFilename); |
| 149 | continue; |
| 150 | } |
| 151 | zQFilename = quoteFilename(zFilename); |
| 152 | zSyscmd = mprintf("%s %s %s", zFossil, zCmd, zQFilename); |
| 153 | fossil_print("%s\n", zSyscmd); |
| 154 | fflush(stdout); |
| 155 | rc = fossil_system(zSyscmd); |
| 156 | free(zSyscmd); |
| 157 | free(zQFilename); |
| 158 | if( stopOnError && rc ){ |
| @@ -167,11 +167,11 @@ | |
| 167 | if( nMissing ){ |
| 168 | db_begin_transaction(); |
| 169 | db_reset(&q); |
| 170 | while( db_step(&q)==SQLITE_ROW ){ |
| 171 | const char *zFilename = db_column_text(&q, 0); |
| 172 | if( file_access(zFilename, 0) ){ |
| 173 | char *zRepo = mprintf("repo:%s", zFilename); |
| 174 | db_unset(zRepo, 1); |
| 175 | free(zRepo); |
| 176 | }else if( !file_is_canonical(zFilename) ){ |
| 177 | Blob cname; |
| 178 |
+8
-8
| --- src/bisect.c | ||
| +++ src/bisect.c | ||
| @@ -191,11 +191,11 @@ | ||
| 191 | 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | 192 | if( g.argc==3 ){ |
| 193 | 193 | unsigned int i; |
| 194 | 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | - printf(" %-15s %-6s ", aBisectOption[i].zName, | |
| 196 | + fossil_print(" %-15s %-6s ", aBisectOption[i].zName, | |
| 197 | 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | 198 | fossil_free(z); |
| 199 | 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | 200 | } |
| 201 | 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | ||
| 205 | 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | 207 | if( g.argc==5 ){ |
| 208 | 208 | db_lset(z, g.argv[4]); |
| 209 | 209 | } |
| 210 | - printf("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); | |
| 210 | + fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); | |
| 211 | 211 | fossil_free(z); |
| 212 | 212 | break; |
| 213 | 213 | } |
| 214 | 214 | } |
| 215 | 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | ||
| 237 | 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | 238 | const char *z; |
| 239 | 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | 241 | z = db_column_text(&s, 0); |
| 242 | - printf("%s", z); | |
| 243 | - if( p->rid==bisect.good ) printf(" GOOD"); | |
| 244 | - if( p->rid==bisect.bad ) printf(" BAD"); | |
| 245 | - if( p->rid==vid ) printf(" CURRENT"); | |
| 246 | - if( nStep>1 && n==nStep/2 ) printf(" NEXT"); | |
| 247 | - printf("\n"); | |
| 242 | + fossil_print("%s", z); | |
| 243 | + if( p->rid==bisect.good ) fossil_print(" GOOD"); | |
| 244 | + if( p->rid==bisect.bad ) fossil_print(" BAD"); | |
| 245 | + if( p->rid==vid ) fossil_print(" CURRENT"); | |
| 246 | + if( nStep>1 && n==nStep/2 ) fossil_print(" NEXT"); | |
| 247 | + fossil_print("\n"); | |
| 248 | 248 | } |
| 249 | 249 | db_reset(&s); |
| 250 | 250 | } |
| 251 | 251 | db_finalize(&s); |
| 252 | 252 | }else{ |
| 253 | 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | 254 | } |
| 255 | 255 | } |
| 256 | 256 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -191,11 +191,11 @@ | |
| 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | if( g.argc==3 ){ |
| 193 | unsigned int i; |
| 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | printf(" %-15s %-6s ", aBisectOption[i].zName, |
| 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | fossil_free(z); |
| 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | } |
| 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | |
| 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | if( g.argc==5 ){ |
| 208 | db_lset(z, g.argv[4]); |
| 209 | } |
| 210 | printf("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 211 | fossil_free(z); |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | |
| 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | const char *z; |
| 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | z = db_column_text(&s, 0); |
| 242 | printf("%s", z); |
| 243 | if( p->rid==bisect.good ) printf(" GOOD"); |
| 244 | if( p->rid==bisect.bad ) printf(" BAD"); |
| 245 | if( p->rid==vid ) printf(" CURRENT"); |
| 246 | if( nStep>1 && n==nStep/2 ) printf(" NEXT"); |
| 247 | printf("\n"); |
| 248 | } |
| 249 | db_reset(&s); |
| 250 | } |
| 251 | db_finalize(&s); |
| 252 | }else{ |
| 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | } |
| 255 | } |
| 256 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -191,11 +191,11 @@ | |
| 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | if( g.argc==3 ){ |
| 193 | unsigned int i; |
| 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | fossil_print(" %-15s %-6s ", aBisectOption[i].zName, |
| 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | fossil_free(z); |
| 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | } |
| 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | |
| 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | if( g.argc==5 ){ |
| 208 | db_lset(z, g.argv[4]); |
| 209 | } |
| 210 | fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 211 | fossil_free(z); |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | |
| 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | const char *z; |
| 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | z = db_column_text(&s, 0); |
| 242 | fossil_print("%s", z); |
| 243 | if( p->rid==bisect.good ) fossil_print(" GOOD"); |
| 244 | if( p->rid==bisect.bad ) fossil_print(" BAD"); |
| 245 | if( p->rid==vid ) fossil_print(" CURRENT"); |
| 246 | if( nStep>1 && n==nStep/2 ) fossil_print(" NEXT"); |
| 247 | fossil_print("\n"); |
| 248 | } |
| 249 | db_reset(&s); |
| 250 | } |
| 251 | db_finalize(&s); |
| 252 | }else{ |
| 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | } |
| 255 | } |
| 256 |
+8
-8
| --- src/bisect.c | ||
| +++ src/bisect.c | ||
| @@ -191,11 +191,11 @@ | ||
| 191 | 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | 192 | if( g.argc==3 ){ |
| 193 | 193 | unsigned int i; |
| 194 | 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | - printf(" %-15s %-6s ", aBisectOption[i].zName, | |
| 196 | + fossil_print(" %-15s %-6s ", aBisectOption[i].zName, | |
| 197 | 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | 198 | fossil_free(z); |
| 199 | 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | 200 | } |
| 201 | 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | ||
| 205 | 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | 207 | if( g.argc==5 ){ |
| 208 | 208 | db_lset(z, g.argv[4]); |
| 209 | 209 | } |
| 210 | - printf("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); | |
| 210 | + fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); | |
| 211 | 211 | fossil_free(z); |
| 212 | 212 | break; |
| 213 | 213 | } |
| 214 | 214 | } |
| 215 | 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | ||
| 237 | 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | 238 | const char *z; |
| 239 | 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | 241 | z = db_column_text(&s, 0); |
| 242 | - printf("%s", z); | |
| 243 | - if( p->rid==bisect.good ) printf(" GOOD"); | |
| 244 | - if( p->rid==bisect.bad ) printf(" BAD"); | |
| 245 | - if( p->rid==vid ) printf(" CURRENT"); | |
| 246 | - if( nStep>1 && n==nStep/2 ) printf(" NEXT"); | |
| 247 | - printf("\n"); | |
| 242 | + fossil_print("%s", z); | |
| 243 | + if( p->rid==bisect.good ) fossil_print(" GOOD"); | |
| 244 | + if( p->rid==bisect.bad ) fossil_print(" BAD"); | |
| 245 | + if( p->rid==vid ) fossil_print(" CURRENT"); | |
| 246 | + if( nStep>1 && n==nStep/2 ) fossil_print(" NEXT"); | |
| 247 | + fossil_print("\n"); | |
| 248 | 248 | } |
| 249 | 249 | db_reset(&s); |
| 250 | 250 | } |
| 251 | 251 | db_finalize(&s); |
| 252 | 252 | }else{ |
| 253 | 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | 254 | } |
| 255 | 255 | } |
| 256 | 256 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -191,11 +191,11 @@ | |
| 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | if( g.argc==3 ){ |
| 193 | unsigned int i; |
| 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | printf(" %-15s %-6s ", aBisectOption[i].zName, |
| 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | fossil_free(z); |
| 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | } |
| 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | |
| 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | if( g.argc==5 ){ |
| 208 | db_lset(z, g.argv[4]); |
| 209 | } |
| 210 | printf("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 211 | fossil_free(z); |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | |
| 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | const char *z; |
| 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | z = db_column_text(&s, 0); |
| 242 | printf("%s", z); |
| 243 | if( p->rid==bisect.good ) printf(" GOOD"); |
| 244 | if( p->rid==bisect.bad ) printf(" BAD"); |
| 245 | if( p->rid==vid ) printf(" CURRENT"); |
| 246 | if( nStep>1 && n==nStep/2 ) printf(" NEXT"); |
| 247 | printf("\n"); |
| 248 | } |
| 249 | db_reset(&s); |
| 250 | } |
| 251 | db_finalize(&s); |
| 252 | }else{ |
| 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | } |
| 255 | } |
| 256 |
| --- src/bisect.c | |
| +++ src/bisect.c | |
| @@ -191,11 +191,11 @@ | |
| 191 | }else if( memcmp(zCmd, "options", n)==0 ){ |
| 192 | if( g.argc==3 ){ |
| 193 | unsigned int i; |
| 194 | for(i=0; i<sizeof(aBisectOption)/sizeof(aBisectOption[0]); i++){ |
| 195 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 196 | fossil_print(" %-15s %-6s ", aBisectOption[i].zName, |
| 197 | db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 198 | fossil_free(z); |
| 199 | comment_print(aBisectOption[i].zDesc, 27, 79); |
| 200 | } |
| 201 | }else if( g.argc==4 || g.argc==5 ){ |
| @@ -205,11 +205,11 @@ | |
| 205 | if( memcmp(g.argv[3], aBisectOption[i].zName, n)==0 ){ |
| 206 | char *z = mprintf("bisect-%s", aBisectOption[i].zName); |
| 207 | if( g.argc==5 ){ |
| 208 | db_lset(z, g.argv[4]); |
| 209 | } |
| 210 | fossil_print("%s\n", db_lget(z, (char*)aBisectOption[i].zDefault)); |
| 211 | fossil_free(z); |
| 212 | break; |
| 213 | } |
| 214 | } |
| 215 | if( i>=sizeof(aBisectOption)/sizeof(aBisectOption[0]) ){ |
| @@ -237,19 +237,19 @@ | |
| 237 | for(p=path_last(), n=0; p; p=p->pFrom, n++){ |
| 238 | const char *z; |
| 239 | db_bind_int(&s, ":rid", p->rid); |
| 240 | if( db_step(&s)==SQLITE_ROW ){ |
| 241 | z = db_column_text(&s, 0); |
| 242 | fossil_print("%s", z); |
| 243 | if( p->rid==bisect.good ) fossil_print(" GOOD"); |
| 244 | if( p->rid==bisect.bad ) fossil_print(" BAD"); |
| 245 | if( p->rid==vid ) fossil_print(" CURRENT"); |
| 246 | if( nStep>1 && n==nStep/2 ) fossil_print(" NEXT"); |
| 247 | fossil_print("\n"); |
| 248 | } |
| 249 | db_reset(&s); |
| 250 | } |
| 251 | db_finalize(&s); |
| 252 | }else{ |
| 253 | usage("bad|good|next|reset|vlist ..."); |
| 254 | } |
| 255 | } |
| 256 |
+43
-5
| --- src/blob.c | ||
| +++ src/blob.c | ||
| @@ -111,11 +111,11 @@ | ||
| 111 | 111 | assert( fossil_isspace((char)i) ); |
| 112 | 112 | }else{ |
| 113 | 113 | assert( !fossil_isspace((char)i) ); |
| 114 | 114 | } |
| 115 | 115 | } |
| 116 | - printf("All 256 characters OK\n"); | |
| 116 | + fossil_print("All 256 characters OK\n"); | |
| 117 | 117 | } |
| 118 | 118 | |
| 119 | 119 | /* |
| 120 | 120 | ** This routine is called if a blob operation fails because we |
| 121 | 121 | ** have run out of memory. |
| @@ -494,10 +494,48 @@ | ||
| 494 | 494 | blob_extract(pFrom, i-pFrom->iCursor, pTo); |
| 495 | 495 | while( i<n && fossil_isspace(aData[i]) ){ i++; } |
| 496 | 496 | pFrom->iCursor = i; |
| 497 | 497 | return pTo->nUsed; |
| 498 | 498 | } |
| 499 | + | |
| 500 | +/* | |
| 501 | +** Extract a single SQL token from pFrom and use it to initialize pTo. | |
| 502 | +** Return the number of bytes in the token. If no token is found, | |
| 503 | +** return 0. | |
| 504 | +** | |
| 505 | +** An SQL token consists of one or more non-space characters. If the | |
| 506 | +** first character is ' then the token is terminated by a matching ' | |
| 507 | +** (ignoring double '') or by the end of the string | |
| 508 | +** | |
| 509 | +** The cursor of pFrom is left pointing at the first character past | |
| 510 | +** the end of the token. | |
| 511 | +** | |
| 512 | +** pTo will be an ephermeral blob. If pFrom changes, it might alter | |
| 513 | +** pTo as well. | |
| 514 | +*/ | |
| 515 | +int blob_sqltoken(Blob *pFrom, Blob *pTo){ | |
| 516 | + char *aData = pFrom->aData; | |
| 517 | + int n = pFrom->nUsed; | |
| 518 | + int i = pFrom->iCursor; | |
| 519 | + while( i<n && fossil_isspace(aData[i]) ){ i++; } | |
| 520 | + pFrom->iCursor = i; | |
| 521 | + if( aData[i]=='\'' ){ | |
| 522 | + i++; | |
| 523 | + while( i<n ){ | |
| 524 | + if( aData[i]=='\'' ){ | |
| 525 | + if( aData[++i]!='\'' ) break; | |
| 526 | + } | |
| 527 | + i++; | |
| 528 | + } | |
| 529 | + }else{ | |
| 530 | + while( i<n && !fossil_isspace(aData[i]) ){ i++; } | |
| 531 | + } | |
| 532 | + blob_extract(pFrom, i-pFrom->iCursor, pTo); | |
| 533 | + while( i<n && fossil_isspace(aData[i]) ){ i++; } | |
| 534 | + pFrom->iCursor = i; | |
| 535 | + return pTo->nUsed; | |
| 536 | +} | |
| 499 | 537 | |
| 500 | 538 | /* |
| 501 | 539 | ** Extract everything from the current cursor to the end of the blob |
| 502 | 540 | ** into a new blob. The new blob is an ephemerial reference to the |
| 503 | 541 | ** original blob. The cursor of the original blob is unchanged. |
| @@ -652,11 +690,11 @@ | ||
| 652 | 690 | } |
| 653 | 691 | if( size==0 ){ |
| 654 | 692 | return 0; |
| 655 | 693 | } |
| 656 | 694 | blob_resize(pBlob, size); |
| 657 | - in = fopen(zFilename, "rb"); | |
| 695 | + in = fossil_fopen(zFilename, "rb"); | |
| 658 | 696 | if( in==0 ){ |
| 659 | 697 | fossil_panic("cannot open %s for reading", zFilename); |
| 660 | 698 | } |
| 661 | 699 | got = fread(blob_buffer(pBlob), 1, size, in); |
| 662 | 700 | fclose(in); |
| @@ -712,11 +750,11 @@ | ||
| 712 | 750 | } |
| 713 | 751 | #endif |
| 714 | 752 | zName[i] = '/'; |
| 715 | 753 | } |
| 716 | 754 | } |
| 717 | - out = fopen(zName, "wb"); | |
| 755 | + out = fossil_fopen(zName, "wb"); | |
| 718 | 756 | if( out==0 ){ |
| 719 | 757 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 720 | 758 | return 0; |
| 721 | 759 | } |
| 722 | 760 | needToClose = 1; |
| @@ -723,11 +761,11 @@ | ||
| 723 | 761 | if( zName!=zBuf ) free(zName); |
| 724 | 762 | } |
| 725 | 763 | blob_is_init(pBlob); |
| 726 | 764 | wrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); |
| 727 | 765 | if( needToClose ) fclose(out); |
| 728 | - if( wrote!=blob_size(pBlob) ){ | |
| 766 | + if( wrote!=blob_size(pBlob) && out!=stdout ){ | |
| 729 | 767 | fossil_fatal_recursive("short write: %d of %d bytes to %s", wrote, |
| 730 | 768 | blob_size(pBlob), zFilename); |
| 731 | 769 | } |
| 732 | 770 | return wrote; |
| 733 | 771 | } |
| @@ -887,11 +925,11 @@ | ||
| 887 | 925 | } |
| 888 | 926 | blob_reset(&b1); |
| 889 | 927 | blob_reset(&b2); |
| 890 | 928 | blob_reset(&b3); |
| 891 | 929 | } |
| 892 | - printf("ok\n"); | |
| 930 | + fossil_print("ok\n"); | |
| 893 | 931 | } |
| 894 | 932 | |
| 895 | 933 | #if defined(_WIN32) |
| 896 | 934 | /* |
| 897 | 935 | ** Convert every \n character in the given blob into \r\n. |
| 898 | 936 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -111,11 +111,11 @@ | |
| 111 | assert( fossil_isspace((char)i) ); |
| 112 | }else{ |
| 113 | assert( !fossil_isspace((char)i) ); |
| 114 | } |
| 115 | } |
| 116 | printf("All 256 characters OK\n"); |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | ** This routine is called if a blob operation fails because we |
| 121 | ** have run out of memory. |
| @@ -494,10 +494,48 @@ | |
| 494 | blob_extract(pFrom, i-pFrom->iCursor, pTo); |
| 495 | while( i<n && fossil_isspace(aData[i]) ){ i++; } |
| 496 | pFrom->iCursor = i; |
| 497 | return pTo->nUsed; |
| 498 | } |
| 499 | |
| 500 | /* |
| 501 | ** Extract everything from the current cursor to the end of the blob |
| 502 | ** into a new blob. The new blob is an ephemerial reference to the |
| 503 | ** original blob. The cursor of the original blob is unchanged. |
| @@ -652,11 +690,11 @@ | |
| 652 | } |
| 653 | if( size==0 ){ |
| 654 | return 0; |
| 655 | } |
| 656 | blob_resize(pBlob, size); |
| 657 | in = fopen(zFilename, "rb"); |
| 658 | if( in==0 ){ |
| 659 | fossil_panic("cannot open %s for reading", zFilename); |
| 660 | } |
| 661 | got = fread(blob_buffer(pBlob), 1, size, in); |
| 662 | fclose(in); |
| @@ -712,11 +750,11 @@ | |
| 712 | } |
| 713 | #endif |
| 714 | zName[i] = '/'; |
| 715 | } |
| 716 | } |
| 717 | out = fopen(zName, "wb"); |
| 718 | if( out==0 ){ |
| 719 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 720 | return 0; |
| 721 | } |
| 722 | needToClose = 1; |
| @@ -723,11 +761,11 @@ | |
| 723 | if( zName!=zBuf ) free(zName); |
| 724 | } |
| 725 | blob_is_init(pBlob); |
| 726 | wrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); |
| 727 | if( needToClose ) fclose(out); |
| 728 | if( wrote!=blob_size(pBlob) ){ |
| 729 | fossil_fatal_recursive("short write: %d of %d bytes to %s", wrote, |
| 730 | blob_size(pBlob), zFilename); |
| 731 | } |
| 732 | return wrote; |
| 733 | } |
| @@ -887,11 +925,11 @@ | |
| 887 | } |
| 888 | blob_reset(&b1); |
| 889 | blob_reset(&b2); |
| 890 | blob_reset(&b3); |
| 891 | } |
| 892 | printf("ok\n"); |
| 893 | } |
| 894 | |
| 895 | #if defined(_WIN32) |
| 896 | /* |
| 897 | ** Convert every \n character in the given blob into \r\n. |
| 898 |
| --- src/blob.c | |
| +++ src/blob.c | |
| @@ -111,11 +111,11 @@ | |
| 111 | assert( fossil_isspace((char)i) ); |
| 112 | }else{ |
| 113 | assert( !fossil_isspace((char)i) ); |
| 114 | } |
| 115 | } |
| 116 | fossil_print("All 256 characters OK\n"); |
| 117 | } |
| 118 | |
| 119 | /* |
| 120 | ** This routine is called if a blob operation fails because we |
| 121 | ** have run out of memory. |
| @@ -494,10 +494,48 @@ | |
| 494 | blob_extract(pFrom, i-pFrom->iCursor, pTo); |
| 495 | while( i<n && fossil_isspace(aData[i]) ){ i++; } |
| 496 | pFrom->iCursor = i; |
| 497 | return pTo->nUsed; |
| 498 | } |
| 499 | |
| 500 | /* |
| 501 | ** Extract a single SQL token from pFrom and use it to initialize pTo. |
| 502 | ** Return the number of bytes in the token. If no token is found, |
| 503 | ** return 0. |
| 504 | ** |
| 505 | ** An SQL token consists of one or more non-space characters. If the |
| 506 | ** first character is ' then the token is terminated by a matching ' |
| 507 | ** (ignoring double '') or by the end of the string |
| 508 | ** |
| 509 | ** The cursor of pFrom is left pointing at the first character past |
| 510 | ** the end of the token. |
| 511 | ** |
| 512 | ** pTo will be an ephermeral blob. If pFrom changes, it might alter |
| 513 | ** pTo as well. |
| 514 | */ |
| 515 | int blob_sqltoken(Blob *pFrom, Blob *pTo){ |
| 516 | char *aData = pFrom->aData; |
| 517 | int n = pFrom->nUsed; |
| 518 | int i = pFrom->iCursor; |
| 519 | while( i<n && fossil_isspace(aData[i]) ){ i++; } |
| 520 | pFrom->iCursor = i; |
| 521 | if( aData[i]=='\'' ){ |
| 522 | i++; |
| 523 | while( i<n ){ |
| 524 | if( aData[i]=='\'' ){ |
| 525 | if( aData[++i]!='\'' ) break; |
| 526 | } |
| 527 | i++; |
| 528 | } |
| 529 | }else{ |
| 530 | while( i<n && !fossil_isspace(aData[i]) ){ i++; } |
| 531 | } |
| 532 | blob_extract(pFrom, i-pFrom->iCursor, pTo); |
| 533 | while( i<n && fossil_isspace(aData[i]) ){ i++; } |
| 534 | pFrom->iCursor = i; |
| 535 | return pTo->nUsed; |
| 536 | } |
| 537 | |
| 538 | /* |
| 539 | ** Extract everything from the current cursor to the end of the blob |
| 540 | ** into a new blob. The new blob is an ephemerial reference to the |
| 541 | ** original blob. The cursor of the original blob is unchanged. |
| @@ -652,11 +690,11 @@ | |
| 690 | } |
| 691 | if( size==0 ){ |
| 692 | return 0; |
| 693 | } |
| 694 | blob_resize(pBlob, size); |
| 695 | in = fossil_fopen(zFilename, "rb"); |
| 696 | if( in==0 ){ |
| 697 | fossil_panic("cannot open %s for reading", zFilename); |
| 698 | } |
| 699 | got = fread(blob_buffer(pBlob), 1, size, in); |
| 700 | fclose(in); |
| @@ -712,11 +750,11 @@ | |
| 750 | } |
| 751 | #endif |
| 752 | zName[i] = '/'; |
| 753 | } |
| 754 | } |
| 755 | out = fossil_fopen(zName, "wb"); |
| 756 | if( out==0 ){ |
| 757 | fossil_fatal_recursive("unable to open file \"%s\" for writing", zName); |
| 758 | return 0; |
| 759 | } |
| 760 | needToClose = 1; |
| @@ -723,11 +761,11 @@ | |
| 761 | if( zName!=zBuf ) free(zName); |
| 762 | } |
| 763 | blob_is_init(pBlob); |
| 764 | wrote = fwrite(blob_buffer(pBlob), 1, blob_size(pBlob), out); |
| 765 | if( needToClose ) fclose(out); |
| 766 | if( wrote!=blob_size(pBlob) && out!=stdout ){ |
| 767 | fossil_fatal_recursive("short write: %d of %d bytes to %s", wrote, |
| 768 | blob_size(pBlob), zFilename); |
| 769 | } |
| 770 | return wrote; |
| 771 | } |
| @@ -887,11 +925,11 @@ | |
| 925 | } |
| 926 | blob_reset(&b1); |
| 927 | blob_reset(&b2); |
| 928 | blob_reset(&b3); |
| 929 | } |
| 930 | fossil_print("ok\n"); |
| 931 | } |
| 932 | |
| 933 | #if defined(_WIN32) |
| 934 | /* |
| 935 | ** Convert every \n character in the given blob into \r\n. |
| 936 |
+25
-11
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -157,13 +157,13 @@ | ||
| 157 | 157 | fossil_panic("unable to install new manifest"); |
| 158 | 158 | } |
| 159 | 159 | assert( blob_is_reset(&branch) ); |
| 160 | 160 | content_deltify(rootid, brid, 0); |
| 161 | 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | - printf("New branch: %s\n", zUuid); | |
| 162 | + fossil_print("New branch: %s\n", zUuid); | |
| 163 | 163 | if( g.argc==3 ){ |
| 164 | - printf( | |
| 164 | + fossil_print( | |
| 165 | 165 | "\n" |
| 166 | 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | 168 | "\n" |
| 169 | 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | ||
| 234 | 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | 235 | ); |
| 236 | 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | - printf("%s%s\n", (isCur ? "* " : " "), zBr); | |
| 239 | + fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); | |
| 240 | 240 | } |
| 241 | 241 | db_finalize(&q); |
| 242 | 242 | }else{ |
| 243 | 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | ||
| 281 | 281 | @ reopened)</li> |
| 282 | 282 | @ </ol> |
| 283 | 283 | style_sidebox_end(); |
| 284 | 284 | |
| 285 | 285 | cnt = 0; |
| 286 | - db_prepare(&q, | |
| 287 | - "SELECT DISTINCT value FROM tagxref" | |
| 288 | - " WHERE tagid=%d AND value NOT NULL" | |
| 289 | - " AND rid IN leaf" | |
| 290 | - " AND %s %z" | |
| 291 | - " ORDER BY value /*sort*/", | |
| 292 | - TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") | |
| 293 | - ); | |
| 286 | + if( showClosed ){ | |
| 287 | + db_prepare(&q, | |
| 288 | + "SELECT value FROM tagxref" | |
| 289 | + " WHERE tagid=%d AND value NOT NULL " | |
| 290 | + "EXCEPT " | |
| 291 | + "SELECT value FROM tagxref" | |
| 292 | + " WHERE tagid=%d" | |
| 293 | + " AND rid IN leaf" | |
| 294 | + " AND NOT %z" | |
| 295 | + " ORDER BY value /*sort*/", | |
| 296 | + TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 297 | + ); | |
| 298 | + }else{ | |
| 299 | + db_prepare(&q, | |
| 300 | + "SELECT DISTINCT value FROM tagxref" | |
| 301 | + " WHERE tagid=%d AND value NOT NULL" | |
| 302 | + " AND rid IN leaf" | |
| 303 | + " AND NOT %z" | |
| 304 | + " ORDER BY value /*sort*/", | |
| 305 | + TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 306 | + ); | |
| 307 | + } | |
| 294 | 308 | while( db_step(&q)==SQLITE_ROW ){ |
| 295 | 309 | const char *zBr = db_column_text(&q, 0); |
| 296 | 310 | if( cnt==0 ){ |
| 297 | 311 | if( showClosed ){ |
| 298 | 312 | @ <h2>Closed Branches:</h2> |
| 299 | 313 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -157,13 +157,13 @@ | |
| 157 | fossil_panic("unable to install new manifest"); |
| 158 | } |
| 159 | assert( blob_is_reset(&branch) ); |
| 160 | content_deltify(rootid, brid, 0); |
| 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | printf("New branch: %s\n", zUuid); |
| 163 | if( g.argc==3 ){ |
| 164 | printf( |
| 165 | "\n" |
| 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | "\n" |
| 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | |
| 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | ); |
| 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | printf("%s%s\n", (isCur ? "* " : " "), zBr); |
| 240 | } |
| 241 | db_finalize(&q); |
| 242 | }else{ |
| 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | |
| 281 | @ reopened)</li> |
| 282 | @ </ol> |
| 283 | style_sidebox_end(); |
| 284 | |
| 285 | cnt = 0; |
| 286 | db_prepare(&q, |
| 287 | "SELECT DISTINCT value FROM tagxref" |
| 288 | " WHERE tagid=%d AND value NOT NULL" |
| 289 | " AND rid IN leaf" |
| 290 | " AND %s %z" |
| 291 | " ORDER BY value /*sort*/", |
| 292 | TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") |
| 293 | ); |
| 294 | while( db_step(&q)==SQLITE_ROW ){ |
| 295 | const char *zBr = db_column_text(&q, 0); |
| 296 | if( cnt==0 ){ |
| 297 | if( showClosed ){ |
| 298 | @ <h2>Closed Branches:</h2> |
| 299 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -157,13 +157,13 @@ | |
| 157 | fossil_panic("unable to install new manifest"); |
| 158 | } |
| 159 | assert( blob_is_reset(&branch) ); |
| 160 | content_deltify(rootid, brid, 0); |
| 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | fossil_print("New branch: %s\n", zUuid); |
| 163 | if( g.argc==3 ){ |
| 164 | fossil_print( |
| 165 | "\n" |
| 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | "\n" |
| 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | |
| 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | ); |
| 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 240 | } |
| 241 | db_finalize(&q); |
| 242 | }else{ |
| 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | |
| 281 | @ reopened)</li> |
| 282 | @ </ol> |
| 283 | style_sidebox_end(); |
| 284 | |
| 285 | cnt = 0; |
| 286 | if( showClosed ){ |
| 287 | db_prepare(&q, |
| 288 | "SELECT value FROM tagxref" |
| 289 | " WHERE tagid=%d AND value NOT NULL " |
| 290 | "EXCEPT " |
| 291 | "SELECT value FROM tagxref" |
| 292 | " WHERE tagid=%d" |
| 293 | " AND rid IN leaf" |
| 294 | " AND NOT %z" |
| 295 | " ORDER BY value /*sort*/", |
| 296 | TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 297 | ); |
| 298 | }else{ |
| 299 | db_prepare(&q, |
| 300 | "SELECT DISTINCT value FROM tagxref" |
| 301 | " WHERE tagid=%d AND value NOT NULL" |
| 302 | " AND rid IN leaf" |
| 303 | " AND NOT %z" |
| 304 | " ORDER BY value /*sort*/", |
| 305 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 306 | ); |
| 307 | } |
| 308 | while( db_step(&q)==SQLITE_ROW ){ |
| 309 | const char *zBr = db_column_text(&q, 0); |
| 310 | if( cnt==0 ){ |
| 311 | if( showClosed ){ |
| 312 | @ <h2>Closed Branches:</h2> |
| 313 |
+25
-11
| --- src/branch.c | ||
| +++ src/branch.c | ||
| @@ -157,13 +157,13 @@ | ||
| 157 | 157 | fossil_panic("unable to install new manifest"); |
| 158 | 158 | } |
| 159 | 159 | assert( blob_is_reset(&branch) ); |
| 160 | 160 | content_deltify(rootid, brid, 0); |
| 161 | 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | - printf("New branch: %s\n", zUuid); | |
| 162 | + fossil_print("New branch: %s\n", zUuid); | |
| 163 | 163 | if( g.argc==3 ){ |
| 164 | - printf( | |
| 164 | + fossil_print( | |
| 165 | 165 | "\n" |
| 166 | 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | 168 | "\n" |
| 169 | 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | ||
| 234 | 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | 235 | ); |
| 236 | 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | - printf("%s%s\n", (isCur ? "* " : " "), zBr); | |
| 239 | + fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); | |
| 240 | 240 | } |
| 241 | 241 | db_finalize(&q); |
| 242 | 242 | }else{ |
| 243 | 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | ||
| 281 | 281 | @ reopened)</li> |
| 282 | 282 | @ </ol> |
| 283 | 283 | style_sidebox_end(); |
| 284 | 284 | |
| 285 | 285 | cnt = 0; |
| 286 | - db_prepare(&q, | |
| 287 | - "SELECT DISTINCT value FROM tagxref" | |
| 288 | - " WHERE tagid=%d AND value NOT NULL" | |
| 289 | - " AND rid IN leaf" | |
| 290 | - " AND %s %z" | |
| 291 | - " ORDER BY value /*sort*/", | |
| 292 | - TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") | |
| 293 | - ); | |
| 286 | + if( showClosed ){ | |
| 287 | + db_prepare(&q, | |
| 288 | + "SELECT value FROM tagxref" | |
| 289 | + " WHERE tagid=%d AND value NOT NULL " | |
| 290 | + "EXCEPT " | |
| 291 | + "SELECT value FROM tagxref" | |
| 292 | + " WHERE tagid=%d" | |
| 293 | + " AND rid IN leaf" | |
| 294 | + " AND NOT %z" | |
| 295 | + " ORDER BY value /*sort*/", | |
| 296 | + TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 297 | + ); | |
| 298 | + }else{ | |
| 299 | + db_prepare(&q, | |
| 300 | + "SELECT DISTINCT value FROM tagxref" | |
| 301 | + " WHERE tagid=%d AND value NOT NULL" | |
| 302 | + " AND rid IN leaf" | |
| 303 | + " AND NOT %z" | |
| 304 | + " ORDER BY value /*sort*/", | |
| 305 | + TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") | |
| 306 | + ); | |
| 307 | + } | |
| 294 | 308 | while( db_step(&q)==SQLITE_ROW ){ |
| 295 | 309 | const char *zBr = db_column_text(&q, 0); |
| 296 | 310 | if( cnt==0 ){ |
| 297 | 311 | if( showClosed ){ |
| 298 | 312 | @ <h2>Closed Branches:</h2> |
| 299 | 313 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -157,13 +157,13 @@ | |
| 157 | fossil_panic("unable to install new manifest"); |
| 158 | } |
| 159 | assert( blob_is_reset(&branch) ); |
| 160 | content_deltify(rootid, brid, 0); |
| 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | printf("New branch: %s\n", zUuid); |
| 163 | if( g.argc==3 ){ |
| 164 | printf( |
| 165 | "\n" |
| 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | "\n" |
| 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | |
| 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | ); |
| 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | printf("%s%s\n", (isCur ? "* " : " "), zBr); |
| 240 | } |
| 241 | db_finalize(&q); |
| 242 | }else{ |
| 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | |
| 281 | @ reopened)</li> |
| 282 | @ </ol> |
| 283 | style_sidebox_end(); |
| 284 | |
| 285 | cnt = 0; |
| 286 | db_prepare(&q, |
| 287 | "SELECT DISTINCT value FROM tagxref" |
| 288 | " WHERE tagid=%d AND value NOT NULL" |
| 289 | " AND rid IN leaf" |
| 290 | " AND %s %z" |
| 291 | " ORDER BY value /*sort*/", |
| 292 | TAG_BRANCH, showClosed ? "" : "NOT", leaf_is_closed_sql("tagxref.rid") |
| 293 | ); |
| 294 | while( db_step(&q)==SQLITE_ROW ){ |
| 295 | const char *zBr = db_column_text(&q, 0); |
| 296 | if( cnt==0 ){ |
| 297 | if( showClosed ){ |
| 298 | @ <h2>Closed Branches:</h2> |
| 299 |
| --- src/branch.c | |
| +++ src/branch.c | |
| @@ -157,13 +157,13 @@ | |
| 157 | fossil_panic("unable to install new manifest"); |
| 158 | } |
| 159 | assert( blob_is_reset(&branch) ); |
| 160 | content_deltify(rootid, brid, 0); |
| 161 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", brid); |
| 162 | fossil_print("New branch: %s\n", zUuid); |
| 163 | if( g.argc==3 ){ |
| 164 | fossil_print( |
| 165 | "\n" |
| 166 | "Note: the local check-out has not been updated to the new\n" |
| 167 | " branch. To begin working on the new branch, do this:\n" |
| 168 | "\n" |
| 169 | " %s update %s\n", |
| @@ -234,11 +234,11 @@ | |
| 234 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 235 | ); |
| 236 | while( db_step(&q)==SQLITE_ROW ){ |
| 237 | const char *zBr = db_column_text(&q, 0); |
| 238 | int isCur = zCurrent!=0 && fossil_strcmp(zCurrent,zBr)==0; |
| 239 | fossil_print("%s%s\n", (isCur ? "* " : " "), zBr); |
| 240 | } |
| 241 | db_finalize(&q); |
| 242 | }else{ |
| 243 | fossil_panic("branch subcommand should be one of: " |
| 244 | "new list ls"); |
| @@ -281,18 +281,32 @@ | |
| 281 | @ reopened)</li> |
| 282 | @ </ol> |
| 283 | style_sidebox_end(); |
| 284 | |
| 285 | cnt = 0; |
| 286 | if( showClosed ){ |
| 287 | db_prepare(&q, |
| 288 | "SELECT value FROM tagxref" |
| 289 | " WHERE tagid=%d AND value NOT NULL " |
| 290 | "EXCEPT " |
| 291 | "SELECT value FROM tagxref" |
| 292 | " WHERE tagid=%d" |
| 293 | " AND rid IN leaf" |
| 294 | " AND NOT %z" |
| 295 | " ORDER BY value /*sort*/", |
| 296 | TAG_BRANCH, TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 297 | ); |
| 298 | }else{ |
| 299 | db_prepare(&q, |
| 300 | "SELECT DISTINCT value FROM tagxref" |
| 301 | " WHERE tagid=%d AND value NOT NULL" |
| 302 | " AND rid IN leaf" |
| 303 | " AND NOT %z" |
| 304 | " ORDER BY value /*sort*/", |
| 305 | TAG_BRANCH, leaf_is_closed_sql("tagxref.rid") |
| 306 | ); |
| 307 | } |
| 308 | while( db_step(&q)==SQLITE_ROW ){ |
| 309 | const char *zBr = db_column_text(&q, 0); |
| 310 | if( cnt==0 ){ |
| 311 | if( showClosed ){ |
| 312 | @ <h2>Closed Branches:</h2> |
| 313 |
+1
-1
| --- src/captcha.c | ||
| +++ src/captcha.c | ||
| @@ -392,11 +392,11 @@ | ||
| 392 | 392 | for(i=2; i<g.argc; i++){ |
| 393 | 393 | char zHex[30]; |
| 394 | 394 | v = (unsigned int)atoi(g.argv[i]); |
| 395 | 395 | sqlite3_snprintf(sizeof(zHex), zHex, "%x", v); |
| 396 | 396 | z = captcha_render(zHex); |
| 397 | - printf("%s:\n%s", zHex, z); | |
| 397 | + fossil_print("%s:\n%s", zHex, z); | |
| 398 | 398 | free(z); |
| 399 | 399 | } |
| 400 | 400 | } |
| 401 | 401 | |
| 402 | 402 | /* |
| 403 | 403 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -392,11 +392,11 @@ | |
| 392 | for(i=2; i<g.argc; i++){ |
| 393 | char zHex[30]; |
| 394 | v = (unsigned int)atoi(g.argv[i]); |
| 395 | sqlite3_snprintf(sizeof(zHex), zHex, "%x", v); |
| 396 | z = captcha_render(zHex); |
| 397 | printf("%s:\n%s", zHex, z); |
| 398 | free(z); |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | /* |
| 403 |
| --- src/captcha.c | |
| +++ src/captcha.c | |
| @@ -392,11 +392,11 @@ | |
| 392 | for(i=2; i<g.argc; i++){ |
| 393 | char zHex[30]; |
| 394 | v = (unsigned int)atoi(g.argv[i]); |
| 395 | sqlite3_snprintf(sizeof(zHex), zHex, "%x", v); |
| 396 | z = captcha_render(zHex); |
| 397 | fossil_print("%s:\n%s", zHex, z); |
| 398 | free(z); |
| 399 | } |
| 400 | } |
| 401 | |
| 402 | /* |
| 403 |
+29
-8
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -2,11 +2,11 @@ | ||
| 2 | 2 | ** Copyright (c) 2006 D. Richard Hipp |
| 3 | 3 | ** |
| 4 | 4 | ** This program is free software; you can redistribute it and/or |
| 5 | 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | - | |
| 7 | +** | |
| 8 | 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | 9 | ** but without any warranty; without even the implied warranty of |
| 10 | 10 | ** merchantability or fitness for a particular purpose. |
| 11 | 11 | ** |
| 12 | 12 | ** Author contact information: |
| @@ -55,12 +55,12 @@ | ||
| 55 | 55 | ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y") |
| 56 | 56 | ** does the same except "y" is returned in place of NULL if there is not match. |
| 57 | 57 | */ |
| 58 | 58 | #define P(x) cgi_parameter((x),0) |
| 59 | 59 | #define PD(x,y) cgi_parameter((x),(y)) |
| 60 | -#define QP(x) quotable_string(cgi_parameter((x),0)) | |
| 61 | -#define QPD(x,y) quotable_string(cgi_parameter((x),(y))) | |
| 60 | +#define PT(x) cgi_parameter_trimmed((x),0) | |
| 61 | +#define PDT(x,y) cgi_parameter_trimmed((x),(y)) | |
| 62 | 62 | |
| 63 | 63 | |
| 64 | 64 | /* |
| 65 | 65 | ** Destinations for output text. |
| 66 | 66 | */ |
| @@ -191,20 +191,24 @@ | ||
| 191 | 191 | const char *zName, /* Name of the cookie */ |
| 192 | 192 | const char *zValue, /* Value of the cookie. Automatically escaped */ |
| 193 | 193 | const char *zPath, /* Path cookie applies to. NULL means "/" */ |
| 194 | 194 | int lifetime /* Expiration of the cookie in seconds from now */ |
| 195 | 195 | ){ |
| 196 | + char *zSecure = ""; | |
| 196 | 197 | if( zPath==0 ) zPath = g.zTop; |
| 198 | + if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){ | |
| 199 | + zSecure = " secure;"; | |
| 200 | + } | |
| 197 | 201 | if( lifetime>0 ){ |
| 198 | 202 | lifetime += (int)time(0); |
| 199 | 203 | blob_appendf(&extraHeader, |
| 200 | - "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n", | |
| 201 | - zName, zValue, zPath, cgi_rfc822_datestamp(lifetime)); | |
| 204 | + "Set-Cookie: %s=%t; Path=%s; expires=%z; HttpOnly;%s Version=1\r\n", | |
| 205 | + zName, zValue, zPath, cgi_rfc822_datestamp(lifetime), zSecure); | |
| 202 | 206 | }else{ |
| 203 | 207 | blob_appendf(&extraHeader, |
| 204 | - "Set-Cookie: %s=%t; Path=%s; Version=1\r\n", | |
| 205 | - zName, zValue, zPath); | |
| 208 | + "Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n", | |
| 209 | + zName, zValue, zPath, zSecure); | |
| 206 | 210 | } |
| 207 | 211 | } |
| 208 | 212 | |
| 209 | 213 | #if 0 |
| 210 | 214 | /* |
| @@ -787,10 +791,27 @@ | ||
| 787 | 791 | } |
| 788 | 792 | } |
| 789 | 793 | CGIDEBUG(("no-match [%s]\n", zName)); |
| 790 | 794 | return zDefault; |
| 791 | 795 | } |
| 796 | + | |
| 797 | +/* | |
| 798 | +** Return the value of a CGI parameter with leading and trailing | |
| 799 | +** spaces removed. | |
| 800 | +*/ | |
| 801 | +char *cgi_parameter_trimmed(const char *zName, const char *zDefault){ | |
| 802 | + const char *zIn; | |
| 803 | + char *zOut; | |
| 804 | + int i; | |
| 805 | + zIn = cgi_parameter(zName, 0); | |
| 806 | + if( zIn==0 ) zIn = zDefault; | |
| 807 | + while( fossil_isspace(zIn[0]) ) zIn++; | |
| 808 | + zOut = fossil_strdup(zIn); | |
| 809 | + for(i=0; zOut[i]; i++){} | |
| 810 | + while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; | |
| 811 | + return zOut; | |
| 812 | +} | |
| 792 | 813 | |
| 793 | 814 | /* |
| 794 | 815 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 795 | 816 | ** are fewer than i registered CGI parmaeters. |
| 796 | 817 | */ |
| @@ -1099,11 +1120,11 @@ | ||
| 1099 | 1120 | } |
| 1100 | 1121 | } |
| 1101 | 1122 | if( iPort>mxPort ) return 1; |
| 1102 | 1123 | listen(listener,10); |
| 1103 | 1124 | if( iPort>mnPort ){ |
| 1104 | - printf("Listening for HTTP requests on TCP port %d\n", iPort); | |
| 1125 | + fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); | |
| 1105 | 1126 | fflush(stdout); |
| 1106 | 1127 | } |
| 1107 | 1128 | if( zBrowser ){ |
| 1108 | 1129 | zBrowser = mprintf(zBrowser, iPort); |
| 1109 | 1130 | system(zBrowser); |
| 1110 | 1131 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2006 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -55,12 +55,12 @@ | |
| 55 | ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y") |
| 56 | ** does the same except "y" is returned in place of NULL if there is not match. |
| 57 | */ |
| 58 | #define P(x) cgi_parameter((x),0) |
| 59 | #define PD(x,y) cgi_parameter((x),(y)) |
| 60 | #define QP(x) quotable_string(cgi_parameter((x),0)) |
| 61 | #define QPD(x,y) quotable_string(cgi_parameter((x),(y))) |
| 62 | |
| 63 | |
| 64 | /* |
| 65 | ** Destinations for output text. |
| 66 | */ |
| @@ -191,20 +191,24 @@ | |
| 191 | const char *zName, /* Name of the cookie */ |
| 192 | const char *zValue, /* Value of the cookie. Automatically escaped */ |
| 193 | const char *zPath, /* Path cookie applies to. NULL means "/" */ |
| 194 | int lifetime /* Expiration of the cookie in seconds from now */ |
| 195 | ){ |
| 196 | if( zPath==0 ) zPath = g.zTop; |
| 197 | if( lifetime>0 ){ |
| 198 | lifetime += (int)time(0); |
| 199 | blob_appendf(&extraHeader, |
| 200 | "Set-Cookie: %s=%t; Path=%s; expires=%z; Version=1\r\n", |
| 201 | zName, zValue, zPath, cgi_rfc822_datestamp(lifetime)); |
| 202 | }else{ |
| 203 | blob_appendf(&extraHeader, |
| 204 | "Set-Cookie: %s=%t; Path=%s; Version=1\r\n", |
| 205 | zName, zValue, zPath); |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | #if 0 |
| 210 | /* |
| @@ -787,10 +791,27 @@ | |
| 787 | } |
| 788 | } |
| 789 | CGIDEBUG(("no-match [%s]\n", zName)); |
| 790 | return zDefault; |
| 791 | } |
| 792 | |
| 793 | /* |
| 794 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 795 | ** are fewer than i registered CGI parmaeters. |
| 796 | */ |
| @@ -1099,11 +1120,11 @@ | |
| 1099 | } |
| 1100 | } |
| 1101 | if( iPort>mxPort ) return 1; |
| 1102 | listen(listener,10); |
| 1103 | if( iPort>mnPort ){ |
| 1104 | printf("Listening for HTTP requests on TCP port %d\n", iPort); |
| 1105 | fflush(stdout); |
| 1106 | } |
| 1107 | if( zBrowser ){ |
| 1108 | zBrowser = mprintf(zBrowser, iPort); |
| 1109 | system(zBrowser); |
| 1110 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2006 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -55,12 +55,12 @@ | |
| 55 | ** or cookie "x", or NULL if there is no such parameter or cookie. PD("x","y") |
| 56 | ** does the same except "y" is returned in place of NULL if there is not match. |
| 57 | */ |
| 58 | #define P(x) cgi_parameter((x),0) |
| 59 | #define PD(x,y) cgi_parameter((x),(y)) |
| 60 | #define PT(x) cgi_parameter_trimmed((x),0) |
| 61 | #define PDT(x,y) cgi_parameter_trimmed((x),(y)) |
| 62 | |
| 63 | |
| 64 | /* |
| 65 | ** Destinations for output text. |
| 66 | */ |
| @@ -191,20 +191,24 @@ | |
| 191 | const char *zName, /* Name of the cookie */ |
| 192 | const char *zValue, /* Value of the cookie. Automatically escaped */ |
| 193 | const char *zPath, /* Path cookie applies to. NULL means "/" */ |
| 194 | int lifetime /* Expiration of the cookie in seconds from now */ |
| 195 | ){ |
| 196 | char *zSecure = ""; |
| 197 | if( zPath==0 ) zPath = g.zTop; |
| 198 | if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){ |
| 199 | zSecure = " secure;"; |
| 200 | } |
| 201 | if( lifetime>0 ){ |
| 202 | lifetime += (int)time(0); |
| 203 | blob_appendf(&extraHeader, |
| 204 | "Set-Cookie: %s=%t; Path=%s; expires=%z; HttpOnly;%s Version=1\r\n", |
| 205 | zName, zValue, zPath, cgi_rfc822_datestamp(lifetime), zSecure); |
| 206 | }else{ |
| 207 | blob_appendf(&extraHeader, |
| 208 | "Set-Cookie: %s=%t; Path=%s; HttpOnly;%s Version=1\r\n", |
| 209 | zName, zValue, zPath, zSecure); |
| 210 | } |
| 211 | } |
| 212 | |
| 213 | #if 0 |
| 214 | /* |
| @@ -787,10 +791,27 @@ | |
| 791 | } |
| 792 | } |
| 793 | CGIDEBUG(("no-match [%s]\n", zName)); |
| 794 | return zDefault; |
| 795 | } |
| 796 | |
| 797 | /* |
| 798 | ** Return the value of a CGI parameter with leading and trailing |
| 799 | ** spaces removed. |
| 800 | */ |
| 801 | char *cgi_parameter_trimmed(const char *zName, const char *zDefault){ |
| 802 | const char *zIn; |
| 803 | char *zOut; |
| 804 | int i; |
| 805 | zIn = cgi_parameter(zName, 0); |
| 806 | if( zIn==0 ) zIn = zDefault; |
| 807 | while( fossil_isspace(zIn[0]) ) zIn++; |
| 808 | zOut = fossil_strdup(zIn); |
| 809 | for(i=0; zOut[i]; i++){} |
| 810 | while( i>0 && fossil_isspace(zOut[i-1]) ) zOut[--i] = 0; |
| 811 | return zOut; |
| 812 | } |
| 813 | |
| 814 | /* |
| 815 | ** Return the name of the i-th CGI parameter. Return NULL if there |
| 816 | ** are fewer than i registered CGI parmaeters. |
| 817 | */ |
| @@ -1099,11 +1120,11 @@ | |
| 1120 | } |
| 1121 | } |
| 1122 | if( iPort>mxPort ) return 1; |
| 1123 | listen(listener,10); |
| 1124 | if( iPort>mnPort ){ |
| 1125 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 1126 | fflush(stdout); |
| 1127 | } |
| 1128 | if( zBrowser ){ |
| 1129 | zBrowser = mprintf(zBrowser, iPort); |
| 1130 | system(zBrowser); |
| 1131 |
+41
-102
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -54,11 +54,11 @@ | ||
| 54 | 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | 56 | if( isDeleted ){ |
| 57 | 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | - if( access(zFullName, 0)==0 ){ | |
| 59 | + if( file_access(zFullName, 0)==0 ){ | |
| 60 | 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | 61 | if( missingIsFatal ){ |
| 62 | 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | 63 | nErr++; |
| 64 | 64 | } |
| @@ -142,13 +142,13 @@ | ||
| 142 | 142 | */ |
| 143 | 143 | void status_cmd(void){ |
| 144 | 144 | int vid; |
| 145 | 145 | db_must_be_within_tree(); |
| 146 | 146 | /* 012345678901234 */ |
| 147 | - printf("repository: %s\n", db_lget("repository","")); | |
| 148 | - printf("local-root: %s\n", g.zLocalRoot); | |
| 149 | - printf("server-code: %s\n", db_get("server-code", "")); | |
| 147 | + fossil_print("repository: %s\n", db_lget("repository","")); | |
| 148 | + fossil_print("local-root: %s\n", g.zLocalRoot); | |
| 149 | + fossil_print("server-code: %s\n", db_get("server-code", "")); | |
| 150 | 150 | vid = db_lget_int("checkout", 0); |
| 151 | 151 | if( vid ){ |
| 152 | 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | 153 | } |
| 154 | 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | ||
| 185 | 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | 186 | int chnged = db_column_int(&q,3); |
| 187 | 187 | int renamed = db_column_int(&q,4); |
| 188 | 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | 189 | if( isBrief ){ |
| 190 | - printf("%s\n", zPathname); | |
| 190 | + fossil_print("%s\n", zPathname); | |
| 191 | 191 | }else if( isNew ){ |
| 192 | - printf("ADDED %s\n", zPathname); | |
| 192 | + fossil_print("ADDED %s\n", zPathname); | |
| 193 | 193 | }else if( isDeleted ){ |
| 194 | - printf("DELETED %s\n", zPathname); | |
| 194 | + fossil_print("DELETED %s\n", zPathname); | |
| 195 | 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | - if( access(zFullName, 0)==0 ){ | |
| 197 | - printf("NOT_A_FILE %s\n", zPathname); | |
| 196 | + if( file_access(zFullName, 0)==0 ){ | |
| 197 | + fossil_print("NOT_A_FILE %s\n", zPathname); | |
| 198 | 198 | }else{ |
| 199 | - printf("MISSING %s\n", zPathname); | |
| 199 | + fossil_print("MISSING %s\n", zPathname); | |
| 200 | 200 | } |
| 201 | 201 | }else if( chnged ){ |
| 202 | - printf("EDITED %s\n", zPathname); | |
| 202 | + fossil_print("EDITED %s\n", zPathname); | |
| 203 | 203 | }else if( renamed ){ |
| 204 | - printf("RENAMED %s\n", zPathname); | |
| 204 | + fossil_print("RENAMED %s\n", zPathname); | |
| 205 | 205 | }else{ |
| 206 | - printf("UNCHANGED %s\n", zPathname); | |
| 206 | + fossil_print("UNCHANGED %s\n", zPathname); | |
| 207 | 207 | } |
| 208 | 208 | free(zFullName); |
| 209 | 209 | } |
| 210 | 210 | db_finalize(&q); |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | -/* | |
| 214 | -** Construct and return a string which is an SQL expression that will | |
| 215 | -** be TRUE if value zVal matches any of the GLOB expressions in the list | |
| 216 | -** zGlobList. For example: | |
| 217 | -** | |
| 218 | -** zVal: "x" | |
| 219 | -** zGlobList: "*.o,*.obj" | |
| 220 | -** | |
| 221 | -** Result: "(x GLOB '*.o' OR x GLOB '*.obj')" | |
| 222 | -** | |
| 223 | -** Each element of the GLOB list may optionally be enclosed in either '...' | |
| 224 | -** or "...". This allows commas in the expression. Whitespace at the | |
| 225 | -** beginning and end of each GLOB pattern is ignored, except when enclosed | |
| 226 | -** within '...' or "...". | |
| 227 | -** | |
| 228 | -** This routine makes no effort to free the memory space it uses. | |
| 229 | -*/ | |
| 230 | -char *glob_expr(const char *zVal, const char *zGlobList){ | |
| 231 | - Blob expr; | |
| 232 | - char *zSep = "("; | |
| 233 | - int nTerm = 0; | |
| 234 | - int i; | |
| 235 | - int cTerm; | |
| 236 | - | |
| 237 | - if( zGlobList==0 || zGlobList[0]==0 ) return "0"; | |
| 238 | - blob_zero(&expr); | |
| 239 | - while( zGlobList[0] ){ | |
| 240 | - while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++; | |
| 241 | - if( zGlobList[0]==0 ) break; | |
| 242 | - if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){ | |
| 243 | - cTerm = zGlobList[0]; | |
| 244 | - zGlobList++; | |
| 245 | - }else{ | |
| 246 | - cTerm = ','; | |
| 247 | - } | |
| 248 | - for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){} | |
| 249 | - if( cTerm==',' ){ | |
| 250 | - while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; } | |
| 251 | - } | |
| 252 | - blob_appendf(&expr, "%s%s GLOB '%.*q'", zSep, zVal, i, zGlobList); | |
| 253 | - zSep = " OR "; | |
| 254 | - if( cTerm!=',' && zGlobList[i] ) i++; | |
| 255 | - zGlobList += i; | |
| 256 | - if( zGlobList[0] ) zGlobList++; | |
| 257 | - nTerm++; | |
| 258 | - } | |
| 259 | - if( nTerm ){ | |
| 260 | - blob_appendf(&expr, ")"); | |
| 261 | - return blob_str(&expr); | |
| 262 | - }else{ | |
| 263 | - return "0"; | |
| 264 | - } | |
| 265 | -} | |
| 266 | - | |
| 267 | 213 | /* |
| 268 | 214 | ** COMMAND: extras |
| 269 | 215 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 270 | 216 | ** |
| 271 | 217 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | ||
| 288 | 234 | Stmt q; |
| 289 | 235 | int n; |
| 290 | 236 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 291 | 237 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 292 | 238 | int outputManifest; |
| 239 | + Glob *pIgnore; | |
| 293 | 240 | |
| 294 | 241 | db_must_be_within_tree(); |
| 295 | 242 | outputManifest = db_get_boolean("manifest",0); |
| 296 | 243 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 297 | 244 | n = strlen(g.zLocalRoot); |
| 298 | 245 | blob_init(&path, g.zLocalRoot, n-1); |
| 299 | 246 | if( zIgnoreFlag==0 ){ |
| 300 | 247 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 301 | 248 | } |
| 302 | - vfile_scan(0, &path, blob_size(&path), allFlag); | |
| 249 | + pIgnore = glob_create(zIgnoreFlag); | |
| 250 | + vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 251 | + glob_free(pIgnore); | |
| 303 | 252 | db_prepare(&q, |
| 304 | 253 | "SELECT x FROM sfile" |
| 305 | 254 | " WHERE x NOT IN (%s)" |
| 306 | - " AND NOT %s" | |
| 307 | 255 | " ORDER BY 1", |
| 308 | - fossil_all_reserved_names(), | |
| 309 | - glob_expr("x", zIgnoreFlag) | |
| 256 | + fossil_all_reserved_names() | |
| 310 | 257 | ); |
| 311 | 258 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 312 | 259 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 313 | 260 | } |
| 314 | 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 315 | - printf("%s\n", db_column_text(&q, 0)); | |
| 262 | + fossil_print("%s\n", db_column_text(&q, 0)); | |
| 316 | 263 | } |
| 317 | 264 | db_finalize(&q); |
| 318 | 265 | } |
| 319 | 266 | |
| 320 | 267 | /* |
| @@ -348,10 +295,12 @@ | ||
| 348 | 295 | int dotfilesFlag; |
| 349 | 296 | const char *zIgnoreFlag; |
| 350 | 297 | Blob path, repo; |
| 351 | 298 | Stmt q; |
| 352 | 299 | int n; |
| 300 | + Glob *pIgnore; | |
| 301 | + | |
| 353 | 302 | allFlag = find_option("force","f",0)!=0; |
| 354 | 303 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 355 | 304 | zIgnoreFlag = find_option("ignore",0,1); |
| 356 | 305 | db_must_be_within_tree(); |
| 357 | 306 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | ||
| 358 | 307 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 359 | 308 | } |
| 360 | 309 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 361 | 310 | n = strlen(g.zLocalRoot); |
| 362 | 311 | blob_init(&path, g.zLocalRoot, n-1); |
| 363 | - vfile_scan(0, &path, blob_size(&path), dotfilesFlag); | |
| 312 | + pIgnore = glob_create(zIgnoreFlag); | |
| 313 | + vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); | |
| 314 | + glob_free(pIgnore); | |
| 364 | 315 | db_prepare(&q, |
| 365 | 316 | "SELECT %Q || x FROM sfile" |
| 366 | - " WHERE x NOT IN (%s) AND NOT %s" | |
| 317 | + " WHERE x NOT IN (%s)" | |
| 367 | 318 | " ORDER BY 1", |
| 368 | - g.zLocalRoot, fossil_all_reserved_names(), glob_expr("x",zIgnoreFlag) | |
| 319 | + g.zLocalRoot, fossil_all_reserved_names() | |
| 369 | 320 | ); |
| 370 | 321 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 371 | 322 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 372 | 323 | } |
| 373 | 324 | while( db_step(&q)==SQLITE_ROW ){ |
| 374 | 325 | if( allFlag ){ |
| 375 | - unlink(db_column_text(&q, 0)); | |
| 326 | + file_delete(db_column_text(&q, 0)); | |
| 376 | 327 | }else{ |
| 377 | 328 | Blob ans; |
| 378 | 329 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 379 | 330 | db_column_text(&q, 0)); |
| 380 | 331 | blob_zero(&ans); |
| 381 | 332 | prompt_user(prompt, &ans); |
| 382 | 333 | if( blob_str(&ans)[0]=='y' ){ |
| 383 | - unlink(db_column_text(&q, 0)); | |
| 334 | + file_delete(db_column_text(&q, 0)); | |
| 384 | 335 | } |
| 385 | 336 | } |
| 386 | 337 | } |
| 387 | 338 | db_finalize(&q); |
| 388 | 339 | } |
| @@ -463,26 +414,31 @@ | ||
| 463 | 414 | blob_add_cr(&text); |
| 464 | 415 | #endif |
| 465 | 416 | blob_write_to_file(&text, zFile); |
| 466 | 417 | if( zEditor ){ |
| 467 | 418 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 468 | - printf("%s\n", zCmd); | |
| 419 | + fossil_print("%s\n", zCmd); | |
| 469 | 420 | if( fossil_system(zCmd) ){ |
| 470 | 421 | fossil_panic("editor aborted"); |
| 471 | 422 | } |
| 472 | 423 | blob_reset(&text); |
| 473 | 424 | blob_read_from_file(&text, zFile); |
| 474 | 425 | }else{ |
| 475 | 426 | char zIn[300]; |
| 476 | 427 | blob_reset(&text); |
| 477 | 428 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 478 | - if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ) break; | |
| 429 | + char *zUtf8 = fossil_mbcs_to_utf8(zIn); | |
| 430 | + if( zUtf8[0]=='.' && (zUtf8[1]==0 || zUtf8[1]=='\r' || zUtf8[1]=='\n') ){ | |
| 431 | + fossil_mbcs_free(zUtf8); | |
| 432 | + break; | |
| 433 | + } | |
| 479 | 434 | blob_append(&text, zIn, -1); |
| 435 | + fossil_mbcs_free(zUtf8); | |
| 480 | 436 | } |
| 481 | 437 | } |
| 482 | 438 | blob_remove_cr(&text); |
| 483 | - unlink(zFile); | |
| 439 | + file_delete(zFile); | |
| 484 | 440 | free(zFile); |
| 485 | 441 | blob_zero(pComment); |
| 486 | 442 | while( blob_line(&text, &line) ){ |
| 487 | 443 | int i, n; |
| 488 | 444 | char *z; |
| @@ -534,28 +490,10 @@ | ||
| 534 | 490 | } |
| 535 | 491 | g.aCommitFile[ii-2] = 0; |
| 536 | 492 | } |
| 537 | 493 | } |
| 538 | 494 | |
| 539 | -/* | |
| 540 | -** Return true if the check-in with RID=rid is a leaf. | |
| 541 | -** A leaf has no children in the same branch. | |
| 542 | -*/ | |
| 543 | -int is_a_leaf(int rid){ | |
| 544 | - int rc; | |
| 545 | - static const char zSql[] = | |
| 546 | - @ SELECT 1 FROM plink | |
| 547 | - @ WHERE pid=%d | |
| 548 | - @ AND coalesce((SELECT value FROM tagxref | |
| 549 | - @ WHERE tagid=%d AND rid=plink.pid), 'trunk') | |
| 550 | - @ =coalesce((SELECT value FROM tagxref | |
| 551 | - @ WHERE tagid=%d AND rid=plink.cid), 'trunk') | |
| 552 | - ; | |
| 553 | - rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); | |
| 554 | - return rc==0; | |
| 555 | -} | |
| 556 | - | |
| 557 | 495 | /* |
| 558 | 496 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 559 | 497 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 560 | 498 | */ |
| 561 | 499 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | ||
| 795 | 733 | } |
| 796 | 734 | if( nCrNl ){ |
| 797 | 735 | char c; |
| 798 | 736 | file_relative_name(zFilename, &fname); |
| 799 | 737 | blob_zero(&ans); |
| 800 | - zMsg = mprintf("%s contains CR/NL line endings; commit anyhow (y/N/a)?", | |
| 801 | - blob_str(&fname)); | |
| 738 | + zMsg = mprintf( | |
| 739 | + "%s contains CR/NL line endings; commit anyhow (yes/no/all)?", | |
| 740 | + blob_str(&fname)); | |
| 802 | 741 | prompt_user(zMsg, &ans); |
| 803 | 742 | fossil_free(zMsg); |
| 804 | 743 | c = blob_str(&ans)[0]; |
| 805 | 744 | if( c=='a' ){ |
| 806 | 745 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | ||
| 1179 | 1118 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1180 | 1119 | manifest_crosslink(nvid, &manifest); |
| 1181 | 1120 | assert( blob_is_reset(&manifest) ); |
| 1182 | 1121 | content_deltify(vid, nvid, 0); |
| 1183 | 1122 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1184 | - printf("New_Version: %s\n", zUuid); | |
| 1123 | + fossil_print("New_Version: %s\n", zUuid); | |
| 1185 | 1124 | if( outputManifest ){ |
| 1186 | 1125 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1187 | 1126 | blob_zero(&muuid); |
| 1188 | 1127 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1189 | 1128 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | ||
| 1248 | 1187 | |
| 1249 | 1188 | if( !g.markPrivate ){ |
| 1250 | 1189 | autosync(AUTOSYNC_PUSH); |
| 1251 | 1190 | } |
| 1252 | 1191 | if( count_nonbranch_children(vid)>1 ){ |
| 1253 | - printf("**** warning: a fork has occurred *****\n"); | |
| 1192 | + fossil_print("**** warning: a fork has occurred *****\n"); | |
| 1254 | 1193 | } |
| 1255 | 1194 | } |
| 1256 | 1195 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | if( isDeleted ){ |
| 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | if( access(zFullName, 0)==0 ){ |
| 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | if( missingIsFatal ){ |
| 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | nErr++; |
| 64 | } |
| @@ -142,13 +142,13 @@ | |
| 142 | */ |
| 143 | void status_cmd(void){ |
| 144 | int vid; |
| 145 | db_must_be_within_tree(); |
| 146 | /* 012345678901234 */ |
| 147 | printf("repository: %s\n", db_lget("repository","")); |
| 148 | printf("local-root: %s\n", g.zLocalRoot); |
| 149 | printf("server-code: %s\n", db_get("server-code", "")); |
| 150 | vid = db_lget_int("checkout", 0); |
| 151 | if( vid ){ |
| 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | } |
| 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | |
| 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | int chnged = db_column_int(&q,3); |
| 187 | int renamed = db_column_int(&q,4); |
| 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | if( isBrief ){ |
| 190 | printf("%s\n", zPathname); |
| 191 | }else if( isNew ){ |
| 192 | printf("ADDED %s\n", zPathname); |
| 193 | }else if( isDeleted ){ |
| 194 | printf("DELETED %s\n", zPathname); |
| 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | if( access(zFullName, 0)==0 ){ |
| 197 | printf("NOT_A_FILE %s\n", zPathname); |
| 198 | }else{ |
| 199 | printf("MISSING %s\n", zPathname); |
| 200 | } |
| 201 | }else if( chnged ){ |
| 202 | printf("EDITED %s\n", zPathname); |
| 203 | }else if( renamed ){ |
| 204 | printf("RENAMED %s\n", zPathname); |
| 205 | }else{ |
| 206 | printf("UNCHANGED %s\n", zPathname); |
| 207 | } |
| 208 | free(zFullName); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** Construct and return a string which is an SQL expression that will |
| 215 | ** be TRUE if value zVal matches any of the GLOB expressions in the list |
| 216 | ** zGlobList. For example: |
| 217 | ** |
| 218 | ** zVal: "x" |
| 219 | ** zGlobList: "*.o,*.obj" |
| 220 | ** |
| 221 | ** Result: "(x GLOB '*.o' OR x GLOB '*.obj')" |
| 222 | ** |
| 223 | ** Each element of the GLOB list may optionally be enclosed in either '...' |
| 224 | ** or "...". This allows commas in the expression. Whitespace at the |
| 225 | ** beginning and end of each GLOB pattern is ignored, except when enclosed |
| 226 | ** within '...' or "...". |
| 227 | ** |
| 228 | ** This routine makes no effort to free the memory space it uses. |
| 229 | */ |
| 230 | char *glob_expr(const char *zVal, const char *zGlobList){ |
| 231 | Blob expr; |
| 232 | char *zSep = "("; |
| 233 | int nTerm = 0; |
| 234 | int i; |
| 235 | int cTerm; |
| 236 | |
| 237 | if( zGlobList==0 || zGlobList[0]==0 ) return "0"; |
| 238 | blob_zero(&expr); |
| 239 | while( zGlobList[0] ){ |
| 240 | while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++; |
| 241 | if( zGlobList[0]==0 ) break; |
| 242 | if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){ |
| 243 | cTerm = zGlobList[0]; |
| 244 | zGlobList++; |
| 245 | }else{ |
| 246 | cTerm = ','; |
| 247 | } |
| 248 | for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){} |
| 249 | if( cTerm==',' ){ |
| 250 | while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; } |
| 251 | } |
| 252 | blob_appendf(&expr, "%s%s GLOB '%.*q'", zSep, zVal, i, zGlobList); |
| 253 | zSep = " OR "; |
| 254 | if( cTerm!=',' && zGlobList[i] ) i++; |
| 255 | zGlobList += i; |
| 256 | if( zGlobList[0] ) zGlobList++; |
| 257 | nTerm++; |
| 258 | } |
| 259 | if( nTerm ){ |
| 260 | blob_appendf(&expr, ")"); |
| 261 | return blob_str(&expr); |
| 262 | }else{ |
| 263 | return "0"; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | ** COMMAND: extras |
| 269 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 270 | ** |
| 271 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | |
| 288 | Stmt q; |
| 289 | int n; |
| 290 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 291 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 292 | int outputManifest; |
| 293 | |
| 294 | db_must_be_within_tree(); |
| 295 | outputManifest = db_get_boolean("manifest",0); |
| 296 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 297 | n = strlen(g.zLocalRoot); |
| 298 | blob_init(&path, g.zLocalRoot, n-1); |
| 299 | if( zIgnoreFlag==0 ){ |
| 300 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 301 | } |
| 302 | vfile_scan(0, &path, blob_size(&path), allFlag); |
| 303 | db_prepare(&q, |
| 304 | "SELECT x FROM sfile" |
| 305 | " WHERE x NOT IN (%s)" |
| 306 | " AND NOT %s" |
| 307 | " ORDER BY 1", |
| 308 | fossil_all_reserved_names(), |
| 309 | glob_expr("x", zIgnoreFlag) |
| 310 | ); |
| 311 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 312 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 313 | } |
| 314 | while( db_step(&q)==SQLITE_ROW ){ |
| 315 | printf("%s\n", db_column_text(&q, 0)); |
| 316 | } |
| 317 | db_finalize(&q); |
| 318 | } |
| 319 | |
| 320 | /* |
| @@ -348,10 +295,12 @@ | |
| 348 | int dotfilesFlag; |
| 349 | const char *zIgnoreFlag; |
| 350 | Blob path, repo; |
| 351 | Stmt q; |
| 352 | int n; |
| 353 | allFlag = find_option("force","f",0)!=0; |
| 354 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 355 | zIgnoreFlag = find_option("ignore",0,1); |
| 356 | db_must_be_within_tree(); |
| 357 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | |
| 358 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 359 | } |
| 360 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 361 | n = strlen(g.zLocalRoot); |
| 362 | blob_init(&path, g.zLocalRoot, n-1); |
| 363 | vfile_scan(0, &path, blob_size(&path), dotfilesFlag); |
| 364 | db_prepare(&q, |
| 365 | "SELECT %Q || x FROM sfile" |
| 366 | " WHERE x NOT IN (%s) AND NOT %s" |
| 367 | " ORDER BY 1", |
| 368 | g.zLocalRoot, fossil_all_reserved_names(), glob_expr("x",zIgnoreFlag) |
| 369 | ); |
| 370 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 371 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 372 | } |
| 373 | while( db_step(&q)==SQLITE_ROW ){ |
| 374 | if( allFlag ){ |
| 375 | unlink(db_column_text(&q, 0)); |
| 376 | }else{ |
| 377 | Blob ans; |
| 378 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 379 | db_column_text(&q, 0)); |
| 380 | blob_zero(&ans); |
| 381 | prompt_user(prompt, &ans); |
| 382 | if( blob_str(&ans)[0]=='y' ){ |
| 383 | unlink(db_column_text(&q, 0)); |
| 384 | } |
| 385 | } |
| 386 | } |
| 387 | db_finalize(&q); |
| 388 | } |
| @@ -463,26 +414,31 @@ | |
| 463 | blob_add_cr(&text); |
| 464 | #endif |
| 465 | blob_write_to_file(&text, zFile); |
| 466 | if( zEditor ){ |
| 467 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 468 | printf("%s\n", zCmd); |
| 469 | if( fossil_system(zCmd) ){ |
| 470 | fossil_panic("editor aborted"); |
| 471 | } |
| 472 | blob_reset(&text); |
| 473 | blob_read_from_file(&text, zFile); |
| 474 | }else{ |
| 475 | char zIn[300]; |
| 476 | blob_reset(&text); |
| 477 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 478 | if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ) break; |
| 479 | blob_append(&text, zIn, -1); |
| 480 | } |
| 481 | } |
| 482 | blob_remove_cr(&text); |
| 483 | unlink(zFile); |
| 484 | free(zFile); |
| 485 | blob_zero(pComment); |
| 486 | while( blob_line(&text, &line) ){ |
| 487 | int i, n; |
| 488 | char *z; |
| @@ -534,28 +490,10 @@ | |
| 534 | } |
| 535 | g.aCommitFile[ii-2] = 0; |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | /* |
| 540 | ** Return true if the check-in with RID=rid is a leaf. |
| 541 | ** A leaf has no children in the same branch. |
| 542 | */ |
| 543 | int is_a_leaf(int rid){ |
| 544 | int rc; |
| 545 | static const char zSql[] = |
| 546 | @ SELECT 1 FROM plink |
| 547 | @ WHERE pid=%d |
| 548 | @ AND coalesce((SELECT value FROM tagxref |
| 549 | @ WHERE tagid=%d AND rid=plink.pid), 'trunk') |
| 550 | @ =coalesce((SELECT value FROM tagxref |
| 551 | @ WHERE tagid=%d AND rid=plink.cid), 'trunk') |
| 552 | ; |
| 553 | rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); |
| 554 | return rc==0; |
| 555 | } |
| 556 | |
| 557 | /* |
| 558 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 559 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 560 | */ |
| 561 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | |
| 795 | } |
| 796 | if( nCrNl ){ |
| 797 | char c; |
| 798 | file_relative_name(zFilename, &fname); |
| 799 | blob_zero(&ans); |
| 800 | zMsg = mprintf("%s contains CR/NL line endings; commit anyhow (y/N/a)?", |
| 801 | blob_str(&fname)); |
| 802 | prompt_user(zMsg, &ans); |
| 803 | fossil_free(zMsg); |
| 804 | c = blob_str(&ans)[0]; |
| 805 | if( c=='a' ){ |
| 806 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | |
| 1179 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1180 | manifest_crosslink(nvid, &manifest); |
| 1181 | assert( blob_is_reset(&manifest) ); |
| 1182 | content_deltify(vid, nvid, 0); |
| 1183 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1184 | printf("New_Version: %s\n", zUuid); |
| 1185 | if( outputManifest ){ |
| 1186 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1187 | blob_zero(&muuid); |
| 1188 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1189 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | |
| 1248 | |
| 1249 | if( !g.markPrivate ){ |
| 1250 | autosync(AUTOSYNC_PUSH); |
| 1251 | } |
| 1252 | if( count_nonbranch_children(vid)>1 ){ |
| 1253 | printf("**** warning: a fork has occurred *****\n"); |
| 1254 | } |
| 1255 | } |
| 1256 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | if( isDeleted ){ |
| 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | if( file_access(zFullName, 0)==0 ){ |
| 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | if( missingIsFatal ){ |
| 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | nErr++; |
| 64 | } |
| @@ -142,13 +142,13 @@ | |
| 142 | */ |
| 143 | void status_cmd(void){ |
| 144 | int vid; |
| 145 | db_must_be_within_tree(); |
| 146 | /* 012345678901234 */ |
| 147 | fossil_print("repository: %s\n", db_lget("repository","")); |
| 148 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 149 | fossil_print("server-code: %s\n", db_get("server-code", "")); |
| 150 | vid = db_lget_int("checkout", 0); |
| 151 | if( vid ){ |
| 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | } |
| 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | |
| 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | int chnged = db_column_int(&q,3); |
| 187 | int renamed = db_column_int(&q,4); |
| 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | if( isBrief ){ |
| 190 | fossil_print("%s\n", zPathname); |
| 191 | }else if( isNew ){ |
| 192 | fossil_print("ADDED %s\n", zPathname); |
| 193 | }else if( isDeleted ){ |
| 194 | fossil_print("DELETED %s\n", zPathname); |
| 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | if( file_access(zFullName, 0)==0 ){ |
| 197 | fossil_print("NOT_A_FILE %s\n", zPathname); |
| 198 | }else{ |
| 199 | fossil_print("MISSING %s\n", zPathname); |
| 200 | } |
| 201 | }else if( chnged ){ |
| 202 | fossil_print("EDITED %s\n", zPathname); |
| 203 | }else if( renamed ){ |
| 204 | fossil_print("RENAMED %s\n", zPathname); |
| 205 | }else{ |
| 206 | fossil_print("UNCHANGED %s\n", zPathname); |
| 207 | } |
| 208 | free(zFullName); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** COMMAND: extras |
| 215 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 216 | ** |
| 217 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | |
| 234 | Stmt q; |
| 235 | int n; |
| 236 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 237 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 238 | int outputManifest; |
| 239 | Glob *pIgnore; |
| 240 | |
| 241 | db_must_be_within_tree(); |
| 242 | outputManifest = db_get_boolean("manifest",0); |
| 243 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 244 | n = strlen(g.zLocalRoot); |
| 245 | blob_init(&path, g.zLocalRoot, n-1); |
| 246 | if( zIgnoreFlag==0 ){ |
| 247 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 248 | } |
| 249 | pIgnore = glob_create(zIgnoreFlag); |
| 250 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 251 | glob_free(pIgnore); |
| 252 | db_prepare(&q, |
| 253 | "SELECT x FROM sfile" |
| 254 | " WHERE x NOT IN (%s)" |
| 255 | " ORDER BY 1", |
| 256 | fossil_all_reserved_names() |
| 257 | ); |
| 258 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 259 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 260 | } |
| 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 262 | fossil_print("%s\n", db_column_text(&q, 0)); |
| 263 | } |
| 264 | db_finalize(&q); |
| 265 | } |
| 266 | |
| 267 | /* |
| @@ -348,10 +295,12 @@ | |
| 295 | int dotfilesFlag; |
| 296 | const char *zIgnoreFlag; |
| 297 | Blob path, repo; |
| 298 | Stmt q; |
| 299 | int n; |
| 300 | Glob *pIgnore; |
| 301 | |
| 302 | allFlag = find_option("force","f",0)!=0; |
| 303 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 304 | zIgnoreFlag = find_option("ignore",0,1); |
| 305 | db_must_be_within_tree(); |
| 306 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | |
| 307 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 308 | } |
| 309 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 310 | n = strlen(g.zLocalRoot); |
| 311 | blob_init(&path, g.zLocalRoot, n-1); |
| 312 | pIgnore = glob_create(zIgnoreFlag); |
| 313 | vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); |
| 314 | glob_free(pIgnore); |
| 315 | db_prepare(&q, |
| 316 | "SELECT %Q || x FROM sfile" |
| 317 | " WHERE x NOT IN (%s)" |
| 318 | " ORDER BY 1", |
| 319 | g.zLocalRoot, fossil_all_reserved_names() |
| 320 | ); |
| 321 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 322 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 323 | } |
| 324 | while( db_step(&q)==SQLITE_ROW ){ |
| 325 | if( allFlag ){ |
| 326 | file_delete(db_column_text(&q, 0)); |
| 327 | }else{ |
| 328 | Blob ans; |
| 329 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 330 | db_column_text(&q, 0)); |
| 331 | blob_zero(&ans); |
| 332 | prompt_user(prompt, &ans); |
| 333 | if( blob_str(&ans)[0]=='y' ){ |
| 334 | file_delete(db_column_text(&q, 0)); |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | db_finalize(&q); |
| 339 | } |
| @@ -463,26 +414,31 @@ | |
| 414 | blob_add_cr(&text); |
| 415 | #endif |
| 416 | blob_write_to_file(&text, zFile); |
| 417 | if( zEditor ){ |
| 418 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 419 | fossil_print("%s\n", zCmd); |
| 420 | if( fossil_system(zCmd) ){ |
| 421 | fossil_panic("editor aborted"); |
| 422 | } |
| 423 | blob_reset(&text); |
| 424 | blob_read_from_file(&text, zFile); |
| 425 | }else{ |
| 426 | char zIn[300]; |
| 427 | blob_reset(&text); |
| 428 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 429 | char *zUtf8 = fossil_mbcs_to_utf8(zIn); |
| 430 | if( zUtf8[0]=='.' && (zUtf8[1]==0 || zUtf8[1]=='\r' || zUtf8[1]=='\n') ){ |
| 431 | fossil_mbcs_free(zUtf8); |
| 432 | break; |
| 433 | } |
| 434 | blob_append(&text, zIn, -1); |
| 435 | fossil_mbcs_free(zUtf8); |
| 436 | } |
| 437 | } |
| 438 | blob_remove_cr(&text); |
| 439 | file_delete(zFile); |
| 440 | free(zFile); |
| 441 | blob_zero(pComment); |
| 442 | while( blob_line(&text, &line) ){ |
| 443 | int i, n; |
| 444 | char *z; |
| @@ -534,28 +490,10 @@ | |
| 490 | } |
| 491 | g.aCommitFile[ii-2] = 0; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | /* |
| 496 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 497 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 498 | */ |
| 499 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | |
| 733 | } |
| 734 | if( nCrNl ){ |
| 735 | char c; |
| 736 | file_relative_name(zFilename, &fname); |
| 737 | blob_zero(&ans); |
| 738 | zMsg = mprintf( |
| 739 | "%s contains CR/NL line endings; commit anyhow (yes/no/all)?", |
| 740 | blob_str(&fname)); |
| 741 | prompt_user(zMsg, &ans); |
| 742 | fossil_free(zMsg); |
| 743 | c = blob_str(&ans)[0]; |
| 744 | if( c=='a' ){ |
| 745 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | |
| 1118 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1119 | manifest_crosslink(nvid, &manifest); |
| 1120 | assert( blob_is_reset(&manifest) ); |
| 1121 | content_deltify(vid, nvid, 0); |
| 1122 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1123 | fossil_print("New_Version: %s\n", zUuid); |
| 1124 | if( outputManifest ){ |
| 1125 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1126 | blob_zero(&muuid); |
| 1127 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1128 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | |
| 1187 | |
| 1188 | if( !g.markPrivate ){ |
| 1189 | autosync(AUTOSYNC_PUSH); |
| 1190 | } |
| 1191 | if( count_nonbranch_children(vid)>1 ){ |
| 1192 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 1193 | } |
| 1194 | } |
| 1195 |
+41
-102
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -54,11 +54,11 @@ | ||
| 54 | 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | 56 | if( isDeleted ){ |
| 57 | 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | - if( access(zFullName, 0)==0 ){ | |
| 59 | + if( file_access(zFullName, 0)==0 ){ | |
| 60 | 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | 61 | if( missingIsFatal ){ |
| 62 | 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | 63 | nErr++; |
| 64 | 64 | } |
| @@ -142,13 +142,13 @@ | ||
| 142 | 142 | */ |
| 143 | 143 | void status_cmd(void){ |
| 144 | 144 | int vid; |
| 145 | 145 | db_must_be_within_tree(); |
| 146 | 146 | /* 012345678901234 */ |
| 147 | - printf("repository: %s\n", db_lget("repository","")); | |
| 148 | - printf("local-root: %s\n", g.zLocalRoot); | |
| 149 | - printf("server-code: %s\n", db_get("server-code", "")); | |
| 147 | + fossil_print("repository: %s\n", db_lget("repository","")); | |
| 148 | + fossil_print("local-root: %s\n", g.zLocalRoot); | |
| 149 | + fossil_print("server-code: %s\n", db_get("server-code", "")); | |
| 150 | 150 | vid = db_lget_int("checkout", 0); |
| 151 | 151 | if( vid ){ |
| 152 | 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | 153 | } |
| 154 | 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | ||
| 185 | 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | 186 | int chnged = db_column_int(&q,3); |
| 187 | 187 | int renamed = db_column_int(&q,4); |
| 188 | 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | 189 | if( isBrief ){ |
| 190 | - printf("%s\n", zPathname); | |
| 190 | + fossil_print("%s\n", zPathname); | |
| 191 | 191 | }else if( isNew ){ |
| 192 | - printf("ADDED %s\n", zPathname); | |
| 192 | + fossil_print("ADDED %s\n", zPathname); | |
| 193 | 193 | }else if( isDeleted ){ |
| 194 | - printf("DELETED %s\n", zPathname); | |
| 194 | + fossil_print("DELETED %s\n", zPathname); | |
| 195 | 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | - if( access(zFullName, 0)==0 ){ | |
| 197 | - printf("NOT_A_FILE %s\n", zPathname); | |
| 196 | + if( file_access(zFullName, 0)==0 ){ | |
| 197 | + fossil_print("NOT_A_FILE %s\n", zPathname); | |
| 198 | 198 | }else{ |
| 199 | - printf("MISSING %s\n", zPathname); | |
| 199 | + fossil_print("MISSING %s\n", zPathname); | |
| 200 | 200 | } |
| 201 | 201 | }else if( chnged ){ |
| 202 | - printf("EDITED %s\n", zPathname); | |
| 202 | + fossil_print("EDITED %s\n", zPathname); | |
| 203 | 203 | }else if( renamed ){ |
| 204 | - printf("RENAMED %s\n", zPathname); | |
| 204 | + fossil_print("RENAMED %s\n", zPathname); | |
| 205 | 205 | }else{ |
| 206 | - printf("UNCHANGED %s\n", zPathname); | |
| 206 | + fossil_print("UNCHANGED %s\n", zPathname); | |
| 207 | 207 | } |
| 208 | 208 | free(zFullName); |
| 209 | 209 | } |
| 210 | 210 | db_finalize(&q); |
| 211 | 211 | } |
| 212 | 212 | |
| 213 | -/* | |
| 214 | -** Construct and return a string which is an SQL expression that will | |
| 215 | -** be TRUE if value zVal matches any of the GLOB expressions in the list | |
| 216 | -** zGlobList. For example: | |
| 217 | -** | |
| 218 | -** zVal: "x" | |
| 219 | -** zGlobList: "*.o,*.obj" | |
| 220 | -** | |
| 221 | -** Result: "(x GLOB '*.o' OR x GLOB '*.obj')" | |
| 222 | -** | |
| 223 | -** Each element of the GLOB list may optionally be enclosed in either '...' | |
| 224 | -** or "...". This allows commas in the expression. Whitespace at the | |
| 225 | -** beginning and end of each GLOB pattern is ignored, except when enclosed | |
| 226 | -** within '...' or "...". | |
| 227 | -** | |
| 228 | -** This routine makes no effort to free the memory space it uses. | |
| 229 | -*/ | |
| 230 | -char *glob_expr(const char *zVal, const char *zGlobList){ | |
| 231 | - Blob expr; | |
| 232 | - char *zSep = "("; | |
| 233 | - int nTerm = 0; | |
| 234 | - int i; | |
| 235 | - int cTerm; | |
| 236 | - | |
| 237 | - if( zGlobList==0 || zGlobList[0]==0 ) return "0"; | |
| 238 | - blob_zero(&expr); | |
| 239 | - while( zGlobList[0] ){ | |
| 240 | - while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++; | |
| 241 | - if( zGlobList[0]==0 ) break; | |
| 242 | - if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){ | |
| 243 | - cTerm = zGlobList[0]; | |
| 244 | - zGlobList++; | |
| 245 | - }else{ | |
| 246 | - cTerm = ','; | |
| 247 | - } | |
| 248 | - for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){} | |
| 249 | - if( cTerm==',' ){ | |
| 250 | - while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; } | |
| 251 | - } | |
| 252 | - blob_appendf(&expr, "%s%s GLOB '%.*q'", zSep, zVal, i, zGlobList); | |
| 253 | - zSep = " OR "; | |
| 254 | - if( cTerm!=',' && zGlobList[i] ) i++; | |
| 255 | - zGlobList += i; | |
| 256 | - if( zGlobList[0] ) zGlobList++; | |
| 257 | - nTerm++; | |
| 258 | - } | |
| 259 | - if( nTerm ){ | |
| 260 | - blob_appendf(&expr, ")"); | |
| 261 | - return blob_str(&expr); | |
| 262 | - }else{ | |
| 263 | - return "0"; | |
| 264 | - } | |
| 265 | -} | |
| 266 | - | |
| 267 | 213 | /* |
| 268 | 214 | ** COMMAND: extras |
| 269 | 215 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 270 | 216 | ** |
| 271 | 217 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | ||
| 288 | 234 | Stmt q; |
| 289 | 235 | int n; |
| 290 | 236 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 291 | 237 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 292 | 238 | int outputManifest; |
| 239 | + Glob *pIgnore; | |
| 293 | 240 | |
| 294 | 241 | db_must_be_within_tree(); |
| 295 | 242 | outputManifest = db_get_boolean("manifest",0); |
| 296 | 243 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 297 | 244 | n = strlen(g.zLocalRoot); |
| 298 | 245 | blob_init(&path, g.zLocalRoot, n-1); |
| 299 | 246 | if( zIgnoreFlag==0 ){ |
| 300 | 247 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 301 | 248 | } |
| 302 | - vfile_scan(0, &path, blob_size(&path), allFlag); | |
| 249 | + pIgnore = glob_create(zIgnoreFlag); | |
| 250 | + vfile_scan(&path, blob_size(&path), allFlag, pIgnore); | |
| 251 | + glob_free(pIgnore); | |
| 303 | 252 | db_prepare(&q, |
| 304 | 253 | "SELECT x FROM sfile" |
| 305 | 254 | " WHERE x NOT IN (%s)" |
| 306 | - " AND NOT %s" | |
| 307 | 255 | " ORDER BY 1", |
| 308 | - fossil_all_reserved_names(), | |
| 309 | - glob_expr("x", zIgnoreFlag) | |
| 256 | + fossil_all_reserved_names() | |
| 310 | 257 | ); |
| 311 | 258 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 312 | 259 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 313 | 260 | } |
| 314 | 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 315 | - printf("%s\n", db_column_text(&q, 0)); | |
| 262 | + fossil_print("%s\n", db_column_text(&q, 0)); | |
| 316 | 263 | } |
| 317 | 264 | db_finalize(&q); |
| 318 | 265 | } |
| 319 | 266 | |
| 320 | 267 | /* |
| @@ -348,10 +295,12 @@ | ||
| 348 | 295 | int dotfilesFlag; |
| 349 | 296 | const char *zIgnoreFlag; |
| 350 | 297 | Blob path, repo; |
| 351 | 298 | Stmt q; |
| 352 | 299 | int n; |
| 300 | + Glob *pIgnore; | |
| 301 | + | |
| 353 | 302 | allFlag = find_option("force","f",0)!=0; |
| 354 | 303 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 355 | 304 | zIgnoreFlag = find_option("ignore",0,1); |
| 356 | 305 | db_must_be_within_tree(); |
| 357 | 306 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | ||
| 358 | 307 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 359 | 308 | } |
| 360 | 309 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 361 | 310 | n = strlen(g.zLocalRoot); |
| 362 | 311 | blob_init(&path, g.zLocalRoot, n-1); |
| 363 | - vfile_scan(0, &path, blob_size(&path), dotfilesFlag); | |
| 312 | + pIgnore = glob_create(zIgnoreFlag); | |
| 313 | + vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); | |
| 314 | + glob_free(pIgnore); | |
| 364 | 315 | db_prepare(&q, |
| 365 | 316 | "SELECT %Q || x FROM sfile" |
| 366 | - " WHERE x NOT IN (%s) AND NOT %s" | |
| 317 | + " WHERE x NOT IN (%s)" | |
| 367 | 318 | " ORDER BY 1", |
| 368 | - g.zLocalRoot, fossil_all_reserved_names(), glob_expr("x",zIgnoreFlag) | |
| 319 | + g.zLocalRoot, fossil_all_reserved_names() | |
| 369 | 320 | ); |
| 370 | 321 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 371 | 322 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 372 | 323 | } |
| 373 | 324 | while( db_step(&q)==SQLITE_ROW ){ |
| 374 | 325 | if( allFlag ){ |
| 375 | - unlink(db_column_text(&q, 0)); | |
| 326 | + file_delete(db_column_text(&q, 0)); | |
| 376 | 327 | }else{ |
| 377 | 328 | Blob ans; |
| 378 | 329 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 379 | 330 | db_column_text(&q, 0)); |
| 380 | 331 | blob_zero(&ans); |
| 381 | 332 | prompt_user(prompt, &ans); |
| 382 | 333 | if( blob_str(&ans)[0]=='y' ){ |
| 383 | - unlink(db_column_text(&q, 0)); | |
| 334 | + file_delete(db_column_text(&q, 0)); | |
| 384 | 335 | } |
| 385 | 336 | } |
| 386 | 337 | } |
| 387 | 338 | db_finalize(&q); |
| 388 | 339 | } |
| @@ -463,26 +414,31 @@ | ||
| 463 | 414 | blob_add_cr(&text); |
| 464 | 415 | #endif |
| 465 | 416 | blob_write_to_file(&text, zFile); |
| 466 | 417 | if( zEditor ){ |
| 467 | 418 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 468 | - printf("%s\n", zCmd); | |
| 419 | + fossil_print("%s\n", zCmd); | |
| 469 | 420 | if( fossil_system(zCmd) ){ |
| 470 | 421 | fossil_panic("editor aborted"); |
| 471 | 422 | } |
| 472 | 423 | blob_reset(&text); |
| 473 | 424 | blob_read_from_file(&text, zFile); |
| 474 | 425 | }else{ |
| 475 | 426 | char zIn[300]; |
| 476 | 427 | blob_reset(&text); |
| 477 | 428 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 478 | - if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ) break; | |
| 429 | + char *zUtf8 = fossil_mbcs_to_utf8(zIn); | |
| 430 | + if( zUtf8[0]=='.' && (zUtf8[1]==0 || zUtf8[1]=='\r' || zUtf8[1]=='\n') ){ | |
| 431 | + fossil_mbcs_free(zUtf8); | |
| 432 | + break; | |
| 433 | + } | |
| 479 | 434 | blob_append(&text, zIn, -1); |
| 435 | + fossil_mbcs_free(zUtf8); | |
| 480 | 436 | } |
| 481 | 437 | } |
| 482 | 438 | blob_remove_cr(&text); |
| 483 | - unlink(zFile); | |
| 439 | + file_delete(zFile); | |
| 484 | 440 | free(zFile); |
| 485 | 441 | blob_zero(pComment); |
| 486 | 442 | while( blob_line(&text, &line) ){ |
| 487 | 443 | int i, n; |
| 488 | 444 | char *z; |
| @@ -534,28 +490,10 @@ | ||
| 534 | 490 | } |
| 535 | 491 | g.aCommitFile[ii-2] = 0; |
| 536 | 492 | } |
| 537 | 493 | } |
| 538 | 494 | |
| 539 | -/* | |
| 540 | -** Return true if the check-in with RID=rid is a leaf. | |
| 541 | -** A leaf has no children in the same branch. | |
| 542 | -*/ | |
| 543 | -int is_a_leaf(int rid){ | |
| 544 | - int rc; | |
| 545 | - static const char zSql[] = | |
| 546 | - @ SELECT 1 FROM plink | |
| 547 | - @ WHERE pid=%d | |
| 548 | - @ AND coalesce((SELECT value FROM tagxref | |
| 549 | - @ WHERE tagid=%d AND rid=plink.pid), 'trunk') | |
| 550 | - @ =coalesce((SELECT value FROM tagxref | |
| 551 | - @ WHERE tagid=%d AND rid=plink.cid), 'trunk') | |
| 552 | - ; | |
| 553 | - rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); | |
| 554 | - return rc==0; | |
| 555 | -} | |
| 556 | - | |
| 557 | 495 | /* |
| 558 | 496 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 559 | 497 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 560 | 498 | */ |
| 561 | 499 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | ||
| 795 | 733 | } |
| 796 | 734 | if( nCrNl ){ |
| 797 | 735 | char c; |
| 798 | 736 | file_relative_name(zFilename, &fname); |
| 799 | 737 | blob_zero(&ans); |
| 800 | - zMsg = mprintf("%s contains CR/NL line endings; commit anyhow (y/N/a)?", | |
| 801 | - blob_str(&fname)); | |
| 738 | + zMsg = mprintf( | |
| 739 | + "%s contains CR/NL line endings; commit anyhow (yes/no/all)?", | |
| 740 | + blob_str(&fname)); | |
| 802 | 741 | prompt_user(zMsg, &ans); |
| 803 | 742 | fossil_free(zMsg); |
| 804 | 743 | c = blob_str(&ans)[0]; |
| 805 | 744 | if( c=='a' ){ |
| 806 | 745 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | ||
| 1179 | 1118 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1180 | 1119 | manifest_crosslink(nvid, &manifest); |
| 1181 | 1120 | assert( blob_is_reset(&manifest) ); |
| 1182 | 1121 | content_deltify(vid, nvid, 0); |
| 1183 | 1122 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1184 | - printf("New_Version: %s\n", zUuid); | |
| 1123 | + fossil_print("New_Version: %s\n", zUuid); | |
| 1185 | 1124 | if( outputManifest ){ |
| 1186 | 1125 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1187 | 1126 | blob_zero(&muuid); |
| 1188 | 1127 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1189 | 1128 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | ||
| 1248 | 1187 | |
| 1249 | 1188 | if( !g.markPrivate ){ |
| 1250 | 1189 | autosync(AUTOSYNC_PUSH); |
| 1251 | 1190 | } |
| 1252 | 1191 | if( count_nonbranch_children(vid)>1 ){ |
| 1253 | - printf("**** warning: a fork has occurred *****\n"); | |
| 1192 | + fossil_print("**** warning: a fork has occurred *****\n"); | |
| 1254 | 1193 | } |
| 1255 | 1194 | } |
| 1256 | 1195 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | if( isDeleted ){ |
| 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | if( access(zFullName, 0)==0 ){ |
| 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | if( missingIsFatal ){ |
| 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | nErr++; |
| 64 | } |
| @@ -142,13 +142,13 @@ | |
| 142 | */ |
| 143 | void status_cmd(void){ |
| 144 | int vid; |
| 145 | db_must_be_within_tree(); |
| 146 | /* 012345678901234 */ |
| 147 | printf("repository: %s\n", db_lget("repository","")); |
| 148 | printf("local-root: %s\n", g.zLocalRoot); |
| 149 | printf("server-code: %s\n", db_get("server-code", "")); |
| 150 | vid = db_lget_int("checkout", 0); |
| 151 | if( vid ){ |
| 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | } |
| 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | |
| 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | int chnged = db_column_int(&q,3); |
| 187 | int renamed = db_column_int(&q,4); |
| 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | if( isBrief ){ |
| 190 | printf("%s\n", zPathname); |
| 191 | }else if( isNew ){ |
| 192 | printf("ADDED %s\n", zPathname); |
| 193 | }else if( isDeleted ){ |
| 194 | printf("DELETED %s\n", zPathname); |
| 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | if( access(zFullName, 0)==0 ){ |
| 197 | printf("NOT_A_FILE %s\n", zPathname); |
| 198 | }else{ |
| 199 | printf("MISSING %s\n", zPathname); |
| 200 | } |
| 201 | }else if( chnged ){ |
| 202 | printf("EDITED %s\n", zPathname); |
| 203 | }else if( renamed ){ |
| 204 | printf("RENAMED %s\n", zPathname); |
| 205 | }else{ |
| 206 | printf("UNCHANGED %s\n", zPathname); |
| 207 | } |
| 208 | free(zFullName); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** Construct and return a string which is an SQL expression that will |
| 215 | ** be TRUE if value zVal matches any of the GLOB expressions in the list |
| 216 | ** zGlobList. For example: |
| 217 | ** |
| 218 | ** zVal: "x" |
| 219 | ** zGlobList: "*.o,*.obj" |
| 220 | ** |
| 221 | ** Result: "(x GLOB '*.o' OR x GLOB '*.obj')" |
| 222 | ** |
| 223 | ** Each element of the GLOB list may optionally be enclosed in either '...' |
| 224 | ** or "...". This allows commas in the expression. Whitespace at the |
| 225 | ** beginning and end of each GLOB pattern is ignored, except when enclosed |
| 226 | ** within '...' or "...". |
| 227 | ** |
| 228 | ** This routine makes no effort to free the memory space it uses. |
| 229 | */ |
| 230 | char *glob_expr(const char *zVal, const char *zGlobList){ |
| 231 | Blob expr; |
| 232 | char *zSep = "("; |
| 233 | int nTerm = 0; |
| 234 | int i; |
| 235 | int cTerm; |
| 236 | |
| 237 | if( zGlobList==0 || zGlobList[0]==0 ) return "0"; |
| 238 | blob_zero(&expr); |
| 239 | while( zGlobList[0] ){ |
| 240 | while( fossil_isspace(zGlobList[0]) || zGlobList[0]==',' ) zGlobList++; |
| 241 | if( zGlobList[0]==0 ) break; |
| 242 | if( zGlobList[0]=='\'' || zGlobList[0]=='"' ){ |
| 243 | cTerm = zGlobList[0]; |
| 244 | zGlobList++; |
| 245 | }else{ |
| 246 | cTerm = ','; |
| 247 | } |
| 248 | for(i=0; zGlobList[i] && zGlobList[i]!=cTerm; i++){} |
| 249 | if( cTerm==',' ){ |
| 250 | while( i>0 && fossil_isspace(zGlobList[i-1]) ){ i--; } |
| 251 | } |
| 252 | blob_appendf(&expr, "%s%s GLOB '%.*q'", zSep, zVal, i, zGlobList); |
| 253 | zSep = " OR "; |
| 254 | if( cTerm!=',' && zGlobList[i] ) i++; |
| 255 | zGlobList += i; |
| 256 | if( zGlobList[0] ) zGlobList++; |
| 257 | nTerm++; |
| 258 | } |
| 259 | if( nTerm ){ |
| 260 | blob_appendf(&expr, ")"); |
| 261 | return blob_str(&expr); |
| 262 | }else{ |
| 263 | return "0"; |
| 264 | } |
| 265 | } |
| 266 | |
| 267 | /* |
| 268 | ** COMMAND: extras |
| 269 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 270 | ** |
| 271 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | |
| 288 | Stmt q; |
| 289 | int n; |
| 290 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 291 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 292 | int outputManifest; |
| 293 | |
| 294 | db_must_be_within_tree(); |
| 295 | outputManifest = db_get_boolean("manifest",0); |
| 296 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 297 | n = strlen(g.zLocalRoot); |
| 298 | blob_init(&path, g.zLocalRoot, n-1); |
| 299 | if( zIgnoreFlag==0 ){ |
| 300 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 301 | } |
| 302 | vfile_scan(0, &path, blob_size(&path), allFlag); |
| 303 | db_prepare(&q, |
| 304 | "SELECT x FROM sfile" |
| 305 | " WHERE x NOT IN (%s)" |
| 306 | " AND NOT %s" |
| 307 | " ORDER BY 1", |
| 308 | fossil_all_reserved_names(), |
| 309 | glob_expr("x", zIgnoreFlag) |
| 310 | ); |
| 311 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 312 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 313 | } |
| 314 | while( db_step(&q)==SQLITE_ROW ){ |
| 315 | printf("%s\n", db_column_text(&q, 0)); |
| 316 | } |
| 317 | db_finalize(&q); |
| 318 | } |
| 319 | |
| 320 | /* |
| @@ -348,10 +295,12 @@ | |
| 348 | int dotfilesFlag; |
| 349 | const char *zIgnoreFlag; |
| 350 | Blob path, repo; |
| 351 | Stmt q; |
| 352 | int n; |
| 353 | allFlag = find_option("force","f",0)!=0; |
| 354 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 355 | zIgnoreFlag = find_option("ignore",0,1); |
| 356 | db_must_be_within_tree(); |
| 357 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | |
| 358 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 359 | } |
| 360 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 361 | n = strlen(g.zLocalRoot); |
| 362 | blob_init(&path, g.zLocalRoot, n-1); |
| 363 | vfile_scan(0, &path, blob_size(&path), dotfilesFlag); |
| 364 | db_prepare(&q, |
| 365 | "SELECT %Q || x FROM sfile" |
| 366 | " WHERE x NOT IN (%s) AND NOT %s" |
| 367 | " ORDER BY 1", |
| 368 | g.zLocalRoot, fossil_all_reserved_names(), glob_expr("x",zIgnoreFlag) |
| 369 | ); |
| 370 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 371 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 372 | } |
| 373 | while( db_step(&q)==SQLITE_ROW ){ |
| 374 | if( allFlag ){ |
| 375 | unlink(db_column_text(&q, 0)); |
| 376 | }else{ |
| 377 | Blob ans; |
| 378 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 379 | db_column_text(&q, 0)); |
| 380 | blob_zero(&ans); |
| 381 | prompt_user(prompt, &ans); |
| 382 | if( blob_str(&ans)[0]=='y' ){ |
| 383 | unlink(db_column_text(&q, 0)); |
| 384 | } |
| 385 | } |
| 386 | } |
| 387 | db_finalize(&q); |
| 388 | } |
| @@ -463,26 +414,31 @@ | |
| 463 | blob_add_cr(&text); |
| 464 | #endif |
| 465 | blob_write_to_file(&text, zFile); |
| 466 | if( zEditor ){ |
| 467 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 468 | printf("%s\n", zCmd); |
| 469 | if( fossil_system(zCmd) ){ |
| 470 | fossil_panic("editor aborted"); |
| 471 | } |
| 472 | blob_reset(&text); |
| 473 | blob_read_from_file(&text, zFile); |
| 474 | }else{ |
| 475 | char zIn[300]; |
| 476 | blob_reset(&text); |
| 477 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 478 | if( zIn[0]=='.' && (zIn[1]==0 || zIn[1]=='\r' || zIn[1]=='\n') ) break; |
| 479 | blob_append(&text, zIn, -1); |
| 480 | } |
| 481 | } |
| 482 | blob_remove_cr(&text); |
| 483 | unlink(zFile); |
| 484 | free(zFile); |
| 485 | blob_zero(pComment); |
| 486 | while( blob_line(&text, &line) ){ |
| 487 | int i, n; |
| 488 | char *z; |
| @@ -534,28 +490,10 @@ | |
| 534 | } |
| 535 | g.aCommitFile[ii-2] = 0; |
| 536 | } |
| 537 | } |
| 538 | |
| 539 | /* |
| 540 | ** Return true if the check-in with RID=rid is a leaf. |
| 541 | ** A leaf has no children in the same branch. |
| 542 | */ |
| 543 | int is_a_leaf(int rid){ |
| 544 | int rc; |
| 545 | static const char zSql[] = |
| 546 | @ SELECT 1 FROM plink |
| 547 | @ WHERE pid=%d |
| 548 | @ AND coalesce((SELECT value FROM tagxref |
| 549 | @ WHERE tagid=%d AND rid=plink.pid), 'trunk') |
| 550 | @ =coalesce((SELECT value FROM tagxref |
| 551 | @ WHERE tagid=%d AND rid=plink.cid), 'trunk') |
| 552 | ; |
| 553 | rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); |
| 554 | return rc==0; |
| 555 | } |
| 556 | |
| 557 | /* |
| 558 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 559 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 560 | */ |
| 561 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | |
| 795 | } |
| 796 | if( nCrNl ){ |
| 797 | char c; |
| 798 | file_relative_name(zFilename, &fname); |
| 799 | blob_zero(&ans); |
| 800 | zMsg = mprintf("%s contains CR/NL line endings; commit anyhow (y/N/a)?", |
| 801 | blob_str(&fname)); |
| 802 | prompt_user(zMsg, &ans); |
| 803 | fossil_free(zMsg); |
| 804 | c = blob_str(&ans)[0]; |
| 805 | if( c=='a' ){ |
| 806 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | |
| 1179 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1180 | manifest_crosslink(nvid, &manifest); |
| 1181 | assert( blob_is_reset(&manifest) ); |
| 1182 | content_deltify(vid, nvid, 0); |
| 1183 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1184 | printf("New_Version: %s\n", zUuid); |
| 1185 | if( outputManifest ){ |
| 1186 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1187 | blob_zero(&muuid); |
| 1188 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1189 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | |
| 1248 | |
| 1249 | if( !g.markPrivate ){ |
| 1250 | autosync(AUTOSYNC_PUSH); |
| 1251 | } |
| 1252 | if( count_nonbranch_children(vid)>1 ){ |
| 1253 | printf("**** warning: a fork has occurred *****\n"); |
| 1254 | } |
| 1255 | } |
| 1256 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -54,11 +54,11 @@ | |
| 54 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 55 | blob_append(report, zPrefix, nPrefix); |
| 56 | if( isDeleted ){ |
| 57 | blob_appendf(report, "DELETED %s\n", zPathname); |
| 58 | }else if( !file_isfile(zFullName) ){ |
| 59 | if( file_access(zFullName, 0)==0 ){ |
| 60 | blob_appendf(report, "NOT_A_FILE %s\n", zPathname); |
| 61 | if( missingIsFatal ){ |
| 62 | fossil_warning("not a file: %s", zPathname); |
| 63 | nErr++; |
| 64 | } |
| @@ -142,13 +142,13 @@ | |
| 142 | */ |
| 143 | void status_cmd(void){ |
| 144 | int vid; |
| 145 | db_must_be_within_tree(); |
| 146 | /* 012345678901234 */ |
| 147 | fossil_print("repository: %s\n", db_lget("repository","")); |
| 148 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 149 | fossil_print("server-code: %s\n", db_get("server-code", "")); |
| 150 | vid = db_lget_int("checkout", 0); |
| 151 | if( vid ){ |
| 152 | show_common_info(vid, "checkout:", 1, 1); |
| 153 | } |
| 154 | changes_cmd(); |
| @@ -185,87 +185,33 @@ | |
| 185 | int isNew = db_column_int(&q,2)==0; |
| 186 | int chnged = db_column_int(&q,3); |
| 187 | int renamed = db_column_int(&q,4); |
| 188 | char *zFullName = mprintf("%s%s", g.zLocalRoot, zPathname); |
| 189 | if( isBrief ){ |
| 190 | fossil_print("%s\n", zPathname); |
| 191 | }else if( isNew ){ |
| 192 | fossil_print("ADDED %s\n", zPathname); |
| 193 | }else if( isDeleted ){ |
| 194 | fossil_print("DELETED %s\n", zPathname); |
| 195 | }else if( !file_isfile(zFullName) ){ |
| 196 | if( file_access(zFullName, 0)==0 ){ |
| 197 | fossil_print("NOT_A_FILE %s\n", zPathname); |
| 198 | }else{ |
| 199 | fossil_print("MISSING %s\n", zPathname); |
| 200 | } |
| 201 | }else if( chnged ){ |
| 202 | fossil_print("EDITED %s\n", zPathname); |
| 203 | }else if( renamed ){ |
| 204 | fossil_print("RENAMED %s\n", zPathname); |
| 205 | }else{ |
| 206 | fossil_print("UNCHANGED %s\n", zPathname); |
| 207 | } |
| 208 | free(zFullName); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | } |
| 212 | |
| 213 | /* |
| 214 | ** COMMAND: extras |
| 215 | ** Usage: %fossil extras ?--dotfiles? ?--ignore GLOBPATTERN? |
| 216 | ** |
| 217 | ** Print a list of all files in the source tree that are NOT part of |
| @@ -288,33 +234,34 @@ | |
| 234 | Stmt q; |
| 235 | int n; |
| 236 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 237 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 238 | int outputManifest; |
| 239 | Glob *pIgnore; |
| 240 | |
| 241 | db_must_be_within_tree(); |
| 242 | outputManifest = db_get_boolean("manifest",0); |
| 243 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 244 | n = strlen(g.zLocalRoot); |
| 245 | blob_init(&path, g.zLocalRoot, n-1); |
| 246 | if( zIgnoreFlag==0 ){ |
| 247 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 248 | } |
| 249 | pIgnore = glob_create(zIgnoreFlag); |
| 250 | vfile_scan(&path, blob_size(&path), allFlag, pIgnore); |
| 251 | glob_free(pIgnore); |
| 252 | db_prepare(&q, |
| 253 | "SELECT x FROM sfile" |
| 254 | " WHERE x NOT IN (%s)" |
| 255 | " ORDER BY 1", |
| 256 | fossil_all_reserved_names() |
| 257 | ); |
| 258 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 259 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 260 | } |
| 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 262 | fossil_print("%s\n", db_column_text(&q, 0)); |
| 263 | } |
| 264 | db_finalize(&q); |
| 265 | } |
| 266 | |
| 267 | /* |
| @@ -348,10 +295,12 @@ | |
| 295 | int dotfilesFlag; |
| 296 | const char *zIgnoreFlag; |
| 297 | Blob path, repo; |
| 298 | Stmt q; |
| 299 | int n; |
| 300 | Glob *pIgnore; |
| 301 | |
| 302 | allFlag = find_option("force","f",0)!=0; |
| 303 | dotfilesFlag = find_option("dotfiles",0,0)!=0; |
| 304 | zIgnoreFlag = find_option("ignore",0,1); |
| 305 | db_must_be_within_tree(); |
| 306 | if( zIgnoreFlag==0 ){ |
| @@ -358,31 +307,33 @@ | |
| 307 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 308 | } |
| 309 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 310 | n = strlen(g.zLocalRoot); |
| 311 | blob_init(&path, g.zLocalRoot, n-1); |
| 312 | pIgnore = glob_create(zIgnoreFlag); |
| 313 | vfile_scan(&path, blob_size(&path), dotfilesFlag, pIgnore); |
| 314 | glob_free(pIgnore); |
| 315 | db_prepare(&q, |
| 316 | "SELECT %Q || x FROM sfile" |
| 317 | " WHERE x NOT IN (%s)" |
| 318 | " ORDER BY 1", |
| 319 | g.zLocalRoot, fossil_all_reserved_names() |
| 320 | ); |
| 321 | if( file_tree_name(g.zRepositoryName, &repo, 0) ){ |
| 322 | db_multi_exec("DELETE FROM sfile WHERE x=%B", &repo); |
| 323 | } |
| 324 | while( db_step(&q)==SQLITE_ROW ){ |
| 325 | if( allFlag ){ |
| 326 | file_delete(db_column_text(&q, 0)); |
| 327 | }else{ |
| 328 | Blob ans; |
| 329 | char *prompt = mprintf("remove unmanaged file \"%s\" (y/N)? ", |
| 330 | db_column_text(&q, 0)); |
| 331 | blob_zero(&ans); |
| 332 | prompt_user(prompt, &ans); |
| 333 | if( blob_str(&ans)[0]=='y' ){ |
| 334 | file_delete(db_column_text(&q, 0)); |
| 335 | } |
| 336 | } |
| 337 | } |
| 338 | db_finalize(&q); |
| 339 | } |
| @@ -463,26 +414,31 @@ | |
| 414 | blob_add_cr(&text); |
| 415 | #endif |
| 416 | blob_write_to_file(&text, zFile); |
| 417 | if( zEditor ){ |
| 418 | zCmd = mprintf("%s \"%s\"", zEditor, zFile); |
| 419 | fossil_print("%s\n", zCmd); |
| 420 | if( fossil_system(zCmd) ){ |
| 421 | fossil_panic("editor aborted"); |
| 422 | } |
| 423 | blob_reset(&text); |
| 424 | blob_read_from_file(&text, zFile); |
| 425 | }else{ |
| 426 | char zIn[300]; |
| 427 | blob_reset(&text); |
| 428 | while( fgets(zIn, sizeof(zIn), stdin)!=0 ){ |
| 429 | char *zUtf8 = fossil_mbcs_to_utf8(zIn); |
| 430 | if( zUtf8[0]=='.' && (zUtf8[1]==0 || zUtf8[1]=='\r' || zUtf8[1]=='\n') ){ |
| 431 | fossil_mbcs_free(zUtf8); |
| 432 | break; |
| 433 | } |
| 434 | blob_append(&text, zIn, -1); |
| 435 | fossil_mbcs_free(zUtf8); |
| 436 | } |
| 437 | } |
| 438 | blob_remove_cr(&text); |
| 439 | file_delete(zFile); |
| 440 | free(zFile); |
| 441 | blob_zero(pComment); |
| 442 | while( blob_line(&text, &line) ){ |
| 443 | int i, n; |
| 444 | char *z; |
| @@ -534,28 +490,10 @@ | |
| 490 | } |
| 491 | g.aCommitFile[ii-2] = 0; |
| 492 | } |
| 493 | } |
| 494 | |
| 495 | /* |
| 496 | ** Make sure the current check-in with timestamp zDate is younger than its |
| 497 | ** ancestor identified rid and zUuid. Throw a fatal error if not. |
| 498 | */ |
| 499 | static void checkin_verify_younger( |
| @@ -795,12 +733,13 @@ | |
| 733 | } |
| 734 | if( nCrNl ){ |
| 735 | char c; |
| 736 | file_relative_name(zFilename, &fname); |
| 737 | blob_zero(&ans); |
| 738 | zMsg = mprintf( |
| 739 | "%s contains CR/NL line endings; commit anyhow (yes/no/all)?", |
| 740 | blob_str(&fname)); |
| 741 | prompt_user(zMsg, &ans); |
| 742 | fossil_free(zMsg); |
| 743 | c = blob_str(&ans)[0]; |
| 744 | if( c=='a' ){ |
| 745 | allOk = 1; |
| @@ -1179,11 +1118,11 @@ | |
| 1118 | db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nvid); |
| 1119 | manifest_crosslink(nvid, &manifest); |
| 1120 | assert( blob_is_reset(&manifest) ); |
| 1121 | content_deltify(vid, nvid, 0); |
| 1122 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nvid); |
| 1123 | fossil_print("New_Version: %s\n", zUuid); |
| 1124 | if( outputManifest ){ |
| 1125 | zManifestFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 1126 | blob_zero(&muuid); |
| 1127 | blob_appendf(&muuid, "%s\n", zUuid); |
| 1128 | blob_write_to_file(&muuid, zManifestFile); |
| @@ -1248,8 +1187,8 @@ | |
| 1187 | |
| 1188 | if( !g.markPrivate ){ |
| 1189 | autosync(AUTOSYNC_PUSH); |
| 1190 | } |
| 1191 | if( count_nonbranch_children(vid)>1 ){ |
| 1192 | fossil_print("**** warning: a fork has occurred *****\n"); |
| 1193 | } |
| 1194 | } |
| 1195 |
+6
-6
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -157,16 +157,16 @@ | ||
| 157 | 157 | free(zManFile); |
| 158 | 158 | blob_reset(&hash); |
| 159 | 159 | }else{ |
| 160 | 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | - unlink(zManFile); | |
| 162 | + file_delete(zManFile); | |
| 163 | 163 | free(zManFile); |
| 164 | 164 | } |
| 165 | 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | - unlink(zManFile); | |
| 167 | + file_delete(zManFile); | |
| 168 | 168 | free(zManFile); |
| 169 | 169 | } |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | } |
| @@ -203,11 +203,11 @@ | ||
| 203 | 203 | db_must_be_within_tree(); |
| 204 | 204 | db_begin_transaction(); |
| 205 | 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | - promptFlag = find_option("prompt",0,0)!=0; /* Prompt user before overwrite */ | |
| 208 | + promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; | |
| 209 | 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | 211 | } |
| 212 | 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | ||
| 252 | 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | - printf("WARNING: manifest checksum does not agree with disk\n"); | |
| 257 | + fossil_print("WARNING: manifest checksum does not agree with disk\n"); | |
| 258 | 258 | } |
| 259 | 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | - printf("WARNING: manifest checksum does not agree with manifest\n"); | |
| 260 | + fossil_print("WARNING: manifest checksum does not agree with manifest\n"); | |
| 261 | 261 | } |
| 262 | 262 | } |
| 263 | 263 | db_end_transaction(0); |
| 264 | 264 | } |
| 265 | 265 | |
| @@ -271,11 +271,11 @@ | ||
| 271 | 271 | int i; |
| 272 | 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | 274 | char *z; |
| 275 | 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | - unlink(z); | |
| 276 | + file_delete(z); | |
| 277 | 277 | free(z); |
| 278 | 278 | } |
| 279 | 279 | } |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -157,16 +157,16 @@ | |
| 157 | free(zManFile); |
| 158 | blob_reset(&hash); |
| 159 | }else{ |
| 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | unlink(zManFile); |
| 163 | free(zManFile); |
| 164 | } |
| 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | unlink(zManFile); |
| 168 | free(zManFile); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | } |
| @@ -203,11 +203,11 @@ | |
| 203 | db_must_be_within_tree(); |
| 204 | db_begin_transaction(); |
| 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | promptFlag = find_option("prompt",0,0)!=0; /* Prompt user before overwrite */ |
| 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | } |
| 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | |
| 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | printf("WARNING: manifest checksum does not agree with disk\n"); |
| 258 | } |
| 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | printf("WARNING: manifest checksum does not agree with manifest\n"); |
| 261 | } |
| 262 | } |
| 263 | db_end_transaction(0); |
| 264 | } |
| 265 | |
| @@ -271,11 +271,11 @@ | |
| 271 | int i; |
| 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | char *z; |
| 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | unlink(z); |
| 277 | free(z); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -157,16 +157,16 @@ | |
| 157 | free(zManFile); |
| 158 | blob_reset(&hash); |
| 159 | }else{ |
| 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | file_delete(zManFile); |
| 163 | free(zManFile); |
| 164 | } |
| 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | file_delete(zManFile); |
| 168 | free(zManFile); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | } |
| @@ -203,11 +203,11 @@ | |
| 203 | db_must_be_within_tree(); |
| 204 | db_begin_transaction(); |
| 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
| 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | } |
| 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | |
| 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | fossil_print("WARNING: manifest checksum does not agree with disk\n"); |
| 258 | } |
| 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | fossil_print("WARNING: manifest checksum does not agree with manifest\n"); |
| 261 | } |
| 262 | } |
| 263 | db_end_transaction(0); |
| 264 | } |
| 265 | |
| @@ -271,11 +271,11 @@ | |
| 271 | int i; |
| 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | char *z; |
| 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | file_delete(z); |
| 277 | free(z); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 |
+6
-6
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -157,16 +157,16 @@ | ||
| 157 | 157 | free(zManFile); |
| 158 | 158 | blob_reset(&hash); |
| 159 | 159 | }else{ |
| 160 | 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | - unlink(zManFile); | |
| 162 | + file_delete(zManFile); | |
| 163 | 163 | free(zManFile); |
| 164 | 164 | } |
| 165 | 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | - unlink(zManFile); | |
| 167 | + file_delete(zManFile); | |
| 168 | 168 | free(zManFile); |
| 169 | 169 | } |
| 170 | 170 | } |
| 171 | 171 | |
| 172 | 172 | } |
| @@ -203,11 +203,11 @@ | ||
| 203 | 203 | db_must_be_within_tree(); |
| 204 | 204 | db_begin_transaction(); |
| 205 | 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | - promptFlag = find_option("prompt",0,0)!=0; /* Prompt user before overwrite */ | |
| 208 | + promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; | |
| 209 | 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | 211 | } |
| 212 | 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | ||
| 252 | 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | - printf("WARNING: manifest checksum does not agree with disk\n"); | |
| 257 | + fossil_print("WARNING: manifest checksum does not agree with disk\n"); | |
| 258 | 258 | } |
| 259 | 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | - printf("WARNING: manifest checksum does not agree with manifest\n"); | |
| 260 | + fossil_print("WARNING: manifest checksum does not agree with manifest\n"); | |
| 261 | 261 | } |
| 262 | 262 | } |
| 263 | 263 | db_end_transaction(0); |
| 264 | 264 | } |
| 265 | 265 | |
| @@ -271,11 +271,11 @@ | ||
| 271 | 271 | int i; |
| 272 | 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | 274 | char *z; |
| 275 | 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | - unlink(z); | |
| 276 | + file_delete(z); | |
| 277 | 277 | free(z); |
| 278 | 278 | } |
| 279 | 279 | } |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | 282 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -157,16 +157,16 @@ | |
| 157 | free(zManFile); |
| 158 | blob_reset(&hash); |
| 159 | }else{ |
| 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | unlink(zManFile); |
| 163 | free(zManFile); |
| 164 | } |
| 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | unlink(zManFile); |
| 168 | free(zManFile); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | } |
| @@ -203,11 +203,11 @@ | |
| 203 | db_must_be_within_tree(); |
| 204 | db_begin_transaction(); |
| 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | promptFlag = find_option("prompt",0,0)!=0; /* Prompt user before overwrite */ |
| 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | } |
| 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | |
| 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | printf("WARNING: manifest checksum does not agree with disk\n"); |
| 258 | } |
| 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | printf("WARNING: manifest checksum does not agree with manifest\n"); |
| 261 | } |
| 262 | } |
| 263 | db_end_transaction(0); |
| 264 | } |
| 265 | |
| @@ -271,11 +271,11 @@ | |
| 271 | int i; |
| 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | char *z; |
| 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | unlink(z); |
| 277 | free(z); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -157,16 +157,16 @@ | |
| 157 | free(zManFile); |
| 158 | blob_reset(&hash); |
| 159 | }else{ |
| 160 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest'") ){ |
| 161 | zManFile = mprintf("%smanifest", g.zLocalRoot); |
| 162 | file_delete(zManFile); |
| 163 | free(zManFile); |
| 164 | } |
| 165 | if( !db_exists("SELECT 1 FROM vfile WHERE pathname='manifest.uuid'") ){ |
| 166 | zManFile = mprintf("%smanifest.uuid", g.zLocalRoot); |
| 167 | file_delete(zManFile); |
| 168 | free(zManFile); |
| 169 | } |
| 170 | } |
| 171 | |
| 172 | } |
| @@ -203,11 +203,11 @@ | |
| 203 | db_must_be_within_tree(); |
| 204 | db_begin_transaction(); |
| 205 | forceFlag = find_option("force","f",0)!=0; |
| 206 | keepFlag = find_option("keep",0,0)!=0; |
| 207 | latestFlag = find_option("latest",0,0)!=0; |
| 208 | promptFlag = find_option("prompt",0,0)!=0 || forceFlag==0; |
| 209 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 210 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 211 | } |
| 212 | if( !forceFlag && unsaved_changes()==1 ){ |
| 213 | fossil_fatal("there are unsaved changes in the current checkout"); |
| @@ -252,14 +252,14 @@ | |
| 252 | db_multi_exec("DELETE FROM vmerge"); |
| 253 | if( !keepFlag && db_get_boolean("repo-cksum",1) ){ |
| 254 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 255 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 256 | if( blob_compare(&cksum1, &cksum2) ){ |
| 257 | fossil_print("WARNING: manifest checksum does not agree with disk\n"); |
| 258 | } |
| 259 | if( blob_size(&cksum1b) && blob_compare(&cksum1, &cksum1b) ){ |
| 260 | fossil_print("WARNING: manifest checksum does not agree with manifest\n"); |
| 261 | } |
| 262 | } |
| 263 | db_end_transaction(0); |
| 264 | } |
| 265 | |
| @@ -271,11 +271,11 @@ | |
| 271 | int i; |
| 272 | for(i=0; (zReserved = fossil_reserved_name(i))!=0; i++){ |
| 273 | if( manifestOnly==0 || zReserved[0]=='m' ){ |
| 274 | char *z; |
| 275 | z = mprintf("%s%s", g.zLocalRoot, zReserved); |
| 276 | file_delete(z); |
| 277 | free(z); |
| 278 | } |
| 279 | } |
| 280 | } |
| 281 | |
| 282 |
+2
-2
| --- src/clearsign.c | ||
| +++ src/clearsign.c | ||
| @@ -52,11 +52,11 @@ | ||
| 52 | 52 | }else{ |
| 53 | 53 | if( pOut!=pIn ){ |
| 54 | 54 | blob_copy(pOut, pIn); |
| 55 | 55 | } |
| 56 | 56 | } |
| 57 | - unlink(zOut); | |
| 58 | - unlink(zIn); | |
| 57 | + file_delete(zOut); | |
| 58 | + file_delete(zIn); | |
| 59 | 59 | free(zOut); |
| 60 | 60 | free(zIn); |
| 61 | 61 | return rc; |
| 62 | 62 | } |
| 63 | 63 |
| --- src/clearsign.c | |
| +++ src/clearsign.c | |
| @@ -52,11 +52,11 @@ | |
| 52 | }else{ |
| 53 | if( pOut!=pIn ){ |
| 54 | blob_copy(pOut, pIn); |
| 55 | } |
| 56 | } |
| 57 | unlink(zOut); |
| 58 | unlink(zIn); |
| 59 | free(zOut); |
| 60 | free(zIn); |
| 61 | return rc; |
| 62 | } |
| 63 |
| --- src/clearsign.c | |
| +++ src/clearsign.c | |
| @@ -52,11 +52,11 @@ | |
| 52 | }else{ |
| 53 | if( pOut!=pIn ){ |
| 54 | blob_copy(pOut, pIn); |
| 55 | } |
| 56 | } |
| 57 | file_delete(zOut); |
| 58 | file_delete(zIn); |
| 59 | free(zOut); |
| 60 | free(zIn); |
| 61 | return rc; |
| 62 | } |
| 63 |
+12
-12
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -64,14 +64,14 @@ | ||
| 64 | 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | 65 | db_close(1); |
| 66 | 66 | db_open_repository(g.argv[3]); |
| 67 | 67 | db_record_repository_filename(g.argv[3]); |
| 68 | 68 | db_multi_exec( |
| 69 | - "REPLACE INTO config(name,value)" | |
| 70 | - " VALUES('server-code', lower(hex(randomblob(20))));" | |
| 71 | - "REPLACE INTO config(name,value)" | |
| 72 | - " VALUES('last-sync-url', '%q');", | |
| 69 | + "REPLACE INTO config(name,value,mtime)" | |
| 70 | + " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 71 | + "REPLACE INTO config(name,value,mtime)" | |
| 72 | + " VALUES('last-sync-url', '%q',now());", | |
| 73 | 73 | g.urlCanonical |
| 74 | 74 | ); |
| 75 | 75 | db_multi_exec( |
| 76 | 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | ||
| 80 | 80 | shun_artifacts(); |
| 81 | 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | 82 | if( g.zLogin==0 ){ |
| 83 | 83 | db_create_default_users(1,zDefaultUser); |
| 84 | 84 | } |
| 85 | - printf("Repository cloned into %s\n", g.argv[3]); | |
| 85 | + fossil_print("Repository cloned into %s\n", g.argv[3]); | |
| 86 | 86 | }else{ |
| 87 | 87 | db_create_repository(g.argv[3]); |
| 88 | 88 | db_open_repository(g.argv[3]); |
| 89 | 89 | db_begin_transaction(); |
| 90 | 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | ||
| 92 | 92 | user_select(); |
| 93 | 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | 96 | db_multi_exec( |
| 97 | - "REPLACE INTO config(name,value)" | |
| 98 | - " VALUES('server-code', lower(hex(randomblob(20))));" | |
| 97 | + "REPLACE INTO config(name,value,mtime)" | |
| 98 | + " VALUES('server-code', lower(hex(randomblob(20))), now());" | |
| 99 | 99 | ); |
| 100 | 100 | url_enable_proxy(0); |
| 101 | 101 | url_get_password_if_needed(); |
| 102 | 102 | g.xlinkClusterOnly = 1; |
| 103 | 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | ||
| 104 | 104 | g.xlinkClusterOnly = 0; |
| 105 | 105 | verify_cancel(); |
| 106 | 106 | db_end_transaction(0); |
| 107 | 107 | db_close(1); |
| 108 | 108 | if( nErr ){ |
| 109 | - unlink(g.argv[3]); | |
| 109 | + file_delete(g.argv[3]); | |
| 110 | 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | 111 | } |
| 112 | 112 | db_open_repository(g.argv[3]); |
| 113 | 113 | } |
| 114 | 114 | db_begin_transaction(); |
| 115 | - printf("Rebuilding repository meta-data...\n"); | |
| 115 | + fossil_print("Rebuilding repository meta-data...\n"); | |
| 116 | 116 | rebuild_db(0, 1, 0); |
| 117 | - printf("project-id: %s\n", db_get("project-code", 0)); | |
| 118 | - printf("server-id: %s\n", db_get("server-code", 0)); | |
| 117 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 118 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 119 | 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | - printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 120 | + fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 121 | 121 | db_end_transaction(0); |
| 122 | 122 | } |
| 123 | 123 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -64,14 +64,14 @@ | |
| 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | db_close(1); |
| 66 | db_open_repository(g.argv[3]); |
| 67 | db_record_repository_filename(g.argv[3]); |
| 68 | db_multi_exec( |
| 69 | "REPLACE INTO config(name,value)" |
| 70 | " VALUES('server-code', lower(hex(randomblob(20))));" |
| 71 | "REPLACE INTO config(name,value)" |
| 72 | " VALUES('last-sync-url', '%q');", |
| 73 | g.urlCanonical |
| 74 | ); |
| 75 | db_multi_exec( |
| 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | |
| 80 | shun_artifacts(); |
| 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | if( g.zLogin==0 ){ |
| 83 | db_create_default_users(1,zDefaultUser); |
| 84 | } |
| 85 | printf("Repository cloned into %s\n", g.argv[3]); |
| 86 | }else{ |
| 87 | db_create_repository(g.argv[3]); |
| 88 | db_open_repository(g.argv[3]); |
| 89 | db_begin_transaction(); |
| 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | |
| 92 | user_select(); |
| 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | db_multi_exec( |
| 97 | "REPLACE INTO config(name,value)" |
| 98 | " VALUES('server-code', lower(hex(randomblob(20))));" |
| 99 | ); |
| 100 | url_enable_proxy(0); |
| 101 | url_get_password_if_needed(); |
| 102 | g.xlinkClusterOnly = 1; |
| 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | |
| 104 | g.xlinkClusterOnly = 0; |
| 105 | verify_cancel(); |
| 106 | db_end_transaction(0); |
| 107 | db_close(1); |
| 108 | if( nErr ){ |
| 109 | unlink(g.argv[3]); |
| 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | } |
| 112 | db_open_repository(g.argv[3]); |
| 113 | } |
| 114 | db_begin_transaction(); |
| 115 | printf("Rebuilding repository meta-data...\n"); |
| 116 | rebuild_db(0, 1, 0); |
| 117 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 118 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 121 | db_end_transaction(0); |
| 122 | } |
| 123 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -64,14 +64,14 @@ | |
| 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | db_close(1); |
| 66 | db_open_repository(g.argv[3]); |
| 67 | db_record_repository_filename(g.argv[3]); |
| 68 | db_multi_exec( |
| 69 | "REPLACE INTO config(name,value,mtime)" |
| 70 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 71 | "REPLACE INTO config(name,value,mtime)" |
| 72 | " VALUES('last-sync-url', '%q',now());", |
| 73 | g.urlCanonical |
| 74 | ); |
| 75 | db_multi_exec( |
| 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | |
| 80 | shun_artifacts(); |
| 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | if( g.zLogin==0 ){ |
| 83 | db_create_default_users(1,zDefaultUser); |
| 84 | } |
| 85 | fossil_print("Repository cloned into %s\n", g.argv[3]); |
| 86 | }else{ |
| 87 | db_create_repository(g.argv[3]); |
| 88 | db_open_repository(g.argv[3]); |
| 89 | db_begin_transaction(); |
| 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | |
| 92 | user_select(); |
| 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | db_multi_exec( |
| 97 | "REPLACE INTO config(name,value,mtime)" |
| 98 | " VALUES('server-code', lower(hex(randomblob(20))), now());" |
| 99 | ); |
| 100 | url_enable_proxy(0); |
| 101 | url_get_password_if_needed(); |
| 102 | g.xlinkClusterOnly = 1; |
| 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | |
| 104 | g.xlinkClusterOnly = 0; |
| 105 | verify_cancel(); |
| 106 | db_end_transaction(0); |
| 107 | db_close(1); |
| 108 | if( nErr ){ |
| 109 | file_delete(g.argv[3]); |
| 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | } |
| 112 | db_open_repository(g.argv[3]); |
| 113 | } |
| 114 | db_begin_transaction(); |
| 115 | fossil_print("Rebuilding repository meta-data...\n"); |
| 116 | rebuild_db(0, 1, 0); |
| 117 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 118 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 121 | db_end_transaction(0); |
| 122 | } |
| 123 |
+12
-12
| --- src/clone.c | ||
| +++ src/clone.c | ||
| @@ -64,14 +64,14 @@ | ||
| 64 | 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | 65 | db_close(1); |
| 66 | 66 | db_open_repository(g.argv[3]); |
| 67 | 67 | db_record_repository_filename(g.argv[3]); |
| 68 | 68 | db_multi_exec( |
| 69 | - "REPLACE INTO config(name,value)" | |
| 70 | - " VALUES('server-code', lower(hex(randomblob(20))));" | |
| 71 | - "REPLACE INTO config(name,value)" | |
| 72 | - " VALUES('last-sync-url', '%q');", | |
| 69 | + "REPLACE INTO config(name,value,mtime)" | |
| 70 | + " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 71 | + "REPLACE INTO config(name,value,mtime)" | |
| 72 | + " VALUES('last-sync-url', '%q',now());", | |
| 73 | 73 | g.urlCanonical |
| 74 | 74 | ); |
| 75 | 75 | db_multi_exec( |
| 76 | 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | ||
| 80 | 80 | shun_artifacts(); |
| 81 | 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | 82 | if( g.zLogin==0 ){ |
| 83 | 83 | db_create_default_users(1,zDefaultUser); |
| 84 | 84 | } |
| 85 | - printf("Repository cloned into %s\n", g.argv[3]); | |
| 85 | + fossil_print("Repository cloned into %s\n", g.argv[3]); | |
| 86 | 86 | }else{ |
| 87 | 87 | db_create_repository(g.argv[3]); |
| 88 | 88 | db_open_repository(g.argv[3]); |
| 89 | 89 | db_begin_transaction(); |
| 90 | 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | ||
| 92 | 92 | user_select(); |
| 93 | 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | 96 | db_multi_exec( |
| 97 | - "REPLACE INTO config(name,value)" | |
| 98 | - " VALUES('server-code', lower(hex(randomblob(20))));" | |
| 97 | + "REPLACE INTO config(name,value,mtime)" | |
| 98 | + " VALUES('server-code', lower(hex(randomblob(20))), now());" | |
| 99 | 99 | ); |
| 100 | 100 | url_enable_proxy(0); |
| 101 | 101 | url_get_password_if_needed(); |
| 102 | 102 | g.xlinkClusterOnly = 1; |
| 103 | 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | ||
| 104 | 104 | g.xlinkClusterOnly = 0; |
| 105 | 105 | verify_cancel(); |
| 106 | 106 | db_end_transaction(0); |
| 107 | 107 | db_close(1); |
| 108 | 108 | if( nErr ){ |
| 109 | - unlink(g.argv[3]); | |
| 109 | + file_delete(g.argv[3]); | |
| 110 | 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | 111 | } |
| 112 | 112 | db_open_repository(g.argv[3]); |
| 113 | 113 | } |
| 114 | 114 | db_begin_transaction(); |
| 115 | - printf("Rebuilding repository meta-data...\n"); | |
| 115 | + fossil_print("Rebuilding repository meta-data...\n"); | |
| 116 | 116 | rebuild_db(0, 1, 0); |
| 117 | - printf("project-id: %s\n", db_get("project-code", 0)); | |
| 118 | - printf("server-id: %s\n", db_get("server-code", 0)); | |
| 117 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 118 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 119 | 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | - printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 120 | + fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 121 | 121 | db_end_transaction(0); |
| 122 | 122 | } |
| 123 | 123 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -64,14 +64,14 @@ | |
| 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | db_close(1); |
| 66 | db_open_repository(g.argv[3]); |
| 67 | db_record_repository_filename(g.argv[3]); |
| 68 | db_multi_exec( |
| 69 | "REPLACE INTO config(name,value)" |
| 70 | " VALUES('server-code', lower(hex(randomblob(20))));" |
| 71 | "REPLACE INTO config(name,value)" |
| 72 | " VALUES('last-sync-url', '%q');", |
| 73 | g.urlCanonical |
| 74 | ); |
| 75 | db_multi_exec( |
| 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | |
| 80 | shun_artifacts(); |
| 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | if( g.zLogin==0 ){ |
| 83 | db_create_default_users(1,zDefaultUser); |
| 84 | } |
| 85 | printf("Repository cloned into %s\n", g.argv[3]); |
| 86 | }else{ |
| 87 | db_create_repository(g.argv[3]); |
| 88 | db_open_repository(g.argv[3]); |
| 89 | db_begin_transaction(); |
| 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | |
| 92 | user_select(); |
| 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | db_multi_exec( |
| 97 | "REPLACE INTO config(name,value)" |
| 98 | " VALUES('server-code', lower(hex(randomblob(20))));" |
| 99 | ); |
| 100 | url_enable_proxy(0); |
| 101 | url_get_password_if_needed(); |
| 102 | g.xlinkClusterOnly = 1; |
| 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | |
| 104 | g.xlinkClusterOnly = 0; |
| 105 | verify_cancel(); |
| 106 | db_end_transaction(0); |
| 107 | db_close(1); |
| 108 | if( nErr ){ |
| 109 | unlink(g.argv[3]); |
| 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | } |
| 112 | db_open_repository(g.argv[3]); |
| 113 | } |
| 114 | db_begin_transaction(); |
| 115 | printf("Rebuilding repository meta-data...\n"); |
| 116 | rebuild_db(0, 1, 0); |
| 117 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 118 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 121 | db_end_transaction(0); |
| 122 | } |
| 123 |
| --- src/clone.c | |
| +++ src/clone.c | |
| @@ -64,14 +64,14 @@ | |
| 64 | file_copy(g.urlName, g.argv[3]); |
| 65 | db_close(1); |
| 66 | db_open_repository(g.argv[3]); |
| 67 | db_record_repository_filename(g.argv[3]); |
| 68 | db_multi_exec( |
| 69 | "REPLACE INTO config(name,value,mtime)" |
| 70 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 71 | "REPLACE INTO config(name,value,mtime)" |
| 72 | " VALUES('last-sync-url', '%q',now());", |
| 73 | g.urlCanonical |
| 74 | ); |
| 75 | db_multi_exec( |
| 76 | "DELETE FROM blob WHERE rid IN private;" |
| 77 | "DELETE FROM delta wHERE rid IN private;" |
| @@ -80,11 +80,11 @@ | |
| 80 | shun_artifacts(); |
| 81 | g.zLogin = db_text(0, "SELECT login FROM user WHERE cap LIKE '%%s%%'"); |
| 82 | if( g.zLogin==0 ){ |
| 83 | db_create_default_users(1,zDefaultUser); |
| 84 | } |
| 85 | fossil_print("Repository cloned into %s\n", g.argv[3]); |
| 86 | }else{ |
| 87 | db_create_repository(g.argv[3]); |
| 88 | db_open_repository(g.argv[3]); |
| 89 | db_begin_transaction(); |
| 90 | db_record_repository_filename(g.argv[3]); |
| @@ -92,12 +92,12 @@ | |
| 92 | user_select(); |
| 93 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 94 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 95 | db_set("last-sync-url", g.argv[2], 0); |
| 96 | db_multi_exec( |
| 97 | "REPLACE INTO config(name,value,mtime)" |
| 98 | " VALUES('server-code', lower(hex(randomblob(20))), now());" |
| 99 | ); |
| 100 | url_enable_proxy(0); |
| 101 | url_get_password_if_needed(); |
| 102 | g.xlinkClusterOnly = 1; |
| 103 | nErr = client_sync(0,0,1,bPrivate,CONFIGSET_ALL,0); |
| @@ -104,19 +104,19 @@ | |
| 104 | g.xlinkClusterOnly = 0; |
| 105 | verify_cancel(); |
| 106 | db_end_transaction(0); |
| 107 | db_close(1); |
| 108 | if( nErr ){ |
| 109 | file_delete(g.argv[3]); |
| 110 | fossil_fatal("server returned an error - clone aborted"); |
| 111 | } |
| 112 | db_open_repository(g.argv[3]); |
| 113 | } |
| 114 | db_begin_transaction(); |
| 115 | fossil_print("Rebuilding repository meta-data...\n"); |
| 116 | rebuild_db(0, 1, 0); |
| 117 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 118 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 119 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 120 | fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 121 | db_end_transaction(0); |
| 122 | } |
| 123 |
+6
-6
| --- src/comformat.c | ||
| +++ src/comformat.c | ||
| @@ -41,11 +41,11 @@ | ||
| 41 | 41 | |
| 42 | 42 | for(;;){ |
| 43 | 43 | while( fossil_isspace(zText[0]) ){ zText++; } |
| 44 | 44 | if( zText[0]==0 ){ |
| 45 | 45 | if( doIndent==0 ){ |
| 46 | - printf("\n"); | |
| 46 | + fossil_print("\n"); | |
| 47 | 47 | lineCnt = 1; |
| 48 | 48 | } |
| 49 | 49 | return lineCnt; |
| 50 | 50 | } |
| 51 | 51 | for(sk=si=i=k=0; zText[i] && k<tlen; i++){ |
| @@ -64,23 +64,23 @@ | ||
| 64 | 64 | } |
| 65 | 65 | k++; |
| 66 | 66 | } |
| 67 | 67 | } |
| 68 | 68 | if( doIndent ){ |
| 69 | - printf("%*s", indent, ""); | |
| 69 | + fossil_print("%*s", indent, ""); | |
| 70 | 70 | } |
| 71 | 71 | doIndent = 1; |
| 72 | 72 | if( sk>0 && zText[i] ){ |
| 73 | 73 | zText += si; |
| 74 | 74 | zBuf[sk++] = '\n'; |
| 75 | 75 | zBuf[sk] = 0; |
| 76 | - printf("%s", zBuf); | |
| 76 | + fossil_print("%s", zBuf); | |
| 77 | 77 | }else{ |
| 78 | 78 | zText += i; |
| 79 | 79 | zBuf[k++] = '\n'; |
| 80 | 80 | zBuf[k] = 0; |
| 81 | - printf("%s", zBuf); | |
| 81 | + fossil_print("%s", zBuf); | |
| 82 | 82 | } |
| 83 | 83 | lineCnt++; |
| 84 | 84 | } |
| 85 | 85 | } |
| 86 | 86 | |
| @@ -93,8 +93,8 @@ | ||
| 93 | 93 | int indent; |
| 94 | 94 | if( g.argc!=4 ){ |
| 95 | 95 | usage("PREFIX TEXT"); |
| 96 | 96 | } |
| 97 | 97 | indent = strlen(g.argv[2]) + 1; |
| 98 | - printf("%s ", g.argv[2]); | |
| 99 | - printf("(%d lines output)\n", comment_print(g.argv[3], indent, 79)); | |
| 98 | + fossil_print("%s ", g.argv[2]); | |
| 99 | + fossil_print("(%d lines output)\n", comment_print(g.argv[3], indent, 79)); | |
| 100 | 100 | } |
| 101 | 101 |
| --- src/comformat.c | |
| +++ src/comformat.c | |
| @@ -41,11 +41,11 @@ | |
| 41 | |
| 42 | for(;;){ |
| 43 | while( fossil_isspace(zText[0]) ){ zText++; } |
| 44 | if( zText[0]==0 ){ |
| 45 | if( doIndent==0 ){ |
| 46 | printf("\n"); |
| 47 | lineCnt = 1; |
| 48 | } |
| 49 | return lineCnt; |
| 50 | } |
| 51 | for(sk=si=i=k=0; zText[i] && k<tlen; i++){ |
| @@ -64,23 +64,23 @@ | |
| 64 | } |
| 65 | k++; |
| 66 | } |
| 67 | } |
| 68 | if( doIndent ){ |
| 69 | printf("%*s", indent, ""); |
| 70 | } |
| 71 | doIndent = 1; |
| 72 | if( sk>0 && zText[i] ){ |
| 73 | zText += si; |
| 74 | zBuf[sk++] = '\n'; |
| 75 | zBuf[sk] = 0; |
| 76 | printf("%s", zBuf); |
| 77 | }else{ |
| 78 | zText += i; |
| 79 | zBuf[k++] = '\n'; |
| 80 | zBuf[k] = 0; |
| 81 | printf("%s", zBuf); |
| 82 | } |
| 83 | lineCnt++; |
| 84 | } |
| 85 | } |
| 86 | |
| @@ -93,8 +93,8 @@ | |
| 93 | int indent; |
| 94 | if( g.argc!=4 ){ |
| 95 | usage("PREFIX TEXT"); |
| 96 | } |
| 97 | indent = strlen(g.argv[2]) + 1; |
| 98 | printf("%s ", g.argv[2]); |
| 99 | printf("(%d lines output)\n", comment_print(g.argv[3], indent, 79)); |
| 100 | } |
| 101 |
| --- src/comformat.c | |
| +++ src/comformat.c | |
| @@ -41,11 +41,11 @@ | |
| 41 | |
| 42 | for(;;){ |
| 43 | while( fossil_isspace(zText[0]) ){ zText++; } |
| 44 | if( zText[0]==0 ){ |
| 45 | if( doIndent==0 ){ |
| 46 | fossil_print("\n"); |
| 47 | lineCnt = 1; |
| 48 | } |
| 49 | return lineCnt; |
| 50 | } |
| 51 | for(sk=si=i=k=0; zText[i] && k<tlen; i++){ |
| @@ -64,23 +64,23 @@ | |
| 64 | } |
| 65 | k++; |
| 66 | } |
| 67 | } |
| 68 | if( doIndent ){ |
| 69 | fossil_print("%*s", indent, ""); |
| 70 | } |
| 71 | doIndent = 1; |
| 72 | if( sk>0 && zText[i] ){ |
| 73 | zText += si; |
| 74 | zBuf[sk++] = '\n'; |
| 75 | zBuf[sk] = 0; |
| 76 | fossil_print("%s", zBuf); |
| 77 | }else{ |
| 78 | zText += i; |
| 79 | zBuf[k++] = '\n'; |
| 80 | zBuf[k] = 0; |
| 81 | fossil_print("%s", zBuf); |
| 82 | } |
| 83 | lineCnt++; |
| 84 | } |
| 85 | } |
| 86 | |
| @@ -93,8 +93,8 @@ | |
| 93 | int indent; |
| 94 | if( g.argc!=4 ){ |
| 95 | usage("PREFIX TEXT"); |
| 96 | } |
| 97 | indent = strlen(g.argv[2]) + 1; |
| 98 | fossil_print("%s ", g.argv[2]); |
| 99 | fossil_print("(%d lines output)\n", comment_print(g.argv[3], indent, 79)); |
| 100 | } |
| 101 |
+7
-15
| --- src/config.h | ||
| +++ src/config.h | ||
| @@ -82,10 +82,17 @@ | ||
| 82 | 82 | |
| 83 | 83 | #ifndef _RC_COMPILE_ |
| 84 | 84 | |
| 85 | 85 | #include "sqlite3.h" |
| 86 | 86 | |
| 87 | +/* | |
| 88 | +** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257. | |
| 89 | +*/ | |
| 90 | +#if defined(__sun__) || defined(sun) | |
| 91 | + #define getpass getpassphrase | |
| 92 | +#endif | |
| 93 | + | |
| 87 | 94 | /* |
| 88 | 95 | ** Typedef for a 64-bit integer |
| 89 | 96 | */ |
| 90 | 97 | typedef sqlite3_int64 i64; |
| 91 | 98 | typedef sqlite3_uint64 u64; |
| @@ -123,21 +130,6 @@ | ||
| 123 | 130 | #else /* Generates a warning - but it always works */ |
| 124 | 131 | # define FOSSIL_INT_TO_PTR(X) ((void*)(X)) |
| 125 | 132 | # define FOSSIL_PTR_TO_INT(X) ((int)(X)) |
| 126 | 133 | #endif |
| 127 | 134 | |
| 128 | - | |
| 129 | -/* Unset the following to disable internationalization code. */ | |
| 130 | -#ifndef FOSSIL_I18N | |
| 131 | -# define FOSSIL_I18N 1 | |
| 132 | -#endif | |
| 133 | - | |
| 134 | -#if FOSSIL_I18N | |
| 135 | -# include <locale.h> | |
| 136 | -# include <langinfo.h> | |
| 137 | -#endif | |
| 138 | -#ifndef CODESET | |
| 139 | -# undef FOSSIL_I18N | |
| 140 | -# define FOSSIL_I18N 0 | |
| 141 | -#endif | |
| 142 | - | |
| 143 | 135 | #endif /* _RC_COMPILE_ */ |
| 144 | 136 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -82,10 +82,17 @@ | |
| 82 | |
| 83 | #ifndef _RC_COMPILE_ |
| 84 | |
| 85 | #include "sqlite3.h" |
| 86 | |
| 87 | /* |
| 88 | ** Typedef for a 64-bit integer |
| 89 | */ |
| 90 | typedef sqlite3_int64 i64; |
| 91 | typedef sqlite3_uint64 u64; |
| @@ -123,21 +130,6 @@ | |
| 123 | #else /* Generates a warning - but it always works */ |
| 124 | # define FOSSIL_INT_TO_PTR(X) ((void*)(X)) |
| 125 | # define FOSSIL_PTR_TO_INT(X) ((int)(X)) |
| 126 | #endif |
| 127 | |
| 128 | |
| 129 | /* Unset the following to disable internationalization code. */ |
| 130 | #ifndef FOSSIL_I18N |
| 131 | # define FOSSIL_I18N 1 |
| 132 | #endif |
| 133 | |
| 134 | #if FOSSIL_I18N |
| 135 | # include <locale.h> |
| 136 | # include <langinfo.h> |
| 137 | #endif |
| 138 | #ifndef CODESET |
| 139 | # undef FOSSIL_I18N |
| 140 | # define FOSSIL_I18N 0 |
| 141 | #endif |
| 142 | |
| 143 | #endif /* _RC_COMPILE_ */ |
| 144 |
| --- src/config.h | |
| +++ src/config.h | |
| @@ -82,10 +82,17 @@ | |
| 82 | |
| 83 | #ifndef _RC_COMPILE_ |
| 84 | |
| 85 | #include "sqlite3.h" |
| 86 | |
| 87 | /* |
| 88 | ** On Solaris, getpass() will only return up to 8 characters. getpassphrase() returns up to 257. |
| 89 | */ |
| 90 | #if defined(__sun__) || defined(sun) |
| 91 | #define getpass getpassphrase |
| 92 | #endif |
| 93 | |
| 94 | /* |
| 95 | ** Typedef for a 64-bit integer |
| 96 | */ |
| 97 | typedef sqlite3_int64 i64; |
| 98 | typedef sqlite3_uint64 u64; |
| @@ -123,21 +130,6 @@ | |
| 130 | #else /* Generates a warning - but it always works */ |
| 131 | # define FOSSIL_INT_TO_PTR(X) ((void*)(X)) |
| 132 | # define FOSSIL_PTR_TO_INT(X) ((int)(X)) |
| 133 | #endif |
| 134 | |
| 135 | #endif /* _RC_COMPILE_ */ |
| 136 |
+479
-91
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -2,11 +2,11 @@ | ||
| 2 | 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | 3 | ** |
| 4 | 4 | ** This program is free software; you can redistribute it and/or |
| 5 | 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | - | |
| 7 | +** | |
| 8 | 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | 9 | ** but without any warranty; without even the implied warranty of |
| 10 | 10 | ** merchantability or fitness for a particular purpose. |
| 11 | 11 | ** |
| 12 | 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | ||
| 14 | 14 | ** http://www.hwaci.com/drh/ |
| 15 | 15 | ** |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code used to manage repository configurations. |
| 19 | +** | |
| 19 | 20 | ** By "responsitory configure" we mean the local state of a repository |
| 20 | 21 | ** distinct from the versioned files. |
| 21 | 22 | */ |
| 22 | 23 | #include "config.h" |
| 23 | 24 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | ||
| 26 | 27 | #if INTERFACE |
| 27 | 28 | /* |
| 28 | 29 | ** Configuration transfers occur in groups. These are the allowed |
| 29 | 30 | ** groupings: |
| 30 | 31 | */ |
| 31 | -#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ | |
| 32 | -#define CONFIGSET_TKT 0x000002 /* Ticket configuration */ | |
| 33 | -#define CONFIGSET_PROJ 0x000004 /* Project name */ | |
| 34 | -#define CONFIGSET_SHUN 0x000008 /* Shun settings */ | |
| 35 | -#define CONFIGSET_USER 0x000010 /* The USER table */ | |
| 36 | -#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ | |
| 37 | - | |
| 38 | -#define CONFIGSET_ALL 0xffffff /* Everything */ | |
| 32 | +#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ | |
| 33 | +#define CONFIGSET_TKT 0x000002 /* Ticket configuration */ | |
| 34 | +#define CONFIGSET_PROJ 0x000004 /* Project name */ | |
| 35 | +#define CONFIGSET_SHUN 0x000008 /* Shun settings */ | |
| 36 | +#define CONFIGSET_USER 0x000010 /* The USER table */ | |
| 37 | +#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ | |
| 38 | + | |
| 39 | +#define CONFIGSET_ALL 0x0000ff /* Everything */ | |
| 40 | + | |
| 41 | +#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ | |
| 42 | +#define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ | |
| 39 | 43 | |
| 40 | 44 | #endif /* INTERFACE */ |
| 41 | 45 | |
| 42 | 46 | /* |
| 43 | 47 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | ||
| 45 | 49 | static struct { |
| 46 | 50 | const char *zName; /* Name of the configuration set */ |
| 47 | 51 | int groupMask; /* Mask for that configuration set */ |
| 48 | 52 | const char *zHelp; /* What it does */ |
| 49 | 53 | } aGroupName[] = { |
| 50 | - { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, | |
| 51 | - { "project", CONFIGSET_PROJ, "Project name and description" }, | |
| 52 | - { "skin", CONFIGSET_SKIN, "Web interface apparance settings" }, | |
| 53 | - { "shun", CONFIGSET_SHUN, "List of shunned artifacts" }, | |
| 54 | - { "ticket", CONFIGSET_TKT, "Ticket setup", }, | |
| 55 | - { "user", CONFIGSET_USER, "Users and privilege settings" }, | |
| 56 | - { "all", CONFIGSET_ALL, "All of the above" }, | |
| 54 | + { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, | |
| 55 | + { "/project", CONFIGSET_PROJ, "Project name and description" }, | |
| 56 | + { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" }, | |
| 57 | + { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" }, | |
| 58 | + { "/ticket", CONFIGSET_TKT, "Ticket setup", }, | |
| 59 | + { "/user", CONFIGSET_USER, "Users and privilege settings" }, | |
| 60 | + { "/all", CONFIGSET_ALL, "All of the above" }, | |
| 57 | 61 | }; |
| 58 | 62 | |
| 59 | 63 | |
| 60 | 64 | /* |
| 61 | 65 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | ||
| 105 | 109 | const char *configure_first_name(int iMask){ |
| 106 | 110 | iConfig = 0; |
| 107 | 111 | return configure_next_name(iMask); |
| 108 | 112 | } |
| 109 | 113 | const char *configure_next_name(int iMask){ |
| 110 | - while( iConfig<count(aConfig) ){ | |
| 111 | - if( aConfig[iConfig].groupMask & iMask ){ | |
| 112 | - return aConfig[iConfig++].zName; | |
| 113 | - }else{ | |
| 114 | - iConfig++; | |
| 114 | + if( iMask & CONFIGSET_OLDFORMAT ){ | |
| 115 | + while( iConfig<count(aConfig) ){ | |
| 116 | + if( aConfig[iConfig].groupMask & iMask ){ | |
| 117 | + return aConfig[iConfig++].zName; | |
| 118 | + }else{ | |
| 119 | + iConfig++; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + }else{ | |
| 123 | + if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){ | |
| 124 | + iConfig = count(aGroupName); | |
| 125 | + return "/all"; | |
| 126 | + } | |
| 127 | + while( iConfig<count(aGroupName)-1 ){ | |
| 128 | + if( aGroupName[iConfig].groupMask & iMask ){ | |
| 129 | + return aGroupName[iConfig++].zName; | |
| 130 | + }else{ | |
| 131 | + iConfig++; | |
| 132 | + } | |
| 115 | 133 | } |
| 116 | 134 | } |
| 117 | 135 | return 0; |
| 118 | 136 | } |
| 119 | 137 | |
| 120 | 138 | /* |
| 121 | 139 | ** Return the mask for the named configuration parameter if it can be |
| 122 | 140 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 141 | +** | |
| 142 | +** "Safe" in the previous paragraph means the permission is created to | |
| 143 | +** export the property. In other words, the requesting side has presented | |
| 144 | +** login credentials and has sufficient capabilities to access the requested | |
| 145 | +** information. | |
| 123 | 146 | */ |
| 124 | 147 | int configure_is_exportable(const char *zName){ |
| 125 | 148 | int i; |
| 149 | + int n = strlen(zName); | |
| 150 | + if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){ | |
| 151 | + zName++; | |
| 152 | + n -= 2; | |
| 153 | + } | |
| 126 | 154 | for(i=0; i<count(aConfig); i++){ |
| 127 | - if( fossil_strcmp(zName, aConfig[i].zName)==0 ){ | |
| 155 | + if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ | |
| 128 | 156 | int m = aConfig[i].groupMask; |
| 129 | 157 | if( !g.okAdmin ){ |
| 130 | 158 | m &= ~CONFIGSET_USER; |
| 131 | 159 | } |
| 132 | 160 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | ||
| 194 | 222 | } |
| 195 | 223 | |
| 196 | 224 | /* |
| 197 | 225 | ** Two SQL functions: |
| 198 | 226 | ** |
| 199 | -** flag_test(int) | |
| 200 | -** flag_clear(int) | |
| 227 | +** config_is_reset(int) | |
| 228 | +** config_reset(int) | |
| 201 | 229 | ** |
| 202 | -** The flag_test() function takes the integer valued argument and | |
| 203 | -** ANDs it against the static variable "flag_value" below. The | |
| 204 | -** function returns TRUE or false depending on the result. The | |
| 205 | -** flag_clear() function masks off the bits from "flag_value" that | |
| 230 | +** The config_is_reset() function takes the integer valued argument and | |
| 231 | +** ANDs it against the static variable "configHasBeenReset" below. The | |
| 232 | +** function returns TRUE or FALSE depending on the result depending on | |
| 233 | +** whether or not the corresponding configuration table has been reset. The | |
| 234 | +** config_reset() function adds the bits to "configHasBeenReset" that | |
| 206 | 235 | ** are given in the argument. |
| 207 | 236 | ** |
| 208 | 237 | ** These functions are used below in the WHEN clause of a trigger to |
| 209 | 238 | ** get the trigger to fire exactly once. |
| 210 | 239 | */ |
| 211 | -static int flag_value = 0xffff; | |
| 212 | -static void flag_test_function( | |
| 240 | +static int configHasBeenReset = 0; | |
| 241 | +static void config_is_reset_function( | |
| 213 | 242 | sqlite3_context *context, |
| 214 | 243 | int argc, |
| 215 | 244 | sqlite3_value **argv |
| 216 | 245 | ){ |
| 217 | 246 | int m = sqlite3_value_int(argv[0]); |
| 218 | - sqlite3_result_int(context, (flag_value&m)!=0 ); | |
| 247 | + sqlite3_result_int(context, (configHasBeenReset&m)!=0 ); | |
| 219 | 248 | } |
| 220 | -static void flag_clear_function( | |
| 249 | +static void config_reset_function( | |
| 221 | 250 | sqlite3_context *context, |
| 222 | 251 | int argc, |
| 223 | 252 | sqlite3_value **argv |
| 224 | 253 | ){ |
| 225 | 254 | int m = sqlite3_value_int(argv[0]); |
| 226 | - flag_value &= ~m; | |
| 255 | + configHasBeenReset |= m; | |
| 227 | 256 | } |
| 228 | 257 | |
| 229 | 258 | /* |
| 230 | 259 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 231 | 260 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | ||
| 255 | 284 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 256 | 285 | @ cexpire DATETIME, -- Time when cookie expires |
| 257 | 286 | @ info TEXT, -- contact information |
| 258 | 287 | @ photo BLOB -- JPEG image of this user |
| 259 | 288 | @ ); |
| 260 | - @ INSERT INTO _xfer_reportfmt SELECT * FROM reportfmt; | |
| 261 | - @ INSERT INTO _xfer_user SELECT * FROM user; | |
| 289 | + @ INSERT INTO _xfer_reportfmt | |
| 290 | + @ SELECT rn,owner,title,cols,sqlcode FROM reportfmt; | |
| 291 | + @ INSERT INTO _xfer_user | |
| 292 | + @ SELECT uid,login,pw,cap,cookie,ipaddr,cexpire,info,photo FROM user; | |
| 262 | 293 | ; |
| 263 | 294 | db_multi_exec(zSQL1); |
| 264 | 295 | |
| 265 | 296 | /* When the replace flag is set, add triggers that run the first time |
| 266 | 297 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | ||
| 267 | 298 | ** existing data. |
| 268 | 299 | */ |
| 269 | 300 | if( replaceFlag ){ |
| 270 | 301 | static const char zSQL2[] = |
| 271 | 302 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 272 | - @ WHEN flag_test(1) BEGIN | |
| 303 | + @ WHEN NOT config_is_reset(2) BEGIN | |
| 273 | 304 | @ DELETE FROM _xfer_reportfmt; |
| 274 | - @ SELECT flag_clear(1); | |
| 305 | + @ SELECT config_reset(2); | |
| 275 | 306 | @ END; |
| 276 | 307 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 277 | - @ WHEN flag_test(2) BEGIN | |
| 308 | + @ WHEN NOT config_is_reset(16) BEGIN | |
| 278 | 309 | @ DELETE FROM _xfer_user; |
| 279 | - @ SELECT flag_clear(2); | |
| 310 | + @ SELECT config_reset(16); | |
| 280 | 311 | @ END; |
| 281 | 312 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 282 | - @ WHEN flag_test(4) BEGIN | |
| 313 | + @ WHEN NOT config_is_reset(8) BEGIN | |
| 283 | 314 | @ DELETE FROM shun; |
| 284 | - @ SELECT flag_clear(4); | |
| 315 | + @ SELECT config_reset(8); | |
| 285 | 316 | @ END; |
| 286 | 317 | ; |
| 287 | - sqlite3_create_function(g.db, "flag_test", 1, SQLITE_UTF8, 0, | |
| 288 | - flag_test_function, 0, 0); | |
| 289 | - sqlite3_create_function(g.db, "flag_clear", 1, SQLITE_UTF8, 0, | |
| 290 | - flag_clear_function, 0, 0); | |
| 291 | - flag_value = 0xffff; | |
| 318 | + sqlite3_create_function(g.db, "config_is_reset", 1, SQLITE_UTF8, 0, | |
| 319 | + config_is_reset_function, 0, 0); | |
| 320 | + sqlite3_create_function(g.db, "config_reset", 1, SQLITE_UTF8, 0, | |
| 321 | + config_reset_function, 0, 0); | |
| 322 | + configHasBeenReset = 0; | |
| 292 | 323 | db_multi_exec(zSQL2); |
| 293 | 324 | } |
| 294 | 325 | } |
| 295 | 326 | |
| 296 | 327 | /* |
| @@ -306,66 +337,390 @@ | ||
| 306 | 337 | @ DROP TABLE _xfer_user; |
| 307 | 338 | @ DROP TABLE _xfer_reportfmt; |
| 308 | 339 | ; |
| 309 | 340 | db_multi_exec(zSQL); |
| 310 | 341 | } |
| 342 | + | |
| 343 | +/* | |
| 344 | +** Return true if z[] is not a "safe" SQL token. A safe token is one of: | |
| 345 | +** | |
| 346 | +** * A string literal | |
| 347 | +** * A blob literal | |
| 348 | +** * An integer literal (no floating point) | |
| 349 | +** * NULL | |
| 350 | +*/ | |
| 351 | +static int safeSql(const char *z){ | |
| 352 | + int i; | |
| 353 | + if( z==0 || z[0]==0 ) return 0; | |
| 354 | + if( (z[0]=='x' || z[0]=='X') && z[1]=='\'' ) z++; | |
| 355 | + if( z[0]=='\'' ){ | |
| 356 | + for(i=1; z[i]; i++){ | |
| 357 | + if( z[i]=='\'' ){ | |
| 358 | + i++; | |
| 359 | + if( z[i]=='\'' ){ continue; } | |
| 360 | + return z[i]==0; | |
| 361 | + } | |
| 362 | + } | |
| 363 | + return 0; | |
| 364 | + }else{ | |
| 365 | + char c; | |
| 366 | + for(i=0; (c = z[i])!=0; i++){ | |
| 367 | + if( !fossil_isalnum(c) ) return 0; | |
| 368 | + } | |
| 369 | + } | |
| 370 | + return 1; | |
| 371 | +} | |
| 372 | + | |
| 373 | +/* | |
| 374 | +** Return true if z[] consists of nothing but digits | |
| 375 | +*/ | |
| 376 | +static int safeInt(const char *z){ | |
| 377 | + int i; | |
| 378 | + if( z==0 || z[0]==0 ) return 0; | |
| 379 | + for(i=0; fossil_isdigit(z[i]); i++){} | |
| 380 | + return z[i]==0; | |
| 381 | +} | |
| 382 | + | |
| 383 | +/* | |
| 384 | +** Process a single "config" card received from the other side of a | |
| 385 | +** sync session. | |
| 386 | +** | |
| 387 | +** Mask consists of one or more CONFIGSET_* values ORed together, to | |
| 388 | +** designate what types of configuration we are allowed to receive. | |
| 389 | +** | |
| 390 | +** NEW FORMAT: | |
| 391 | +** | |
| 392 | +** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed". | |
| 393 | +** zName indicates the table that holds the configuration information being | |
| 394 | +** transferred. pContent is a string that consist of alternating Fossil | |
| 395 | +** and SQL tokens. The First token is a timestamp in seconds since 1970. | |
| 396 | +** The second token is a primary key for the table identified by zName. If | |
| 397 | +** The entry with the corresponding primary key exists and has a more recent | |
| 398 | +** mtime, then nothing happens. If the entry does not exist or if it has | |
| 399 | +** an older mtime, then the content described by subsequent token pairs is | |
| 400 | +** inserted. The first element of each token pair is a column name and | |
| 401 | +** the second is its value. | |
| 402 | +** | |
| 403 | +** In overview, we have: | |
| 404 | +** | |
| 405 | +** NAME CONTENT | |
| 406 | +** ------- ----------------------------------------------------------- | |
| 407 | +** /config $MTIME $NAME value $VALUE | |
| 408 | +** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE | |
| 409 | +** /shun $MTIME $UUID scom $VALUE | |
| 410 | +** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE | |
| 411 | +** /concealed $MTIME $HASH content $VALUE | |
| 412 | +** | |
| 413 | +** OLD FORMAT: | |
| 414 | +** | |
| 415 | +** The old format is retained for backwards compatiblity, but is deprecated. | |
| 416 | +** The cutover from old format to new was on 2011-04-25. After sufficient | |
| 417 | +** time has passed, support for the old format will be removed. | |
| 418 | +** | |
| 419 | +** zName is either the NAME of an element of the CONFIG table, or else | |
| 420 | +** one of the special names "@shun", "@reportfmt", "@user", or "@concealed". | |
| 421 | +** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the | |
| 422 | +** element in the CONFIG table. For one of the @-labels, CONTENT is raw | |
| 423 | +** SQL that is evaluated. Note that the raw SQL in CONTENT might not | |
| 424 | +** insert directly into the target table but might instead use a proxy | |
| 425 | +** table like _fer_reportfmt or _xfer_user. Such tables must be created | |
| 426 | +** ahead of time using configure_prepare_to_receive(). Then after multiple | |
| 427 | +** calls to this routine, configure_finalize_receive() to transfer the | |
| 428 | +** information received into the true target table. | |
| 429 | +*/ | |
| 430 | +void configure_receive(const char *zName, Blob *pContent, int groupMask){ | |
| 431 | + if( zName[0]=='/' ){ | |
| 432 | + /* The new format */ | |
| 433 | + char *azToken[12]; | |
| 434 | + int nToken = 0; | |
| 435 | + int ii, jj; | |
| 436 | + int thisMask; | |
| 437 | + Blob name, value, sql; | |
| 438 | + static const struct receiveType { | |
| 439 | + const char *zName; | |
| 440 | + const char *zPrimKey; | |
| 441 | + int nField; | |
| 442 | + const char *azField[4]; | |
| 443 | + } aType[] = { | |
| 444 | + { "/config", "name", 1, { "value", 0, 0, 0 } }, | |
| 445 | + { "@user", "login", 4, { "pw", "cap", "info", "photo" } }, | |
| 446 | + { "@shun", "uuid", 1, { "scom", 0, 0, 0 } }, | |
| 447 | + { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } }, | |
| 448 | + { "@concealed", "hash", 1, { "content", 0, 0, 0 } }, | |
| 449 | + }; | |
| 450 | + for(ii=0; ii<count(aType); ii++){ | |
| 451 | + if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break; | |
| 452 | + } | |
| 453 | + if( ii>=count(aType) ) return; | |
| 454 | + while( blob_token(pContent, &name) && blob_sqltoken(pContent, &value) ){ | |
| 455 | + char *z = blob_terminate(&name); | |
| 456 | + if( !safeSql(z) ) return; | |
| 457 | + if( nToken>0 ){ | |
| 458 | + for(jj=0; jj<aType[ii].nField; jj++){ | |
| 459 | + if( fossil_strcmp(aType[ii].azField[jj], z)==0 ) break; | |
| 460 | + } | |
| 461 | + if( jj>=aType[ii].nField ) continue; | |
| 462 | + }else{ | |
| 463 | + if( !safeInt(z) ) return; | |
| 464 | + } | |
| 465 | + azToken[nToken++] = z; | |
| 466 | + azToken[nToken++] = z = blob_terminate(&value); | |
| 467 | + if( !safeSql(z) ) return; | |
| 468 | + if( nToken>=count(azToken) ) break; | |
| 469 | + } | |
| 470 | + if( nToken<2 ) return; | |
| 471 | + if( aType[ii].zName[0]=='/' ){ | |
| 472 | + thisMask = configure_is_exportable(azToken[1]); | |
| 473 | + }else{ | |
| 474 | + thisMask = configure_is_exportable(aType[ii].zName); | |
| 475 | + } | |
| 476 | + if( (thisMask & groupMask)==0 ) return; | |
| 477 | + | |
| 478 | + blob_zero(&sql); | |
| 479 | + if( groupMask & CONFIGSET_OVERWRITE ){ | |
| 480 | + if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){ | |
| 481 | + db_multi_exec("DELETE FROM %s", &aType[ii].zName[1]); | |
| 482 | + configHasBeenReset |= thisMask; | |
| 483 | + } | |
| 484 | + blob_append(&sql, "REPLACE INTO ", -1); | |
| 485 | + }else{ | |
| 486 | + blob_append(&sql, "INSERT OR IGNORE INTO ", -1); | |
| 487 | + } | |
| 488 | + blob_appendf(&sql, "%s(%s, mtime", &zName[1], aType[ii].zPrimKey); | |
| 489 | + for(jj=2; jj<nToken; jj+=2){ | |
| 490 | + blob_appendf(&sql, ",%s", azToken[jj]); | |
| 491 | + } | |
| 492 | + blob_appendf(&sql,") VALUES(%s,%s", azToken[1], azToken[0]); | |
| 493 | + for(jj=2; jj<nToken; jj+=2){ | |
| 494 | + blob_appendf(&sql, ",%s", azToken[jj+1]); | |
| 495 | + } | |
| 496 | + db_multi_exec("%s)", blob_str(&sql)); | |
| 497 | + if( db_changes()==0 ){ | |
| 498 | + blob_reset(&sql); | |
| 499 | + blob_appendf(&sql, "UPDATE %s SET mtime=%s", &zName[1], azToken[0]); | |
| 500 | + for(jj=2; jj<nToken; jj+=2){ | |
| 501 | + blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]); | |
| 502 | + } | |
| 503 | + blob_appendf(&sql, " WHERE %s=%s AND mtime<%s", | |
| 504 | + aType[ii].zPrimKey, azToken[1], azToken[0]); | |
| 505 | + db_multi_exec("%s", blob_str(&sql)); | |
| 506 | + } | |
| 507 | + blob_reset(&sql); | |
| 508 | + }else{ | |
| 509 | + /* Otherwise, the old format */ | |
| 510 | + if( (configure_is_exportable(zName) & groupMask)==0 ) return; | |
| 511 | + if( strcmp(zName, "logo-image")==0 ){ | |
| 512 | + Stmt ins; | |
| 513 | + db_prepare(&ins, | |
| 514 | + "REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())" | |
| 515 | + ); | |
| 516 | + db_bind_text(&ins, ":name", zName); | |
| 517 | + db_bind_blob(&ins, ":value", pContent); | |
| 518 | + db_step(&ins); | |
| 519 | + db_finalize(&ins); | |
| 520 | + }else if( zName[0]=='@' ){ | |
| 521 | + /* Notice that we are evaluating arbitrary SQL received from the | |
| 522 | + ** client. But this can only happen if the client has authenticated | |
| 523 | + ** as an administrator, so presumably we trust the client at this | |
| 524 | + ** point. | |
| 525 | + */ | |
| 526 | + db_multi_exec("%s", blob_str(pContent)); | |
| 527 | + }else{ | |
| 528 | + db_multi_exec( | |
| 529 | + "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", | |
| 530 | + zName, blob_str(pContent) | |
| 531 | + ); | |
| 532 | + } | |
| 533 | + } | |
| 534 | +} | |
| 535 | + | |
| 536 | +/* | |
| 537 | +** Process a file full of "config" cards. | |
| 538 | +*/ | |
| 539 | +void configure_receive_all(Blob *pIn, int groupMask){ | |
| 540 | + Blob line; | |
| 541 | + int nToken; | |
| 542 | + int size; | |
| 543 | + Blob aToken[4]; | |
| 544 | + | |
| 545 | + configHasBeenReset = 0; | |
| 546 | + while( blob_line(pIn, &line) ){ | |
| 547 | + if( blob_buffer(&line)[0]=='#' ) continue; | |
| 548 | + nToken = blob_tokenize(&line, aToken, count(aToken)); | |
| 549 | + if( blob_eq(&aToken[0],"config") | |
| 550 | + && nToken==3 | |
| 551 | + && blob_is_int(&aToken[2], &size) | |
| 552 | + ){ | |
| 553 | + const char *zName = blob_str(&aToken[1]); | |
| 554 | + Blob content; | |
| 555 | + blob_zero(&content); | |
| 556 | + blob_extract(pIn, size, &content); | |
| 557 | + g.okAdmin = g.okRdAddr = 1; | |
| 558 | + configure_receive(zName, &content, groupMask); | |
| 559 | + blob_reset(&content); | |
| 560 | + blob_seek(pIn, 1, BLOB_SEEK_CUR); | |
| 561 | + } | |
| 562 | + } | |
| 563 | +} | |
| 564 | + | |
| 565 | + | |
| 566 | +/* | |
| 567 | +** Send "config" cards using the new format for all elements of a group | |
| 568 | +** that have recently changed. | |
| 569 | +** | |
| 570 | +** Output goes into pOut. The groupMask identifies the group(s) to be sent. | |
| 571 | +** Send only entries whose timestamp is later than or equal to iStart. | |
| 572 | +** | |
| 573 | +** Return the number of cards sent. | |
| 574 | +*/ | |
| 575 | +int configure_send_group( | |
| 576 | + Blob *pOut, /* Write output here */ | |
| 577 | + int groupMask, /* Mask of groups to be send */ | |
| 578 | + sqlite3_int64 iStart /* Only write values changed since this time */ | |
| 579 | +){ | |
| 580 | + Stmt q; | |
| 581 | + Blob rec; | |
| 582 | + int ii; | |
| 583 | + int nCard = 0; | |
| 584 | + | |
| 585 | + blob_zero(&rec); | |
| 586 | + if( groupMask & CONFIGSET_SHUN ){ | |
| 587 | + db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun" | |
| 588 | + " WHERE mtime>=%lld", iStart); | |
| 589 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 590 | + blob_appendf(&rec,"%s %s scom %s", | |
| 591 | + db_column_text(&q, 0), | |
| 592 | + db_column_text(&q, 1), | |
| 593 | + db_column_text(&q, 2) | |
| 594 | + ); | |
| 595 | + blob_appendf(pOut, "config /shun %d\n%s\n", | |
| 596 | + blob_size(&rec), blob_str(&rec)); | |
| 597 | + nCard++; | |
| 598 | + blob_reset(&rec); | |
| 599 | + } | |
| 600 | + db_finalize(&q); | |
| 601 | + } | |
| 602 | + if( groupMask & CONFIGSET_USER ){ | |
| 603 | + db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap)," | |
| 604 | + " quote(info), quote(photo) FROM user" | |
| 605 | + " WHERE mtime>=%lld", iStart); | |
| 606 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 607 | + blob_appendf(&rec,"%s %s pw %s cap %s info %s photo %s", | |
| 608 | + db_column_text(&q, 0), | |
| 609 | + db_column_text(&q, 1), | |
| 610 | + db_column_text(&q, 2), | |
| 611 | + db_column_text(&q, 3), | |
| 612 | + db_column_text(&q, 4), | |
| 613 | + db_column_text(&q, 5) | |
| 614 | + ); | |
| 615 | + blob_appendf(pOut, "config /user %d\n%s\n", | |
| 616 | + blob_size(&rec), blob_str(&rec)); | |
| 617 | + nCard++; | |
| 618 | + blob_reset(&rec); | |
| 619 | + } | |
| 620 | + db_finalize(&q); | |
| 621 | + } | |
| 622 | + if( groupMask & CONFIGSET_TKT ){ | |
| 623 | + db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols)," | |
| 624 | + " quote(sqlcode) FROM reportfmt" | |
| 625 | + " WHERE mtime>=%lld", iStart); | |
| 626 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 627 | + blob_appendf(&rec,"%s %s owner %s cols %s sqlcode %s", | |
| 628 | + db_column_text(&q, 0), | |
| 629 | + db_column_text(&q, 1), | |
| 630 | + db_column_text(&q, 2), | |
| 631 | + db_column_text(&q, 3), | |
| 632 | + db_column_text(&q, 4) | |
| 633 | + ); | |
| 634 | + blob_appendf(pOut, "config /reportfmt %d\n%s\n", | |
| 635 | + blob_size(&rec), blob_str(&rec)); | |
| 636 | + nCard++; | |
| 637 | + blob_reset(&rec); | |
| 638 | + } | |
| 639 | + db_finalize(&q); | |
| 640 | + } | |
| 641 | + if( groupMask & CONFIGSET_ADDR ){ | |
| 642 | + db_prepare(&q, "SELECT mtime, quote(hash), quote(content) FROM concealed" | |
| 643 | + " WHERE mtime>=%lld", iStart); | |
| 644 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 645 | + blob_appendf(&rec,"%s %s content %s", | |
| 646 | + db_column_text(&q, 0), | |
| 647 | + db_column_text(&q, 1), | |
| 648 | + db_column_text(&q, 2) | |
| 649 | + ); | |
| 650 | + blob_appendf(pOut, "config /concealed %d\n%s\n", | |
| 651 | + blob_size(&rec), blob_str(&rec)); | |
| 652 | + nCard++; | |
| 653 | + blob_reset(&rec); | |
| 654 | + } | |
| 655 | + db_finalize(&q); | |
| 656 | + } | |
| 657 | + db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" | |
| 658 | + " WHERE name=:name AND mtime>=%lld", iStart); | |
| 659 | + for(ii=0; ii<count(aConfig); ii++){ | |
| 660 | + if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){ | |
| 661 | + db_bind_text(&q, ":name", aConfig[ii].zName); | |
| 662 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 663 | + blob_appendf(&rec,"%s %s value %s", | |
| 664 | + db_column_text(&q, 0), | |
| 665 | + db_column_text(&q, 1), | |
| 666 | + db_column_text(&q, 2) | |
| 667 | + ); | |
| 668 | + blob_appendf(pOut, "config /config %d\n%s\n", | |
| 669 | + blob_size(&rec), blob_str(&rec)); | |
| 670 | + nCard++; | |
| 671 | + blob_reset(&rec); | |
| 672 | + } | |
| 673 | + db_reset(&q); | |
| 674 | + } | |
| 675 | + } | |
| 676 | + db_finalize(&q); | |
| 677 | + return nCard; | |
| 678 | +} | |
| 311 | 679 | |
| 312 | 680 | /* |
| 313 | 681 | ** Identify a configuration group by name. Return its mask. |
| 314 | 682 | ** Throw an error if no match. |
| 315 | 683 | */ |
| 316 | -static int find_area(const char *z){ | |
| 684 | +int configure_name_to_mask(const char *z, int notFoundIsFatal){ | |
| 317 | 685 | int i; |
| 318 | 686 | int n = strlen(z); |
| 319 | 687 | for(i=0; i<count(aGroupName); i++){ |
| 320 | - if( strncmp(z, aGroupName[i].zName, n)==0 ){ | |
| 688 | + if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){ | |
| 321 | 689 | return aGroupName[i].groupMask; |
| 322 | 690 | } |
| 323 | 691 | } |
| 324 | - printf("Available configuration areas:\n"); | |
| 325 | - for(i=0; i<count(aGroupName); i++){ | |
| 326 | - printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp); | |
| 692 | + if( notFoundIsFatal ){ | |
| 693 | + fossil_print("Available configuration areas:\n"); | |
| 694 | + for(i=0; i<count(aGroupName); i++){ | |
| 695 | + fossil_print(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp); | |
| 696 | + } | |
| 697 | + fossil_fatal("no such configuration area: \"%s\"", z); | |
| 327 | 698 | } |
| 328 | - fossil_fatal("no such configuration area: \"%s\"", z); | |
| 329 | 699 | return 0; |
| 330 | 700 | } |
| 331 | 701 | |
| 332 | 702 | /* |
| 333 | 703 | ** Write SQL text into file zFilename that will restore the configuration |
| 334 | 704 | ** area identified by mask to its current state from any other state. |
| 335 | 705 | */ |
| 336 | 706 | static void export_config( |
| 337 | - int mask, /* Mask indicating which configuration to export */ | |
| 707 | + int groupMask, /* Mask indicating which configuration to export */ | |
| 338 | 708 | const char *zMask, /* Name of the configuration */ |
| 709 | + sqlite3_int64 iStart, /* Start date */ | |
| 339 | 710 | const char *zFilename /* Write into this file */ |
| 340 | 711 | ){ |
| 341 | - int i; | |
| 342 | 712 | Blob out; |
| 343 | 713 | blob_zero(&out); |
| 344 | - blob_appendf(&out, | |
| 345 | - "-- The \"%s\" configuration exported from\n" | |
| 346 | - "-- repository \"%s\"\n" | |
| 347 | - "-- on %s\n", | |
| 714 | + blob_appendf(&out, | |
| 715 | + "# The \"%s\" configuration exported from\n" | |
| 716 | + "# repository \"%s\"\n" | |
| 717 | + "# on %s\n", | |
| 348 | 718 | zMask, g.zRepositoryName, |
| 349 | 719 | db_text(0, "SELECT datetime('now')") |
| 350 | 720 | ); |
| 351 | - for(i=0; i<count(aConfig); i++){ | |
| 352 | - if( (aConfig[i].groupMask & mask)!=0 ){ | |
| 353 | - const char *zName = aConfig[i].zName; | |
| 354 | - if( zName[0]!='@' ){ | |
| 355 | - char *zValue = db_text(0, | |
| 356 | - "SELECT quote(value) FROM config WHERE name=%Q", zName); | |
| 357 | - if( zValue ){ | |
| 358 | - blob_appendf(&out,"REPLACE INTO config VALUES(%Q,%s);\n", | |
| 359 | - zName, zValue); | |
| 360 | - } | |
| 361 | - free(zValue); | |
| 362 | - }else{ | |
| 363 | - configure_render_special_name(zName, &out); | |
| 364 | - } | |
| 365 | - } | |
| 366 | - } | |
| 721 | + configure_send_group(&out, groupMask, iStart); | |
| 367 | 722 | blob_write_to_file(&out, zFilename); |
| 368 | 723 | blob_reset(&out); |
| 369 | 724 | } |
| 370 | 725 | |
| 371 | 726 | |
| @@ -395,25 +750,31 @@ | ||
| 395 | 750 | ** |
| 396 | 751 | ** %fossil configuration pull AREA ?URL? |
| 397 | 752 | ** |
| 398 | 753 | ** Pull and install the configuration from a different server |
| 399 | 754 | ** identified by URL. If no URL is specified, then the default |
| 400 | -** server is used. | |
| 755 | +** server is used. Use the --legacy option for the older protocol | |
| 756 | +** (when talking to servers compiled prior to 2011-04-27.) Use | |
| 757 | +** the --overwrite flag to completely replace local settings with | |
| 758 | +** content received from URL. | |
| 401 | 759 | ** |
| 402 | 760 | ** %fossil configuration push AREA ?URL? |
| 403 | 761 | ** |
| 404 | 762 | ** Push the local configuration into the remote server identified |
| 405 | 763 | ** by URL. Admin privilege is required on the remote server for |
| 406 | -** this to work. | |
| 764 | +** this to work. When the same record exists both locally and on | |
| 765 | +** the remote end, the one that was most recently changed wins. | |
| 766 | +** Use the --legacy flag when talking to holder servers. | |
| 407 | 767 | ** |
| 408 | 768 | ** %fossil configuration reset AREA |
| 409 | 769 | ** |
| 410 | 770 | ** Restore the configuration to the default. AREA as above. |
| 411 | 771 | ** |
| 412 | -** WARNING: Do not import, merge, or pull configurations from an untrusted | |
| 413 | -** source. The inbound configuration is not checked for safety and can | |
| 414 | -** introduce security vulnerabilities. | |
| 772 | +** %fossil configuration sync AREA ?URL? | |
| 773 | +** | |
| 774 | +** Synchronize configuration changes in the local repository with | |
| 775 | +** the remote repository at URL. | |
| 415 | 776 | ** |
| 416 | 777 | ** |
| 417 | 778 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 418 | 779 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 419 | 780 | ** |
| @@ -438,36 +799,59 @@ | ||
| 438 | 799 | db_find_and_open_repository(0, 0); |
| 439 | 800 | zMethod = g.argv[2]; |
| 440 | 801 | n = strlen(zMethod); |
| 441 | 802 | if( strncmp(zMethod, "export", n)==0 ){ |
| 442 | 803 | int mask; |
| 804 | + const char *zSince = find_option("since",0,1); | |
| 805 | + sqlite3_int64 iStart; | |
| 443 | 806 | if( g.argc!=5 ){ |
| 444 | 807 | usage("export AREA FILENAME"); |
| 445 | 808 | } |
| 446 | - mask = find_area(g.argv[3]); | |
| 447 | - export_config(mask, g.argv[3], g.argv[4]); | |
| 809 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 810 | + if( zSince ){ | |
| 811 | + iStart = db_multi_exec( | |
| 812 | + "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0", | |
| 813 | + zSince, zSince | |
| 814 | + ); | |
| 815 | + }else{ | |
| 816 | + iStart = 0; | |
| 817 | + } | |
| 818 | + export_config(mask, g.argv[3], iStart, g.argv[4]); | |
| 448 | 819 | }else |
| 449 | 820 | if( strncmp(zMethod, "import", n)==0 |
| 450 | 821 | || strncmp(zMethod, "merge", n)==0 ){ |
| 451 | 822 | Blob in; |
| 823 | + int groupMask; | |
| 452 | 824 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 453 | 825 | blob_read_from_file(&in, g.argv[3]); |
| 454 | 826 | db_begin_transaction(); |
| 455 | - configure_prepare_to_receive(zMethod[0]=='i'); | |
| 456 | - db_multi_exec("%s", blob_str(&in)); | |
| 457 | - configure_finalize_receive(); | |
| 827 | + if( zMethod[0]=='i' ){ | |
| 828 | + groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; | |
| 829 | + }else{ | |
| 830 | + groupMask = CONFIGSET_ALL; | |
| 831 | + } | |
| 832 | + configure_receive_all(&in, groupMask); | |
| 458 | 833 | db_end_transaction(0); |
| 459 | 834 | }else |
| 460 | - if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ | |
| 835 | + if( strncmp(zMethod, "pull", n)==0 | |
| 836 | + || strncmp(zMethod, "push", n)==0 | |
| 837 | + || strncmp(zMethod, "sync", n)==0 | |
| 838 | + ){ | |
| 461 | 839 | int mask; |
| 462 | 840 | const char *zServer; |
| 463 | 841 | const char *zPw; |
| 842 | + int legacyFlag = 0; | |
| 843 | + int overwriteFlag = 0; | |
| 844 | + if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0; | |
| 845 | + if( strncmp(zMethod,"pull",n)==0 ){ | |
| 846 | + overwriteFlag = find_option("overwrite",0,0)!=0; | |
| 847 | + } | |
| 464 | 848 | url_proxy_options(); |
| 465 | 849 | if( g.argc!=4 && g.argc!=5 ){ |
| 466 | 850 | usage("pull AREA ?URL?"); |
| 467 | 851 | } |
| 468 | - mask = find_area(g.argv[3]); | |
| 852 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 469 | 853 | if( g.argc==5 ){ |
| 470 | 854 | zServer = g.argv[4]; |
| 471 | 855 | zPw = 0; |
| 472 | 856 | g.dontKeepUrl = 1; |
| 473 | 857 | }else{ |
| @@ -479,25 +863,29 @@ | ||
| 479 | 863 | } |
| 480 | 864 | url_parse(zServer); |
| 481 | 865 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 482 | 866 | user_select(); |
| 483 | 867 | url_enable_proxy("via proxy: "); |
| 868 | + if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; | |
| 869 | + if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; | |
| 484 | 870 | if( strncmp(zMethod, "push", n)==0 ){ |
| 485 | 871 | client_sync(0,0,0,0,0,mask); |
| 486 | - }else{ | |
| 872 | + }else if( strncmp(zMethod, "pull", n)==0 ){ | |
| 487 | 873 | client_sync(0,0,0,0,mask,0); |
| 874 | + }else{ | |
| 875 | + client_sync(0,0,0,0,mask,mask); | |
| 488 | 876 | } |
| 489 | 877 | }else |
| 490 | 878 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 491 | 879 | int mask, i; |
| 492 | 880 | char *zBackup; |
| 493 | 881 | if( g.argc!=4 ) usage("reset AREA"); |
| 494 | - mask = find_area(g.argv[3]); | |
| 882 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 495 | 883 | zBackup = db_text(0, |
| 496 | 884 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 497 | 885 | db_begin_transaction(); |
| 498 | - export_config(mask, g.argv[3], zBackup); | |
| 886 | + export_config(mask, g.argv[3], 0, zBackup); | |
| 499 | 887 | for(i=0; i<count(aConfig); i++){ |
| 500 | 888 | const char *zName = aConfig[i].zName; |
| 501 | 889 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 502 | 890 | if( zName[0]!='@' ){ |
| 503 | 891 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | ||
| 511 | 899 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 512 | 900 | db_multi_exec("DELETE FROM reportfmt"); |
| 513 | 901 | } |
| 514 | 902 | } |
| 515 | 903 | db_end_transaction(0); |
| 516 | - printf("Configuration reset to factory defaults.\n"); | |
| 517 | - printf("To recover, use: %s %s import %s\n", | |
| 904 | + fossil_print("Configuration reset to factory defaults.\n"); | |
| 905 | + fossil_print("To recover, use: %s %s import %s\n", | |
| 518 | 906 | fossil_nameofexe(), g.argv[1], zBackup); |
| 519 | 907 | }else |
| 520 | 908 | { |
| 521 | 909 | fossil_fatal("METHOD should be one of:" |
| 522 | 910 | " export import merge pull push reset"); |
| 523 | 911 | } |
| 524 | 912 | } |
| 525 | 913 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code used to manage repository configurations. |
| 19 | ** By "responsitory configure" we mean the local state of a repository |
| 20 | ** distinct from the versioned files. |
| 21 | */ |
| 22 | #include "config.h" |
| 23 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | |
| 26 | #if INTERFACE |
| 27 | /* |
| 28 | ** Configuration transfers occur in groups. These are the allowed |
| 29 | ** groupings: |
| 30 | */ |
| 31 | #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ |
| 32 | #define CONFIGSET_TKT 0x000002 /* Ticket configuration */ |
| 33 | #define CONFIGSET_PROJ 0x000004 /* Project name */ |
| 34 | #define CONFIGSET_SHUN 0x000008 /* Shun settings */ |
| 35 | #define CONFIGSET_USER 0x000010 /* The USER table */ |
| 36 | #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ |
| 37 | |
| 38 | #define CONFIGSET_ALL 0xffffff /* Everything */ |
| 39 | |
| 40 | #endif /* INTERFACE */ |
| 41 | |
| 42 | /* |
| 43 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | |
| 45 | static struct { |
| 46 | const char *zName; /* Name of the configuration set */ |
| 47 | int groupMask; /* Mask for that configuration set */ |
| 48 | const char *zHelp; /* What it does */ |
| 49 | } aGroupName[] = { |
| 50 | { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, |
| 51 | { "project", CONFIGSET_PROJ, "Project name and description" }, |
| 52 | { "skin", CONFIGSET_SKIN, "Web interface apparance settings" }, |
| 53 | { "shun", CONFIGSET_SHUN, "List of shunned artifacts" }, |
| 54 | { "ticket", CONFIGSET_TKT, "Ticket setup", }, |
| 55 | { "user", CONFIGSET_USER, "Users and privilege settings" }, |
| 56 | { "all", CONFIGSET_ALL, "All of the above" }, |
| 57 | }; |
| 58 | |
| 59 | |
| 60 | /* |
| 61 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | |
| 105 | const char *configure_first_name(int iMask){ |
| 106 | iConfig = 0; |
| 107 | return configure_next_name(iMask); |
| 108 | } |
| 109 | const char *configure_next_name(int iMask){ |
| 110 | while( iConfig<count(aConfig) ){ |
| 111 | if( aConfig[iConfig].groupMask & iMask ){ |
| 112 | return aConfig[iConfig++].zName; |
| 113 | }else{ |
| 114 | iConfig++; |
| 115 | } |
| 116 | } |
| 117 | return 0; |
| 118 | } |
| 119 | |
| 120 | /* |
| 121 | ** Return the mask for the named configuration parameter if it can be |
| 122 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 123 | */ |
| 124 | int configure_is_exportable(const char *zName){ |
| 125 | int i; |
| 126 | for(i=0; i<count(aConfig); i++){ |
| 127 | if( fossil_strcmp(zName, aConfig[i].zName)==0 ){ |
| 128 | int m = aConfig[i].groupMask; |
| 129 | if( !g.okAdmin ){ |
| 130 | m &= ~CONFIGSET_USER; |
| 131 | } |
| 132 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | |
| 194 | } |
| 195 | |
| 196 | /* |
| 197 | ** Two SQL functions: |
| 198 | ** |
| 199 | ** flag_test(int) |
| 200 | ** flag_clear(int) |
| 201 | ** |
| 202 | ** The flag_test() function takes the integer valued argument and |
| 203 | ** ANDs it against the static variable "flag_value" below. The |
| 204 | ** function returns TRUE or false depending on the result. The |
| 205 | ** flag_clear() function masks off the bits from "flag_value" that |
| 206 | ** are given in the argument. |
| 207 | ** |
| 208 | ** These functions are used below in the WHEN clause of a trigger to |
| 209 | ** get the trigger to fire exactly once. |
| 210 | */ |
| 211 | static int flag_value = 0xffff; |
| 212 | static void flag_test_function( |
| 213 | sqlite3_context *context, |
| 214 | int argc, |
| 215 | sqlite3_value **argv |
| 216 | ){ |
| 217 | int m = sqlite3_value_int(argv[0]); |
| 218 | sqlite3_result_int(context, (flag_value&m)!=0 ); |
| 219 | } |
| 220 | static void flag_clear_function( |
| 221 | sqlite3_context *context, |
| 222 | int argc, |
| 223 | sqlite3_value **argv |
| 224 | ){ |
| 225 | int m = sqlite3_value_int(argv[0]); |
| 226 | flag_value &= ~m; |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 231 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | |
| 255 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 256 | @ cexpire DATETIME, -- Time when cookie expires |
| 257 | @ info TEXT, -- contact information |
| 258 | @ photo BLOB -- JPEG image of this user |
| 259 | @ ); |
| 260 | @ INSERT INTO _xfer_reportfmt SELECT * FROM reportfmt; |
| 261 | @ INSERT INTO _xfer_user SELECT * FROM user; |
| 262 | ; |
| 263 | db_multi_exec(zSQL1); |
| 264 | |
| 265 | /* When the replace flag is set, add triggers that run the first time |
| 266 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | |
| 267 | ** existing data. |
| 268 | */ |
| 269 | if( replaceFlag ){ |
| 270 | static const char zSQL2[] = |
| 271 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 272 | @ WHEN flag_test(1) BEGIN |
| 273 | @ DELETE FROM _xfer_reportfmt; |
| 274 | @ SELECT flag_clear(1); |
| 275 | @ END; |
| 276 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 277 | @ WHEN flag_test(2) BEGIN |
| 278 | @ DELETE FROM _xfer_user; |
| 279 | @ SELECT flag_clear(2); |
| 280 | @ END; |
| 281 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 282 | @ WHEN flag_test(4) BEGIN |
| 283 | @ DELETE FROM shun; |
| 284 | @ SELECT flag_clear(4); |
| 285 | @ END; |
| 286 | ; |
| 287 | sqlite3_create_function(g.db, "flag_test", 1, SQLITE_UTF8, 0, |
| 288 | flag_test_function, 0, 0); |
| 289 | sqlite3_create_function(g.db, "flag_clear", 1, SQLITE_UTF8, 0, |
| 290 | flag_clear_function, 0, 0); |
| 291 | flag_value = 0xffff; |
| 292 | db_multi_exec(zSQL2); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | /* |
| @@ -306,66 +337,390 @@ | |
| 306 | @ DROP TABLE _xfer_user; |
| 307 | @ DROP TABLE _xfer_reportfmt; |
| 308 | ; |
| 309 | db_multi_exec(zSQL); |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | ** Identify a configuration group by name. Return its mask. |
| 314 | ** Throw an error if no match. |
| 315 | */ |
| 316 | static int find_area(const char *z){ |
| 317 | int i; |
| 318 | int n = strlen(z); |
| 319 | for(i=0; i<count(aGroupName); i++){ |
| 320 | if( strncmp(z, aGroupName[i].zName, n)==0 ){ |
| 321 | return aGroupName[i].groupMask; |
| 322 | } |
| 323 | } |
| 324 | printf("Available configuration areas:\n"); |
| 325 | for(i=0; i<count(aGroupName); i++){ |
| 326 | printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp); |
| 327 | } |
| 328 | fossil_fatal("no such configuration area: \"%s\"", z); |
| 329 | return 0; |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | ** Write SQL text into file zFilename that will restore the configuration |
| 334 | ** area identified by mask to its current state from any other state. |
| 335 | */ |
| 336 | static void export_config( |
| 337 | int mask, /* Mask indicating which configuration to export */ |
| 338 | const char *zMask, /* Name of the configuration */ |
| 339 | const char *zFilename /* Write into this file */ |
| 340 | ){ |
| 341 | int i; |
| 342 | Blob out; |
| 343 | blob_zero(&out); |
| 344 | blob_appendf(&out, |
| 345 | "-- The \"%s\" configuration exported from\n" |
| 346 | "-- repository \"%s\"\n" |
| 347 | "-- on %s\n", |
| 348 | zMask, g.zRepositoryName, |
| 349 | db_text(0, "SELECT datetime('now')") |
| 350 | ); |
| 351 | for(i=0; i<count(aConfig); i++){ |
| 352 | if( (aConfig[i].groupMask & mask)!=0 ){ |
| 353 | const char *zName = aConfig[i].zName; |
| 354 | if( zName[0]!='@' ){ |
| 355 | char *zValue = db_text(0, |
| 356 | "SELECT quote(value) FROM config WHERE name=%Q", zName); |
| 357 | if( zValue ){ |
| 358 | blob_appendf(&out,"REPLACE INTO config VALUES(%Q,%s);\n", |
| 359 | zName, zValue); |
| 360 | } |
| 361 | free(zValue); |
| 362 | }else{ |
| 363 | configure_render_special_name(zName, &out); |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | blob_write_to_file(&out, zFilename); |
| 368 | blob_reset(&out); |
| 369 | } |
| 370 | |
| 371 | |
| @@ -395,25 +750,31 @@ | |
| 395 | ** |
| 396 | ** %fossil configuration pull AREA ?URL? |
| 397 | ** |
| 398 | ** Pull and install the configuration from a different server |
| 399 | ** identified by URL. If no URL is specified, then the default |
| 400 | ** server is used. |
| 401 | ** |
| 402 | ** %fossil configuration push AREA ?URL? |
| 403 | ** |
| 404 | ** Push the local configuration into the remote server identified |
| 405 | ** by URL. Admin privilege is required on the remote server for |
| 406 | ** this to work. |
| 407 | ** |
| 408 | ** %fossil configuration reset AREA |
| 409 | ** |
| 410 | ** Restore the configuration to the default. AREA as above. |
| 411 | ** |
| 412 | ** WARNING: Do not import, merge, or pull configurations from an untrusted |
| 413 | ** source. The inbound configuration is not checked for safety and can |
| 414 | ** introduce security vulnerabilities. |
| 415 | ** |
| 416 | ** |
| 417 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 418 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 419 | ** |
| @@ -438,36 +799,59 @@ | |
| 438 | db_find_and_open_repository(0, 0); |
| 439 | zMethod = g.argv[2]; |
| 440 | n = strlen(zMethod); |
| 441 | if( strncmp(zMethod, "export", n)==0 ){ |
| 442 | int mask; |
| 443 | if( g.argc!=5 ){ |
| 444 | usage("export AREA FILENAME"); |
| 445 | } |
| 446 | mask = find_area(g.argv[3]); |
| 447 | export_config(mask, g.argv[3], g.argv[4]); |
| 448 | }else |
| 449 | if( strncmp(zMethod, "import", n)==0 |
| 450 | || strncmp(zMethod, "merge", n)==0 ){ |
| 451 | Blob in; |
| 452 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 453 | blob_read_from_file(&in, g.argv[3]); |
| 454 | db_begin_transaction(); |
| 455 | configure_prepare_to_receive(zMethod[0]=='i'); |
| 456 | db_multi_exec("%s", blob_str(&in)); |
| 457 | configure_finalize_receive(); |
| 458 | db_end_transaction(0); |
| 459 | }else |
| 460 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 461 | int mask; |
| 462 | const char *zServer; |
| 463 | const char *zPw; |
| 464 | url_proxy_options(); |
| 465 | if( g.argc!=4 && g.argc!=5 ){ |
| 466 | usage("pull AREA ?URL?"); |
| 467 | } |
| 468 | mask = find_area(g.argv[3]); |
| 469 | if( g.argc==5 ){ |
| 470 | zServer = g.argv[4]; |
| 471 | zPw = 0; |
| 472 | g.dontKeepUrl = 1; |
| 473 | }else{ |
| @@ -479,25 +863,29 @@ | |
| 479 | } |
| 480 | url_parse(zServer); |
| 481 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 482 | user_select(); |
| 483 | url_enable_proxy("via proxy: "); |
| 484 | if( strncmp(zMethod, "push", n)==0 ){ |
| 485 | client_sync(0,0,0,0,0,mask); |
| 486 | }else{ |
| 487 | client_sync(0,0,0,0,mask,0); |
| 488 | } |
| 489 | }else |
| 490 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 491 | int mask, i; |
| 492 | char *zBackup; |
| 493 | if( g.argc!=4 ) usage("reset AREA"); |
| 494 | mask = find_area(g.argv[3]); |
| 495 | zBackup = db_text(0, |
| 496 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 497 | db_begin_transaction(); |
| 498 | export_config(mask, g.argv[3], zBackup); |
| 499 | for(i=0; i<count(aConfig); i++){ |
| 500 | const char *zName = aConfig[i].zName; |
| 501 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 502 | if( zName[0]!='@' ){ |
| 503 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | |
| 511 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 512 | db_multi_exec("DELETE FROM reportfmt"); |
| 513 | } |
| 514 | } |
| 515 | db_end_transaction(0); |
| 516 | printf("Configuration reset to factory defaults.\n"); |
| 517 | printf("To recover, use: %s %s import %s\n", |
| 518 | fossil_nameofexe(), g.argv[1], zBackup); |
| 519 | }else |
| 520 | { |
| 521 | fossil_fatal("METHOD should be one of:" |
| 522 | " export import merge pull push reset"); |
| 523 | } |
| 524 | } |
| 525 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code used to manage repository configurations. |
| 19 | ** |
| 20 | ** By "responsitory configure" we mean the local state of a repository |
| 21 | ** distinct from the versioned files. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | |
| 27 | #if INTERFACE |
| 28 | /* |
| 29 | ** Configuration transfers occur in groups. These are the allowed |
| 30 | ** groupings: |
| 31 | */ |
| 32 | #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ |
| 33 | #define CONFIGSET_TKT 0x000002 /* Ticket configuration */ |
| 34 | #define CONFIGSET_PROJ 0x000004 /* Project name */ |
| 35 | #define CONFIGSET_SHUN 0x000008 /* Shun settings */ |
| 36 | #define CONFIGSET_USER 0x000010 /* The USER table */ |
| 37 | #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ |
| 38 | |
| 39 | #define CONFIGSET_ALL 0x0000ff /* Everything */ |
| 40 | |
| 41 | #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ |
| 42 | #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ |
| 43 | |
| 44 | #endif /* INTERFACE */ |
| 45 | |
| 46 | /* |
| 47 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | |
| 49 | static struct { |
| 50 | const char *zName; /* Name of the configuration set */ |
| 51 | int groupMask; /* Mask for that configuration set */ |
| 52 | const char *zHelp; /* What it does */ |
| 53 | } aGroupName[] = { |
| 54 | { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, |
| 55 | { "/project", CONFIGSET_PROJ, "Project name and description" }, |
| 56 | { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" }, |
| 57 | { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" }, |
| 58 | { "/ticket", CONFIGSET_TKT, "Ticket setup", }, |
| 59 | { "/user", CONFIGSET_USER, "Users and privilege settings" }, |
| 60 | { "/all", CONFIGSET_ALL, "All of the above" }, |
| 61 | }; |
| 62 | |
| 63 | |
| 64 | /* |
| 65 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | |
| 109 | const char *configure_first_name(int iMask){ |
| 110 | iConfig = 0; |
| 111 | return configure_next_name(iMask); |
| 112 | } |
| 113 | const char *configure_next_name(int iMask){ |
| 114 | if( iMask & CONFIGSET_OLDFORMAT ){ |
| 115 | while( iConfig<count(aConfig) ){ |
| 116 | if( aConfig[iConfig].groupMask & iMask ){ |
| 117 | return aConfig[iConfig++].zName; |
| 118 | }else{ |
| 119 | iConfig++; |
| 120 | } |
| 121 | } |
| 122 | }else{ |
| 123 | if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){ |
| 124 | iConfig = count(aGroupName); |
| 125 | return "/all"; |
| 126 | } |
| 127 | while( iConfig<count(aGroupName)-1 ){ |
| 128 | if( aGroupName[iConfig].groupMask & iMask ){ |
| 129 | return aGroupName[iConfig++].zName; |
| 130 | }else{ |
| 131 | iConfig++; |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | return 0; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ** Return the mask for the named configuration parameter if it can be |
| 140 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 141 | ** |
| 142 | ** "Safe" in the previous paragraph means the permission is created to |
| 143 | ** export the property. In other words, the requesting side has presented |
| 144 | ** login credentials and has sufficient capabilities to access the requested |
| 145 | ** information. |
| 146 | */ |
| 147 | int configure_is_exportable(const char *zName){ |
| 148 | int i; |
| 149 | int n = strlen(zName); |
| 150 | if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){ |
| 151 | zName++; |
| 152 | n -= 2; |
| 153 | } |
| 154 | for(i=0; i<count(aConfig); i++){ |
| 155 | if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ |
| 156 | int m = aConfig[i].groupMask; |
| 157 | if( !g.okAdmin ){ |
| 158 | m &= ~CONFIGSET_USER; |
| 159 | } |
| 160 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | |
| 222 | } |
| 223 | |
| 224 | /* |
| 225 | ** Two SQL functions: |
| 226 | ** |
| 227 | ** config_is_reset(int) |
| 228 | ** config_reset(int) |
| 229 | ** |
| 230 | ** The config_is_reset() function takes the integer valued argument and |
| 231 | ** ANDs it against the static variable "configHasBeenReset" below. The |
| 232 | ** function returns TRUE or FALSE depending on the result depending on |
| 233 | ** whether or not the corresponding configuration table has been reset. The |
| 234 | ** config_reset() function adds the bits to "configHasBeenReset" that |
| 235 | ** are given in the argument. |
| 236 | ** |
| 237 | ** These functions are used below in the WHEN clause of a trigger to |
| 238 | ** get the trigger to fire exactly once. |
| 239 | */ |
| 240 | static int configHasBeenReset = 0; |
| 241 | static void config_is_reset_function( |
| 242 | sqlite3_context *context, |
| 243 | int argc, |
| 244 | sqlite3_value **argv |
| 245 | ){ |
| 246 | int m = sqlite3_value_int(argv[0]); |
| 247 | sqlite3_result_int(context, (configHasBeenReset&m)!=0 ); |
| 248 | } |
| 249 | static void config_reset_function( |
| 250 | sqlite3_context *context, |
| 251 | int argc, |
| 252 | sqlite3_value **argv |
| 253 | ){ |
| 254 | int m = sqlite3_value_int(argv[0]); |
| 255 | configHasBeenReset |= m; |
| 256 | } |
| 257 | |
| 258 | /* |
| 259 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 260 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | |
| 284 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 285 | @ cexpire DATETIME, -- Time when cookie expires |
| 286 | @ info TEXT, -- contact information |
| 287 | @ photo BLOB -- JPEG image of this user |
| 288 | @ ); |
| 289 | @ INSERT INTO _xfer_reportfmt |
| 290 | @ SELECT rn,owner,title,cols,sqlcode FROM reportfmt; |
| 291 | @ INSERT INTO _xfer_user |
| 292 | @ SELECT uid,login,pw,cap,cookie,ipaddr,cexpire,info,photo FROM user; |
| 293 | ; |
| 294 | db_multi_exec(zSQL1); |
| 295 | |
| 296 | /* When the replace flag is set, add triggers that run the first time |
| 297 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | |
| 298 | ** existing data. |
| 299 | */ |
| 300 | if( replaceFlag ){ |
| 301 | static const char zSQL2[] = |
| 302 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 303 | @ WHEN NOT config_is_reset(2) BEGIN |
| 304 | @ DELETE FROM _xfer_reportfmt; |
| 305 | @ SELECT config_reset(2); |
| 306 | @ END; |
| 307 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 308 | @ WHEN NOT config_is_reset(16) BEGIN |
| 309 | @ DELETE FROM _xfer_user; |
| 310 | @ SELECT config_reset(16); |
| 311 | @ END; |
| 312 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 313 | @ WHEN NOT config_is_reset(8) BEGIN |
| 314 | @ DELETE FROM shun; |
| 315 | @ SELECT config_reset(8); |
| 316 | @ END; |
| 317 | ; |
| 318 | sqlite3_create_function(g.db, "config_is_reset", 1, SQLITE_UTF8, 0, |
| 319 | config_is_reset_function, 0, 0); |
| 320 | sqlite3_create_function(g.db, "config_reset", 1, SQLITE_UTF8, 0, |
| 321 | config_reset_function, 0, 0); |
| 322 | configHasBeenReset = 0; |
| 323 | db_multi_exec(zSQL2); |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | /* |
| @@ -306,66 +337,390 @@ | |
| 337 | @ DROP TABLE _xfer_user; |
| 338 | @ DROP TABLE _xfer_reportfmt; |
| 339 | ; |
| 340 | db_multi_exec(zSQL); |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | ** Return true if z[] is not a "safe" SQL token. A safe token is one of: |
| 345 | ** |
| 346 | ** * A string literal |
| 347 | ** * A blob literal |
| 348 | ** * An integer literal (no floating point) |
| 349 | ** * NULL |
| 350 | */ |
| 351 | static int safeSql(const char *z){ |
| 352 | int i; |
| 353 | if( z==0 || z[0]==0 ) return 0; |
| 354 | if( (z[0]=='x' || z[0]=='X') && z[1]=='\'' ) z++; |
| 355 | if( z[0]=='\'' ){ |
| 356 | for(i=1; z[i]; i++){ |
| 357 | if( z[i]=='\'' ){ |
| 358 | i++; |
| 359 | if( z[i]=='\'' ){ continue; } |
| 360 | return z[i]==0; |
| 361 | } |
| 362 | } |
| 363 | return 0; |
| 364 | }else{ |
| 365 | char c; |
| 366 | for(i=0; (c = z[i])!=0; i++){ |
| 367 | if( !fossil_isalnum(c) ) return 0; |
| 368 | } |
| 369 | } |
| 370 | return 1; |
| 371 | } |
| 372 | |
| 373 | /* |
| 374 | ** Return true if z[] consists of nothing but digits |
| 375 | */ |
| 376 | static int safeInt(const char *z){ |
| 377 | int i; |
| 378 | if( z==0 || z[0]==0 ) return 0; |
| 379 | for(i=0; fossil_isdigit(z[i]); i++){} |
| 380 | return z[i]==0; |
| 381 | } |
| 382 | |
| 383 | /* |
| 384 | ** Process a single "config" card received from the other side of a |
| 385 | ** sync session. |
| 386 | ** |
| 387 | ** Mask consists of one or more CONFIGSET_* values ORed together, to |
| 388 | ** designate what types of configuration we are allowed to receive. |
| 389 | ** |
| 390 | ** NEW FORMAT: |
| 391 | ** |
| 392 | ** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed". |
| 393 | ** zName indicates the table that holds the configuration information being |
| 394 | ** transferred. pContent is a string that consist of alternating Fossil |
| 395 | ** and SQL tokens. The First token is a timestamp in seconds since 1970. |
| 396 | ** The second token is a primary key for the table identified by zName. If |
| 397 | ** The entry with the corresponding primary key exists and has a more recent |
| 398 | ** mtime, then nothing happens. If the entry does not exist or if it has |
| 399 | ** an older mtime, then the content described by subsequent token pairs is |
| 400 | ** inserted. The first element of each token pair is a column name and |
| 401 | ** the second is its value. |
| 402 | ** |
| 403 | ** In overview, we have: |
| 404 | ** |
| 405 | ** NAME CONTENT |
| 406 | ** ------- ----------------------------------------------------------- |
| 407 | ** /config $MTIME $NAME value $VALUE |
| 408 | ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE |
| 409 | ** /shun $MTIME $UUID scom $VALUE |
| 410 | ** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE |
| 411 | ** /concealed $MTIME $HASH content $VALUE |
| 412 | ** |
| 413 | ** OLD FORMAT: |
| 414 | ** |
| 415 | ** The old format is retained for backwards compatiblity, but is deprecated. |
| 416 | ** The cutover from old format to new was on 2011-04-25. After sufficient |
| 417 | ** time has passed, support for the old format will be removed. |
| 418 | ** |
| 419 | ** zName is either the NAME of an element of the CONFIG table, or else |
| 420 | ** one of the special names "@shun", "@reportfmt", "@user", or "@concealed". |
| 421 | ** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the |
| 422 | ** element in the CONFIG table. For one of the @-labels, CONTENT is raw |
| 423 | ** SQL that is evaluated. Note that the raw SQL in CONTENT might not |
| 424 | ** insert directly into the target table but might instead use a proxy |
| 425 | ** table like _fer_reportfmt or _xfer_user. Such tables must be created |
| 426 | ** ahead of time using configure_prepare_to_receive(). Then after multiple |
| 427 | ** calls to this routine, configure_finalize_receive() to transfer the |
| 428 | ** information received into the true target table. |
| 429 | */ |
| 430 | void configure_receive(const char *zName, Blob *pContent, int groupMask){ |
| 431 | if( zName[0]=='/' ){ |
| 432 | /* The new format */ |
| 433 | char *azToken[12]; |
| 434 | int nToken = 0; |
| 435 | int ii, jj; |
| 436 | int thisMask; |
| 437 | Blob name, value, sql; |
| 438 | static const struct receiveType { |
| 439 | const char *zName; |
| 440 | const char *zPrimKey; |
| 441 | int nField; |
| 442 | const char *azField[4]; |
| 443 | } aType[] = { |
| 444 | { "/config", "name", 1, { "value", 0, 0, 0 } }, |
| 445 | { "@user", "login", 4, { "pw", "cap", "info", "photo" } }, |
| 446 | { "@shun", "uuid", 1, { "scom", 0, 0, 0 } }, |
| 447 | { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } }, |
| 448 | { "@concealed", "hash", 1, { "content", 0, 0, 0 } }, |
| 449 | }; |
| 450 | for(ii=0; ii<count(aType); ii++){ |
| 451 | if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break; |
| 452 | } |
| 453 | if( ii>=count(aType) ) return; |
| 454 | while( blob_token(pContent, &name) && blob_sqltoken(pContent, &value) ){ |
| 455 | char *z = blob_terminate(&name); |
| 456 | if( !safeSql(z) ) return; |
| 457 | if( nToken>0 ){ |
| 458 | for(jj=0; jj<aType[ii].nField; jj++){ |
| 459 | if( fossil_strcmp(aType[ii].azField[jj], z)==0 ) break; |
| 460 | } |
| 461 | if( jj>=aType[ii].nField ) continue; |
| 462 | }else{ |
| 463 | if( !safeInt(z) ) return; |
| 464 | } |
| 465 | azToken[nToken++] = z; |
| 466 | azToken[nToken++] = z = blob_terminate(&value); |
| 467 | if( !safeSql(z) ) return; |
| 468 | if( nToken>=count(azToken) ) break; |
| 469 | } |
| 470 | if( nToken<2 ) return; |
| 471 | if( aType[ii].zName[0]=='/' ){ |
| 472 | thisMask = configure_is_exportable(azToken[1]); |
| 473 | }else{ |
| 474 | thisMask = configure_is_exportable(aType[ii].zName); |
| 475 | } |
| 476 | if( (thisMask & groupMask)==0 ) return; |
| 477 | |
| 478 | blob_zero(&sql); |
| 479 | if( groupMask & CONFIGSET_OVERWRITE ){ |
| 480 | if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){ |
| 481 | db_multi_exec("DELETE FROM %s", &aType[ii].zName[1]); |
| 482 | configHasBeenReset |= thisMask; |
| 483 | } |
| 484 | blob_append(&sql, "REPLACE INTO ", -1); |
| 485 | }else{ |
| 486 | blob_append(&sql, "INSERT OR IGNORE INTO ", -1); |
| 487 | } |
| 488 | blob_appendf(&sql, "%s(%s, mtime", &zName[1], aType[ii].zPrimKey); |
| 489 | for(jj=2; jj<nToken; jj+=2){ |
| 490 | blob_appendf(&sql, ",%s", azToken[jj]); |
| 491 | } |
| 492 | blob_appendf(&sql,") VALUES(%s,%s", azToken[1], azToken[0]); |
| 493 | for(jj=2; jj<nToken; jj+=2){ |
| 494 | blob_appendf(&sql, ",%s", azToken[jj+1]); |
| 495 | } |
| 496 | db_multi_exec("%s)", blob_str(&sql)); |
| 497 | if( db_changes()==0 ){ |
| 498 | blob_reset(&sql); |
| 499 | blob_appendf(&sql, "UPDATE %s SET mtime=%s", &zName[1], azToken[0]); |
| 500 | for(jj=2; jj<nToken; jj+=2){ |
| 501 | blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]); |
| 502 | } |
| 503 | blob_appendf(&sql, " WHERE %s=%s AND mtime<%s", |
| 504 | aType[ii].zPrimKey, azToken[1], azToken[0]); |
| 505 | db_multi_exec("%s", blob_str(&sql)); |
| 506 | } |
| 507 | blob_reset(&sql); |
| 508 | }else{ |
| 509 | /* Otherwise, the old format */ |
| 510 | if( (configure_is_exportable(zName) & groupMask)==0 ) return; |
| 511 | if( strcmp(zName, "logo-image")==0 ){ |
| 512 | Stmt ins; |
| 513 | db_prepare(&ins, |
| 514 | "REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())" |
| 515 | ); |
| 516 | db_bind_text(&ins, ":name", zName); |
| 517 | db_bind_blob(&ins, ":value", pContent); |
| 518 | db_step(&ins); |
| 519 | db_finalize(&ins); |
| 520 | }else if( zName[0]=='@' ){ |
| 521 | /* Notice that we are evaluating arbitrary SQL received from the |
| 522 | ** client. But this can only happen if the client has authenticated |
| 523 | ** as an administrator, so presumably we trust the client at this |
| 524 | ** point. |
| 525 | */ |
| 526 | db_multi_exec("%s", blob_str(pContent)); |
| 527 | }else{ |
| 528 | db_multi_exec( |
| 529 | "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", |
| 530 | zName, blob_str(pContent) |
| 531 | ); |
| 532 | } |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /* |
| 537 | ** Process a file full of "config" cards. |
| 538 | */ |
| 539 | void configure_receive_all(Blob *pIn, int groupMask){ |
| 540 | Blob line; |
| 541 | int nToken; |
| 542 | int size; |
| 543 | Blob aToken[4]; |
| 544 | |
| 545 | configHasBeenReset = 0; |
| 546 | while( blob_line(pIn, &line) ){ |
| 547 | if( blob_buffer(&line)[0]=='#' ) continue; |
| 548 | nToken = blob_tokenize(&line, aToken, count(aToken)); |
| 549 | if( blob_eq(&aToken[0],"config") |
| 550 | && nToken==3 |
| 551 | && blob_is_int(&aToken[2], &size) |
| 552 | ){ |
| 553 | const char *zName = blob_str(&aToken[1]); |
| 554 | Blob content; |
| 555 | blob_zero(&content); |
| 556 | blob_extract(pIn, size, &content); |
| 557 | g.okAdmin = g.okRdAddr = 1; |
| 558 | configure_receive(zName, &content, groupMask); |
| 559 | blob_reset(&content); |
| 560 | blob_seek(pIn, 1, BLOB_SEEK_CUR); |
| 561 | } |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | |
| 566 | /* |
| 567 | ** Send "config" cards using the new format for all elements of a group |
| 568 | ** that have recently changed. |
| 569 | ** |
| 570 | ** Output goes into pOut. The groupMask identifies the group(s) to be sent. |
| 571 | ** Send only entries whose timestamp is later than or equal to iStart. |
| 572 | ** |
| 573 | ** Return the number of cards sent. |
| 574 | */ |
| 575 | int configure_send_group( |
| 576 | Blob *pOut, /* Write output here */ |
| 577 | int groupMask, /* Mask of groups to be send */ |
| 578 | sqlite3_int64 iStart /* Only write values changed since this time */ |
| 579 | ){ |
| 580 | Stmt q; |
| 581 | Blob rec; |
| 582 | int ii; |
| 583 | int nCard = 0; |
| 584 | |
| 585 | blob_zero(&rec); |
| 586 | if( groupMask & CONFIGSET_SHUN ){ |
| 587 | db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun" |
| 588 | " WHERE mtime>=%lld", iStart); |
| 589 | while( db_step(&q)==SQLITE_ROW ){ |
| 590 | blob_appendf(&rec,"%s %s scom %s", |
| 591 | db_column_text(&q, 0), |
| 592 | db_column_text(&q, 1), |
| 593 | db_column_text(&q, 2) |
| 594 | ); |
| 595 | blob_appendf(pOut, "config /shun %d\n%s\n", |
| 596 | blob_size(&rec), blob_str(&rec)); |
| 597 | nCard++; |
| 598 | blob_reset(&rec); |
| 599 | } |
| 600 | db_finalize(&q); |
| 601 | } |
| 602 | if( groupMask & CONFIGSET_USER ){ |
| 603 | db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap)," |
| 604 | " quote(info), quote(photo) FROM user" |
| 605 | " WHERE mtime>=%lld", iStart); |
| 606 | while( db_step(&q)==SQLITE_ROW ){ |
| 607 | blob_appendf(&rec,"%s %s pw %s cap %s info %s photo %s", |
| 608 | db_column_text(&q, 0), |
| 609 | db_column_text(&q, 1), |
| 610 | db_column_text(&q, 2), |
| 611 | db_column_text(&q, 3), |
| 612 | db_column_text(&q, 4), |
| 613 | db_column_text(&q, 5) |
| 614 | ); |
| 615 | blob_appendf(pOut, "config /user %d\n%s\n", |
| 616 | blob_size(&rec), blob_str(&rec)); |
| 617 | nCard++; |
| 618 | blob_reset(&rec); |
| 619 | } |
| 620 | db_finalize(&q); |
| 621 | } |
| 622 | if( groupMask & CONFIGSET_TKT ){ |
| 623 | db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols)," |
| 624 | " quote(sqlcode) FROM reportfmt" |
| 625 | " WHERE mtime>=%lld", iStart); |
| 626 | while( db_step(&q)==SQLITE_ROW ){ |
| 627 | blob_appendf(&rec,"%s %s owner %s cols %s sqlcode %s", |
| 628 | db_column_text(&q, 0), |
| 629 | db_column_text(&q, 1), |
| 630 | db_column_text(&q, 2), |
| 631 | db_column_text(&q, 3), |
| 632 | db_column_text(&q, 4) |
| 633 | ); |
| 634 | blob_appendf(pOut, "config /reportfmt %d\n%s\n", |
| 635 | blob_size(&rec), blob_str(&rec)); |
| 636 | nCard++; |
| 637 | blob_reset(&rec); |
| 638 | } |
| 639 | db_finalize(&q); |
| 640 | } |
| 641 | if( groupMask & CONFIGSET_ADDR ){ |
| 642 | db_prepare(&q, "SELECT mtime, quote(hash), quote(content) FROM concealed" |
| 643 | " WHERE mtime>=%lld", iStart); |
| 644 | while( db_step(&q)==SQLITE_ROW ){ |
| 645 | blob_appendf(&rec,"%s %s content %s", |
| 646 | db_column_text(&q, 0), |
| 647 | db_column_text(&q, 1), |
| 648 | db_column_text(&q, 2) |
| 649 | ); |
| 650 | blob_appendf(pOut, "config /concealed %d\n%s\n", |
| 651 | blob_size(&rec), blob_str(&rec)); |
| 652 | nCard++; |
| 653 | blob_reset(&rec); |
| 654 | } |
| 655 | db_finalize(&q); |
| 656 | } |
| 657 | db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" |
| 658 | " WHERE name=:name AND mtime>=%lld", iStart); |
| 659 | for(ii=0; ii<count(aConfig); ii++){ |
| 660 | if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){ |
| 661 | db_bind_text(&q, ":name", aConfig[ii].zName); |
| 662 | while( db_step(&q)==SQLITE_ROW ){ |
| 663 | blob_appendf(&rec,"%s %s value %s", |
| 664 | db_column_text(&q, 0), |
| 665 | db_column_text(&q, 1), |
| 666 | db_column_text(&q, 2) |
| 667 | ); |
| 668 | blob_appendf(pOut, "config /config %d\n%s\n", |
| 669 | blob_size(&rec), blob_str(&rec)); |
| 670 | nCard++; |
| 671 | blob_reset(&rec); |
| 672 | } |
| 673 | db_reset(&q); |
| 674 | } |
| 675 | } |
| 676 | db_finalize(&q); |
| 677 | return nCard; |
| 678 | } |
| 679 | |
| 680 | /* |
| 681 | ** Identify a configuration group by name. Return its mask. |
| 682 | ** Throw an error if no match. |
| 683 | */ |
| 684 | int configure_name_to_mask(const char *z, int notFoundIsFatal){ |
| 685 | int i; |
| 686 | int n = strlen(z); |
| 687 | for(i=0; i<count(aGroupName); i++){ |
| 688 | if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){ |
| 689 | return aGroupName[i].groupMask; |
| 690 | } |
| 691 | } |
| 692 | if( notFoundIsFatal ){ |
| 693 | fossil_print("Available configuration areas:\n"); |
| 694 | for(i=0; i<count(aGroupName); i++){ |
| 695 | fossil_print(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp); |
| 696 | } |
| 697 | fossil_fatal("no such configuration area: \"%s\"", z); |
| 698 | } |
| 699 | return 0; |
| 700 | } |
| 701 | |
| 702 | /* |
| 703 | ** Write SQL text into file zFilename that will restore the configuration |
| 704 | ** area identified by mask to its current state from any other state. |
| 705 | */ |
| 706 | static void export_config( |
| 707 | int groupMask, /* Mask indicating which configuration to export */ |
| 708 | const char *zMask, /* Name of the configuration */ |
| 709 | sqlite3_int64 iStart, /* Start date */ |
| 710 | const char *zFilename /* Write into this file */ |
| 711 | ){ |
| 712 | Blob out; |
| 713 | blob_zero(&out); |
| 714 | blob_appendf(&out, |
| 715 | "# The \"%s\" configuration exported from\n" |
| 716 | "# repository \"%s\"\n" |
| 717 | "# on %s\n", |
| 718 | zMask, g.zRepositoryName, |
| 719 | db_text(0, "SELECT datetime('now')") |
| 720 | ); |
| 721 | configure_send_group(&out, groupMask, iStart); |
| 722 | blob_write_to_file(&out, zFilename); |
| 723 | blob_reset(&out); |
| 724 | } |
| 725 | |
| 726 | |
| @@ -395,25 +750,31 @@ | |
| 750 | ** |
| 751 | ** %fossil configuration pull AREA ?URL? |
| 752 | ** |
| 753 | ** Pull and install the configuration from a different server |
| 754 | ** identified by URL. If no URL is specified, then the default |
| 755 | ** server is used. Use the --legacy option for the older protocol |
| 756 | ** (when talking to servers compiled prior to 2011-04-27.) Use |
| 757 | ** the --overwrite flag to completely replace local settings with |
| 758 | ** content received from URL. |
| 759 | ** |
| 760 | ** %fossil configuration push AREA ?URL? |
| 761 | ** |
| 762 | ** Push the local configuration into the remote server identified |
| 763 | ** by URL. Admin privilege is required on the remote server for |
| 764 | ** this to work. When the same record exists both locally and on |
| 765 | ** the remote end, the one that was most recently changed wins. |
| 766 | ** Use the --legacy flag when talking to holder servers. |
| 767 | ** |
| 768 | ** %fossil configuration reset AREA |
| 769 | ** |
| 770 | ** Restore the configuration to the default. AREA as above. |
| 771 | ** |
| 772 | ** %fossil configuration sync AREA ?URL? |
| 773 | ** |
| 774 | ** Synchronize configuration changes in the local repository with |
| 775 | ** the remote repository at URL. |
| 776 | ** |
| 777 | ** |
| 778 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 779 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 780 | ** |
| @@ -438,36 +799,59 @@ | |
| 799 | db_find_and_open_repository(0, 0); |
| 800 | zMethod = g.argv[2]; |
| 801 | n = strlen(zMethod); |
| 802 | if( strncmp(zMethod, "export", n)==0 ){ |
| 803 | int mask; |
| 804 | const char *zSince = find_option("since",0,1); |
| 805 | sqlite3_int64 iStart; |
| 806 | if( g.argc!=5 ){ |
| 807 | usage("export AREA FILENAME"); |
| 808 | } |
| 809 | mask = configure_name_to_mask(g.argv[3], 1); |
| 810 | if( zSince ){ |
| 811 | iStart = db_multi_exec( |
| 812 | "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0", |
| 813 | zSince, zSince |
| 814 | ); |
| 815 | }else{ |
| 816 | iStart = 0; |
| 817 | } |
| 818 | export_config(mask, g.argv[3], iStart, g.argv[4]); |
| 819 | }else |
| 820 | if( strncmp(zMethod, "import", n)==0 |
| 821 | || strncmp(zMethod, "merge", n)==0 ){ |
| 822 | Blob in; |
| 823 | int groupMask; |
| 824 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 825 | blob_read_from_file(&in, g.argv[3]); |
| 826 | db_begin_transaction(); |
| 827 | if( zMethod[0]=='i' ){ |
| 828 | groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; |
| 829 | }else{ |
| 830 | groupMask = CONFIGSET_ALL; |
| 831 | } |
| 832 | configure_receive_all(&in, groupMask); |
| 833 | db_end_transaction(0); |
| 834 | }else |
| 835 | if( strncmp(zMethod, "pull", n)==0 |
| 836 | || strncmp(zMethod, "push", n)==0 |
| 837 | || strncmp(zMethod, "sync", n)==0 |
| 838 | ){ |
| 839 | int mask; |
| 840 | const char *zServer; |
| 841 | const char *zPw; |
| 842 | int legacyFlag = 0; |
| 843 | int overwriteFlag = 0; |
| 844 | if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0; |
| 845 | if( strncmp(zMethod,"pull",n)==0 ){ |
| 846 | overwriteFlag = find_option("overwrite",0,0)!=0; |
| 847 | } |
| 848 | url_proxy_options(); |
| 849 | if( g.argc!=4 && g.argc!=5 ){ |
| 850 | usage("pull AREA ?URL?"); |
| 851 | } |
| 852 | mask = configure_name_to_mask(g.argv[3], 1); |
| 853 | if( g.argc==5 ){ |
| 854 | zServer = g.argv[4]; |
| 855 | zPw = 0; |
| 856 | g.dontKeepUrl = 1; |
| 857 | }else{ |
| @@ -479,25 +863,29 @@ | |
| 863 | } |
| 864 | url_parse(zServer); |
| 865 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 866 | user_select(); |
| 867 | url_enable_proxy("via proxy: "); |
| 868 | if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; |
| 869 | if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; |
| 870 | if( strncmp(zMethod, "push", n)==0 ){ |
| 871 | client_sync(0,0,0,0,0,mask); |
| 872 | }else if( strncmp(zMethod, "pull", n)==0 ){ |
| 873 | client_sync(0,0,0,0,mask,0); |
| 874 | }else{ |
| 875 | client_sync(0,0,0,0,mask,mask); |
| 876 | } |
| 877 | }else |
| 878 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 879 | int mask, i; |
| 880 | char *zBackup; |
| 881 | if( g.argc!=4 ) usage("reset AREA"); |
| 882 | mask = configure_name_to_mask(g.argv[3], 1); |
| 883 | zBackup = db_text(0, |
| 884 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 885 | db_begin_transaction(); |
| 886 | export_config(mask, g.argv[3], 0, zBackup); |
| 887 | for(i=0; i<count(aConfig); i++){ |
| 888 | const char *zName = aConfig[i].zName; |
| 889 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 890 | if( zName[0]!='@' ){ |
| 891 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | |
| 899 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 900 | db_multi_exec("DELETE FROM reportfmt"); |
| 901 | } |
| 902 | } |
| 903 | db_end_transaction(0); |
| 904 | fossil_print("Configuration reset to factory defaults.\n"); |
| 905 | fossil_print("To recover, use: %s %s import %s\n", |
| 906 | fossil_nameofexe(), g.argv[1], zBackup); |
| 907 | }else |
| 908 | { |
| 909 | fossil_fatal("METHOD should be one of:" |
| 910 | " export import merge pull push reset"); |
| 911 | } |
| 912 | } |
| 913 |
+479
-91
| --- src/configure.c | ||
| +++ src/configure.c | ||
| @@ -2,11 +2,11 @@ | ||
| 2 | 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | 3 | ** |
| 4 | 4 | ** This program is free software; you can redistribute it and/or |
| 5 | 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | - | |
| 7 | +** | |
| 8 | 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | 9 | ** but without any warranty; without even the implied warranty of |
| 10 | 10 | ** merchantability or fitness for a particular purpose. |
| 11 | 11 | ** |
| 12 | 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | ||
| 14 | 14 | ** http://www.hwaci.com/drh/ |
| 15 | 15 | ** |
| 16 | 16 | ******************************************************************************* |
| 17 | 17 | ** |
| 18 | 18 | ** This file contains code used to manage repository configurations. |
| 19 | +** | |
| 19 | 20 | ** By "responsitory configure" we mean the local state of a repository |
| 20 | 21 | ** distinct from the versioned files. |
| 21 | 22 | */ |
| 22 | 23 | #include "config.h" |
| 23 | 24 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | ||
| 26 | 27 | #if INTERFACE |
| 27 | 28 | /* |
| 28 | 29 | ** Configuration transfers occur in groups. These are the allowed |
| 29 | 30 | ** groupings: |
| 30 | 31 | */ |
| 31 | -#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ | |
| 32 | -#define CONFIGSET_TKT 0x000002 /* Ticket configuration */ | |
| 33 | -#define CONFIGSET_PROJ 0x000004 /* Project name */ | |
| 34 | -#define CONFIGSET_SHUN 0x000008 /* Shun settings */ | |
| 35 | -#define CONFIGSET_USER 0x000010 /* The USER table */ | |
| 36 | -#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ | |
| 37 | - | |
| 38 | -#define CONFIGSET_ALL 0xffffff /* Everything */ | |
| 32 | +#define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ | |
| 33 | +#define CONFIGSET_TKT 0x000002 /* Ticket configuration */ | |
| 34 | +#define CONFIGSET_PROJ 0x000004 /* Project name */ | |
| 35 | +#define CONFIGSET_SHUN 0x000008 /* Shun settings */ | |
| 36 | +#define CONFIGSET_USER 0x000010 /* The USER table */ | |
| 37 | +#define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ | |
| 38 | + | |
| 39 | +#define CONFIGSET_ALL 0x0000ff /* Everything */ | |
| 40 | + | |
| 41 | +#define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ | |
| 42 | +#define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ | |
| 39 | 43 | |
| 40 | 44 | #endif /* INTERFACE */ |
| 41 | 45 | |
| 42 | 46 | /* |
| 43 | 47 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | ||
| 45 | 49 | static struct { |
| 46 | 50 | const char *zName; /* Name of the configuration set */ |
| 47 | 51 | int groupMask; /* Mask for that configuration set */ |
| 48 | 52 | const char *zHelp; /* What it does */ |
| 49 | 53 | } aGroupName[] = { |
| 50 | - { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, | |
| 51 | - { "project", CONFIGSET_PROJ, "Project name and description" }, | |
| 52 | - { "skin", CONFIGSET_SKIN, "Web interface apparance settings" }, | |
| 53 | - { "shun", CONFIGSET_SHUN, "List of shunned artifacts" }, | |
| 54 | - { "ticket", CONFIGSET_TKT, "Ticket setup", }, | |
| 55 | - { "user", CONFIGSET_USER, "Users and privilege settings" }, | |
| 56 | - { "all", CONFIGSET_ALL, "All of the above" }, | |
| 54 | + { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, | |
| 55 | + { "/project", CONFIGSET_PROJ, "Project name and description" }, | |
| 56 | + { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" }, | |
| 57 | + { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" }, | |
| 58 | + { "/ticket", CONFIGSET_TKT, "Ticket setup", }, | |
| 59 | + { "/user", CONFIGSET_USER, "Users and privilege settings" }, | |
| 60 | + { "/all", CONFIGSET_ALL, "All of the above" }, | |
| 57 | 61 | }; |
| 58 | 62 | |
| 59 | 63 | |
| 60 | 64 | /* |
| 61 | 65 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | ||
| 105 | 109 | const char *configure_first_name(int iMask){ |
| 106 | 110 | iConfig = 0; |
| 107 | 111 | return configure_next_name(iMask); |
| 108 | 112 | } |
| 109 | 113 | const char *configure_next_name(int iMask){ |
| 110 | - while( iConfig<count(aConfig) ){ | |
| 111 | - if( aConfig[iConfig].groupMask & iMask ){ | |
| 112 | - return aConfig[iConfig++].zName; | |
| 113 | - }else{ | |
| 114 | - iConfig++; | |
| 114 | + if( iMask & CONFIGSET_OLDFORMAT ){ | |
| 115 | + while( iConfig<count(aConfig) ){ | |
| 116 | + if( aConfig[iConfig].groupMask & iMask ){ | |
| 117 | + return aConfig[iConfig++].zName; | |
| 118 | + }else{ | |
| 119 | + iConfig++; | |
| 120 | + } | |
| 121 | + } | |
| 122 | + }else{ | |
| 123 | + if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){ | |
| 124 | + iConfig = count(aGroupName); | |
| 125 | + return "/all"; | |
| 126 | + } | |
| 127 | + while( iConfig<count(aGroupName)-1 ){ | |
| 128 | + if( aGroupName[iConfig].groupMask & iMask ){ | |
| 129 | + return aGroupName[iConfig++].zName; | |
| 130 | + }else{ | |
| 131 | + iConfig++; | |
| 132 | + } | |
| 115 | 133 | } |
| 116 | 134 | } |
| 117 | 135 | return 0; |
| 118 | 136 | } |
| 119 | 137 | |
| 120 | 138 | /* |
| 121 | 139 | ** Return the mask for the named configuration parameter if it can be |
| 122 | 140 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 141 | +** | |
| 142 | +** "Safe" in the previous paragraph means the permission is created to | |
| 143 | +** export the property. In other words, the requesting side has presented | |
| 144 | +** login credentials and has sufficient capabilities to access the requested | |
| 145 | +** information. | |
| 123 | 146 | */ |
| 124 | 147 | int configure_is_exportable(const char *zName){ |
| 125 | 148 | int i; |
| 149 | + int n = strlen(zName); | |
| 150 | + if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){ | |
| 151 | + zName++; | |
| 152 | + n -= 2; | |
| 153 | + } | |
| 126 | 154 | for(i=0; i<count(aConfig); i++){ |
| 127 | - if( fossil_strcmp(zName, aConfig[i].zName)==0 ){ | |
| 155 | + if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ | |
| 128 | 156 | int m = aConfig[i].groupMask; |
| 129 | 157 | if( !g.okAdmin ){ |
| 130 | 158 | m &= ~CONFIGSET_USER; |
| 131 | 159 | } |
| 132 | 160 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | ||
| 194 | 222 | } |
| 195 | 223 | |
| 196 | 224 | /* |
| 197 | 225 | ** Two SQL functions: |
| 198 | 226 | ** |
| 199 | -** flag_test(int) | |
| 200 | -** flag_clear(int) | |
| 227 | +** config_is_reset(int) | |
| 228 | +** config_reset(int) | |
| 201 | 229 | ** |
| 202 | -** The flag_test() function takes the integer valued argument and | |
| 203 | -** ANDs it against the static variable "flag_value" below. The | |
| 204 | -** function returns TRUE or false depending on the result. The | |
| 205 | -** flag_clear() function masks off the bits from "flag_value" that | |
| 230 | +** The config_is_reset() function takes the integer valued argument and | |
| 231 | +** ANDs it against the static variable "configHasBeenReset" below. The | |
| 232 | +** function returns TRUE or FALSE depending on the result depending on | |
| 233 | +** whether or not the corresponding configuration table has been reset. The | |
| 234 | +** config_reset() function adds the bits to "configHasBeenReset" that | |
| 206 | 235 | ** are given in the argument. |
| 207 | 236 | ** |
| 208 | 237 | ** These functions are used below in the WHEN clause of a trigger to |
| 209 | 238 | ** get the trigger to fire exactly once. |
| 210 | 239 | */ |
| 211 | -static int flag_value = 0xffff; | |
| 212 | -static void flag_test_function( | |
| 240 | +static int configHasBeenReset = 0; | |
| 241 | +static void config_is_reset_function( | |
| 213 | 242 | sqlite3_context *context, |
| 214 | 243 | int argc, |
| 215 | 244 | sqlite3_value **argv |
| 216 | 245 | ){ |
| 217 | 246 | int m = sqlite3_value_int(argv[0]); |
| 218 | - sqlite3_result_int(context, (flag_value&m)!=0 ); | |
| 247 | + sqlite3_result_int(context, (configHasBeenReset&m)!=0 ); | |
| 219 | 248 | } |
| 220 | -static void flag_clear_function( | |
| 249 | +static void config_reset_function( | |
| 221 | 250 | sqlite3_context *context, |
| 222 | 251 | int argc, |
| 223 | 252 | sqlite3_value **argv |
| 224 | 253 | ){ |
| 225 | 254 | int m = sqlite3_value_int(argv[0]); |
| 226 | - flag_value &= ~m; | |
| 255 | + configHasBeenReset |= m; | |
| 227 | 256 | } |
| 228 | 257 | |
| 229 | 258 | /* |
| 230 | 259 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 231 | 260 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | ||
| 255 | 284 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 256 | 285 | @ cexpire DATETIME, -- Time when cookie expires |
| 257 | 286 | @ info TEXT, -- contact information |
| 258 | 287 | @ photo BLOB -- JPEG image of this user |
| 259 | 288 | @ ); |
| 260 | - @ INSERT INTO _xfer_reportfmt SELECT * FROM reportfmt; | |
| 261 | - @ INSERT INTO _xfer_user SELECT * FROM user; | |
| 289 | + @ INSERT INTO _xfer_reportfmt | |
| 290 | + @ SELECT rn,owner,title,cols,sqlcode FROM reportfmt; | |
| 291 | + @ INSERT INTO _xfer_user | |
| 292 | + @ SELECT uid,login,pw,cap,cookie,ipaddr,cexpire,info,photo FROM user; | |
| 262 | 293 | ; |
| 263 | 294 | db_multi_exec(zSQL1); |
| 264 | 295 | |
| 265 | 296 | /* When the replace flag is set, add triggers that run the first time |
| 266 | 297 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | ||
| 267 | 298 | ** existing data. |
| 268 | 299 | */ |
| 269 | 300 | if( replaceFlag ){ |
| 270 | 301 | static const char zSQL2[] = |
| 271 | 302 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 272 | - @ WHEN flag_test(1) BEGIN | |
| 303 | + @ WHEN NOT config_is_reset(2) BEGIN | |
| 273 | 304 | @ DELETE FROM _xfer_reportfmt; |
| 274 | - @ SELECT flag_clear(1); | |
| 305 | + @ SELECT config_reset(2); | |
| 275 | 306 | @ END; |
| 276 | 307 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 277 | - @ WHEN flag_test(2) BEGIN | |
| 308 | + @ WHEN NOT config_is_reset(16) BEGIN | |
| 278 | 309 | @ DELETE FROM _xfer_user; |
| 279 | - @ SELECT flag_clear(2); | |
| 310 | + @ SELECT config_reset(16); | |
| 280 | 311 | @ END; |
| 281 | 312 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 282 | - @ WHEN flag_test(4) BEGIN | |
| 313 | + @ WHEN NOT config_is_reset(8) BEGIN | |
| 283 | 314 | @ DELETE FROM shun; |
| 284 | - @ SELECT flag_clear(4); | |
| 315 | + @ SELECT config_reset(8); | |
| 285 | 316 | @ END; |
| 286 | 317 | ; |
| 287 | - sqlite3_create_function(g.db, "flag_test", 1, SQLITE_UTF8, 0, | |
| 288 | - flag_test_function, 0, 0); | |
| 289 | - sqlite3_create_function(g.db, "flag_clear", 1, SQLITE_UTF8, 0, | |
| 290 | - flag_clear_function, 0, 0); | |
| 291 | - flag_value = 0xffff; | |
| 318 | + sqlite3_create_function(g.db, "config_is_reset", 1, SQLITE_UTF8, 0, | |
| 319 | + config_is_reset_function, 0, 0); | |
| 320 | + sqlite3_create_function(g.db, "config_reset", 1, SQLITE_UTF8, 0, | |
| 321 | + config_reset_function, 0, 0); | |
| 322 | + configHasBeenReset = 0; | |
| 292 | 323 | db_multi_exec(zSQL2); |
| 293 | 324 | } |
| 294 | 325 | } |
| 295 | 326 | |
| 296 | 327 | /* |
| @@ -306,66 +337,390 @@ | ||
| 306 | 337 | @ DROP TABLE _xfer_user; |
| 307 | 338 | @ DROP TABLE _xfer_reportfmt; |
| 308 | 339 | ; |
| 309 | 340 | db_multi_exec(zSQL); |
| 310 | 341 | } |
| 342 | + | |
| 343 | +/* | |
| 344 | +** Return true if z[] is not a "safe" SQL token. A safe token is one of: | |
| 345 | +** | |
| 346 | +** * A string literal | |
| 347 | +** * A blob literal | |
| 348 | +** * An integer literal (no floating point) | |
| 349 | +** * NULL | |
| 350 | +*/ | |
| 351 | +static int safeSql(const char *z){ | |
| 352 | + int i; | |
| 353 | + if( z==0 || z[0]==0 ) return 0; | |
| 354 | + if( (z[0]=='x' || z[0]=='X') && z[1]=='\'' ) z++; | |
| 355 | + if( z[0]=='\'' ){ | |
| 356 | + for(i=1; z[i]; i++){ | |
| 357 | + if( z[i]=='\'' ){ | |
| 358 | + i++; | |
| 359 | + if( z[i]=='\'' ){ continue; } | |
| 360 | + return z[i]==0; | |
| 361 | + } | |
| 362 | + } | |
| 363 | + return 0; | |
| 364 | + }else{ | |
| 365 | + char c; | |
| 366 | + for(i=0; (c = z[i])!=0; i++){ | |
| 367 | + if( !fossil_isalnum(c) ) return 0; | |
| 368 | + } | |
| 369 | + } | |
| 370 | + return 1; | |
| 371 | +} | |
| 372 | + | |
| 373 | +/* | |
| 374 | +** Return true if z[] consists of nothing but digits | |
| 375 | +*/ | |
| 376 | +static int safeInt(const char *z){ | |
| 377 | + int i; | |
| 378 | + if( z==0 || z[0]==0 ) return 0; | |
| 379 | + for(i=0; fossil_isdigit(z[i]); i++){} | |
| 380 | + return z[i]==0; | |
| 381 | +} | |
| 382 | + | |
| 383 | +/* | |
| 384 | +** Process a single "config" card received from the other side of a | |
| 385 | +** sync session. | |
| 386 | +** | |
| 387 | +** Mask consists of one or more CONFIGSET_* values ORed together, to | |
| 388 | +** designate what types of configuration we are allowed to receive. | |
| 389 | +** | |
| 390 | +** NEW FORMAT: | |
| 391 | +** | |
| 392 | +** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed". | |
| 393 | +** zName indicates the table that holds the configuration information being | |
| 394 | +** transferred. pContent is a string that consist of alternating Fossil | |
| 395 | +** and SQL tokens. The First token is a timestamp in seconds since 1970. | |
| 396 | +** The second token is a primary key for the table identified by zName. If | |
| 397 | +** The entry with the corresponding primary key exists and has a more recent | |
| 398 | +** mtime, then nothing happens. If the entry does not exist or if it has | |
| 399 | +** an older mtime, then the content described by subsequent token pairs is | |
| 400 | +** inserted. The first element of each token pair is a column name and | |
| 401 | +** the second is its value. | |
| 402 | +** | |
| 403 | +** In overview, we have: | |
| 404 | +** | |
| 405 | +** NAME CONTENT | |
| 406 | +** ------- ----------------------------------------------------------- | |
| 407 | +** /config $MTIME $NAME value $VALUE | |
| 408 | +** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE | |
| 409 | +** /shun $MTIME $UUID scom $VALUE | |
| 410 | +** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE | |
| 411 | +** /concealed $MTIME $HASH content $VALUE | |
| 412 | +** | |
| 413 | +** OLD FORMAT: | |
| 414 | +** | |
| 415 | +** The old format is retained for backwards compatiblity, but is deprecated. | |
| 416 | +** The cutover from old format to new was on 2011-04-25. After sufficient | |
| 417 | +** time has passed, support for the old format will be removed. | |
| 418 | +** | |
| 419 | +** zName is either the NAME of an element of the CONFIG table, or else | |
| 420 | +** one of the special names "@shun", "@reportfmt", "@user", or "@concealed". | |
| 421 | +** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the | |
| 422 | +** element in the CONFIG table. For one of the @-labels, CONTENT is raw | |
| 423 | +** SQL that is evaluated. Note that the raw SQL in CONTENT might not | |
| 424 | +** insert directly into the target table but might instead use a proxy | |
| 425 | +** table like _fer_reportfmt or _xfer_user. Such tables must be created | |
| 426 | +** ahead of time using configure_prepare_to_receive(). Then after multiple | |
| 427 | +** calls to this routine, configure_finalize_receive() to transfer the | |
| 428 | +** information received into the true target table. | |
| 429 | +*/ | |
| 430 | +void configure_receive(const char *zName, Blob *pContent, int groupMask){ | |
| 431 | + if( zName[0]=='/' ){ | |
| 432 | + /* The new format */ | |
| 433 | + char *azToken[12]; | |
| 434 | + int nToken = 0; | |
| 435 | + int ii, jj; | |
| 436 | + int thisMask; | |
| 437 | + Blob name, value, sql; | |
| 438 | + static const struct receiveType { | |
| 439 | + const char *zName; | |
| 440 | + const char *zPrimKey; | |
| 441 | + int nField; | |
| 442 | + const char *azField[4]; | |
| 443 | + } aType[] = { | |
| 444 | + { "/config", "name", 1, { "value", 0, 0, 0 } }, | |
| 445 | + { "@user", "login", 4, { "pw", "cap", "info", "photo" } }, | |
| 446 | + { "@shun", "uuid", 1, { "scom", 0, 0, 0 } }, | |
| 447 | + { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } }, | |
| 448 | + { "@concealed", "hash", 1, { "content", 0, 0, 0 } }, | |
| 449 | + }; | |
| 450 | + for(ii=0; ii<count(aType); ii++){ | |
| 451 | + if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break; | |
| 452 | + } | |
| 453 | + if( ii>=count(aType) ) return; | |
| 454 | + while( blob_token(pContent, &name) && blob_sqltoken(pContent, &value) ){ | |
| 455 | + char *z = blob_terminate(&name); | |
| 456 | + if( !safeSql(z) ) return; | |
| 457 | + if( nToken>0 ){ | |
| 458 | + for(jj=0; jj<aType[ii].nField; jj++){ | |
| 459 | + if( fossil_strcmp(aType[ii].azField[jj], z)==0 ) break; | |
| 460 | + } | |
| 461 | + if( jj>=aType[ii].nField ) continue; | |
| 462 | + }else{ | |
| 463 | + if( !safeInt(z) ) return; | |
| 464 | + } | |
| 465 | + azToken[nToken++] = z; | |
| 466 | + azToken[nToken++] = z = blob_terminate(&value); | |
| 467 | + if( !safeSql(z) ) return; | |
| 468 | + if( nToken>=count(azToken) ) break; | |
| 469 | + } | |
| 470 | + if( nToken<2 ) return; | |
| 471 | + if( aType[ii].zName[0]=='/' ){ | |
| 472 | + thisMask = configure_is_exportable(azToken[1]); | |
| 473 | + }else{ | |
| 474 | + thisMask = configure_is_exportable(aType[ii].zName); | |
| 475 | + } | |
| 476 | + if( (thisMask & groupMask)==0 ) return; | |
| 477 | + | |
| 478 | + blob_zero(&sql); | |
| 479 | + if( groupMask & CONFIGSET_OVERWRITE ){ | |
| 480 | + if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){ | |
| 481 | + db_multi_exec("DELETE FROM %s", &aType[ii].zName[1]); | |
| 482 | + configHasBeenReset |= thisMask; | |
| 483 | + } | |
| 484 | + blob_append(&sql, "REPLACE INTO ", -1); | |
| 485 | + }else{ | |
| 486 | + blob_append(&sql, "INSERT OR IGNORE INTO ", -1); | |
| 487 | + } | |
| 488 | + blob_appendf(&sql, "%s(%s, mtime", &zName[1], aType[ii].zPrimKey); | |
| 489 | + for(jj=2; jj<nToken; jj+=2){ | |
| 490 | + blob_appendf(&sql, ",%s", azToken[jj]); | |
| 491 | + } | |
| 492 | + blob_appendf(&sql,") VALUES(%s,%s", azToken[1], azToken[0]); | |
| 493 | + for(jj=2; jj<nToken; jj+=2){ | |
| 494 | + blob_appendf(&sql, ",%s", azToken[jj+1]); | |
| 495 | + } | |
| 496 | + db_multi_exec("%s)", blob_str(&sql)); | |
| 497 | + if( db_changes()==0 ){ | |
| 498 | + blob_reset(&sql); | |
| 499 | + blob_appendf(&sql, "UPDATE %s SET mtime=%s", &zName[1], azToken[0]); | |
| 500 | + for(jj=2; jj<nToken; jj+=2){ | |
| 501 | + blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]); | |
| 502 | + } | |
| 503 | + blob_appendf(&sql, " WHERE %s=%s AND mtime<%s", | |
| 504 | + aType[ii].zPrimKey, azToken[1], azToken[0]); | |
| 505 | + db_multi_exec("%s", blob_str(&sql)); | |
| 506 | + } | |
| 507 | + blob_reset(&sql); | |
| 508 | + }else{ | |
| 509 | + /* Otherwise, the old format */ | |
| 510 | + if( (configure_is_exportable(zName) & groupMask)==0 ) return; | |
| 511 | + if( strcmp(zName, "logo-image")==0 ){ | |
| 512 | + Stmt ins; | |
| 513 | + db_prepare(&ins, | |
| 514 | + "REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())" | |
| 515 | + ); | |
| 516 | + db_bind_text(&ins, ":name", zName); | |
| 517 | + db_bind_blob(&ins, ":value", pContent); | |
| 518 | + db_step(&ins); | |
| 519 | + db_finalize(&ins); | |
| 520 | + }else if( zName[0]=='@' ){ | |
| 521 | + /* Notice that we are evaluating arbitrary SQL received from the | |
| 522 | + ** client. But this can only happen if the client has authenticated | |
| 523 | + ** as an administrator, so presumably we trust the client at this | |
| 524 | + ** point. | |
| 525 | + */ | |
| 526 | + db_multi_exec("%s", blob_str(pContent)); | |
| 527 | + }else{ | |
| 528 | + db_multi_exec( | |
| 529 | + "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", | |
| 530 | + zName, blob_str(pContent) | |
| 531 | + ); | |
| 532 | + } | |
| 533 | + } | |
| 534 | +} | |
| 535 | + | |
| 536 | +/* | |
| 537 | +** Process a file full of "config" cards. | |
| 538 | +*/ | |
| 539 | +void configure_receive_all(Blob *pIn, int groupMask){ | |
| 540 | + Blob line; | |
| 541 | + int nToken; | |
| 542 | + int size; | |
| 543 | + Blob aToken[4]; | |
| 544 | + | |
| 545 | + configHasBeenReset = 0; | |
| 546 | + while( blob_line(pIn, &line) ){ | |
| 547 | + if( blob_buffer(&line)[0]=='#' ) continue; | |
| 548 | + nToken = blob_tokenize(&line, aToken, count(aToken)); | |
| 549 | + if( blob_eq(&aToken[0],"config") | |
| 550 | + && nToken==3 | |
| 551 | + && blob_is_int(&aToken[2], &size) | |
| 552 | + ){ | |
| 553 | + const char *zName = blob_str(&aToken[1]); | |
| 554 | + Blob content; | |
| 555 | + blob_zero(&content); | |
| 556 | + blob_extract(pIn, size, &content); | |
| 557 | + g.okAdmin = g.okRdAddr = 1; | |
| 558 | + configure_receive(zName, &content, groupMask); | |
| 559 | + blob_reset(&content); | |
| 560 | + blob_seek(pIn, 1, BLOB_SEEK_CUR); | |
| 561 | + } | |
| 562 | + } | |
| 563 | +} | |
| 564 | + | |
| 565 | + | |
| 566 | +/* | |
| 567 | +** Send "config" cards using the new format for all elements of a group | |
| 568 | +** that have recently changed. | |
| 569 | +** | |
| 570 | +** Output goes into pOut. The groupMask identifies the group(s) to be sent. | |
| 571 | +** Send only entries whose timestamp is later than or equal to iStart. | |
| 572 | +** | |
| 573 | +** Return the number of cards sent. | |
| 574 | +*/ | |
| 575 | +int configure_send_group( | |
| 576 | + Blob *pOut, /* Write output here */ | |
| 577 | + int groupMask, /* Mask of groups to be send */ | |
| 578 | + sqlite3_int64 iStart /* Only write values changed since this time */ | |
| 579 | +){ | |
| 580 | + Stmt q; | |
| 581 | + Blob rec; | |
| 582 | + int ii; | |
| 583 | + int nCard = 0; | |
| 584 | + | |
| 585 | + blob_zero(&rec); | |
| 586 | + if( groupMask & CONFIGSET_SHUN ){ | |
| 587 | + db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun" | |
| 588 | + " WHERE mtime>=%lld", iStart); | |
| 589 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 590 | + blob_appendf(&rec,"%s %s scom %s", | |
| 591 | + db_column_text(&q, 0), | |
| 592 | + db_column_text(&q, 1), | |
| 593 | + db_column_text(&q, 2) | |
| 594 | + ); | |
| 595 | + blob_appendf(pOut, "config /shun %d\n%s\n", | |
| 596 | + blob_size(&rec), blob_str(&rec)); | |
| 597 | + nCard++; | |
| 598 | + blob_reset(&rec); | |
| 599 | + } | |
| 600 | + db_finalize(&q); | |
| 601 | + } | |
| 602 | + if( groupMask & CONFIGSET_USER ){ | |
| 603 | + db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap)," | |
| 604 | + " quote(info), quote(photo) FROM user" | |
| 605 | + " WHERE mtime>=%lld", iStart); | |
| 606 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 607 | + blob_appendf(&rec,"%s %s pw %s cap %s info %s photo %s", | |
| 608 | + db_column_text(&q, 0), | |
| 609 | + db_column_text(&q, 1), | |
| 610 | + db_column_text(&q, 2), | |
| 611 | + db_column_text(&q, 3), | |
| 612 | + db_column_text(&q, 4), | |
| 613 | + db_column_text(&q, 5) | |
| 614 | + ); | |
| 615 | + blob_appendf(pOut, "config /user %d\n%s\n", | |
| 616 | + blob_size(&rec), blob_str(&rec)); | |
| 617 | + nCard++; | |
| 618 | + blob_reset(&rec); | |
| 619 | + } | |
| 620 | + db_finalize(&q); | |
| 621 | + } | |
| 622 | + if( groupMask & CONFIGSET_TKT ){ | |
| 623 | + db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols)," | |
| 624 | + " quote(sqlcode) FROM reportfmt" | |
| 625 | + " WHERE mtime>=%lld", iStart); | |
| 626 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 627 | + blob_appendf(&rec,"%s %s owner %s cols %s sqlcode %s", | |
| 628 | + db_column_text(&q, 0), | |
| 629 | + db_column_text(&q, 1), | |
| 630 | + db_column_text(&q, 2), | |
| 631 | + db_column_text(&q, 3), | |
| 632 | + db_column_text(&q, 4) | |
| 633 | + ); | |
| 634 | + blob_appendf(pOut, "config /reportfmt %d\n%s\n", | |
| 635 | + blob_size(&rec), blob_str(&rec)); | |
| 636 | + nCard++; | |
| 637 | + blob_reset(&rec); | |
| 638 | + } | |
| 639 | + db_finalize(&q); | |
| 640 | + } | |
| 641 | + if( groupMask & CONFIGSET_ADDR ){ | |
| 642 | + db_prepare(&q, "SELECT mtime, quote(hash), quote(content) FROM concealed" | |
| 643 | + " WHERE mtime>=%lld", iStart); | |
| 644 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 645 | + blob_appendf(&rec,"%s %s content %s", | |
| 646 | + db_column_text(&q, 0), | |
| 647 | + db_column_text(&q, 1), | |
| 648 | + db_column_text(&q, 2) | |
| 649 | + ); | |
| 650 | + blob_appendf(pOut, "config /concealed %d\n%s\n", | |
| 651 | + blob_size(&rec), blob_str(&rec)); | |
| 652 | + nCard++; | |
| 653 | + blob_reset(&rec); | |
| 654 | + } | |
| 655 | + db_finalize(&q); | |
| 656 | + } | |
| 657 | + db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" | |
| 658 | + " WHERE name=:name AND mtime>=%lld", iStart); | |
| 659 | + for(ii=0; ii<count(aConfig); ii++){ | |
| 660 | + if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){ | |
| 661 | + db_bind_text(&q, ":name", aConfig[ii].zName); | |
| 662 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 663 | + blob_appendf(&rec,"%s %s value %s", | |
| 664 | + db_column_text(&q, 0), | |
| 665 | + db_column_text(&q, 1), | |
| 666 | + db_column_text(&q, 2) | |
| 667 | + ); | |
| 668 | + blob_appendf(pOut, "config /config %d\n%s\n", | |
| 669 | + blob_size(&rec), blob_str(&rec)); | |
| 670 | + nCard++; | |
| 671 | + blob_reset(&rec); | |
| 672 | + } | |
| 673 | + db_reset(&q); | |
| 674 | + } | |
| 675 | + } | |
| 676 | + db_finalize(&q); | |
| 677 | + return nCard; | |
| 678 | +} | |
| 311 | 679 | |
| 312 | 680 | /* |
| 313 | 681 | ** Identify a configuration group by name. Return its mask. |
| 314 | 682 | ** Throw an error if no match. |
| 315 | 683 | */ |
| 316 | -static int find_area(const char *z){ | |
| 684 | +int configure_name_to_mask(const char *z, int notFoundIsFatal){ | |
| 317 | 685 | int i; |
| 318 | 686 | int n = strlen(z); |
| 319 | 687 | for(i=0; i<count(aGroupName); i++){ |
| 320 | - if( strncmp(z, aGroupName[i].zName, n)==0 ){ | |
| 688 | + if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){ | |
| 321 | 689 | return aGroupName[i].groupMask; |
| 322 | 690 | } |
| 323 | 691 | } |
| 324 | - printf("Available configuration areas:\n"); | |
| 325 | - for(i=0; i<count(aGroupName); i++){ | |
| 326 | - printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp); | |
| 692 | + if( notFoundIsFatal ){ | |
| 693 | + fossil_print("Available configuration areas:\n"); | |
| 694 | + for(i=0; i<count(aGroupName); i++){ | |
| 695 | + fossil_print(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp); | |
| 696 | + } | |
| 697 | + fossil_fatal("no such configuration area: \"%s\"", z); | |
| 327 | 698 | } |
| 328 | - fossil_fatal("no such configuration area: \"%s\"", z); | |
| 329 | 699 | return 0; |
| 330 | 700 | } |
| 331 | 701 | |
| 332 | 702 | /* |
| 333 | 703 | ** Write SQL text into file zFilename that will restore the configuration |
| 334 | 704 | ** area identified by mask to its current state from any other state. |
| 335 | 705 | */ |
| 336 | 706 | static void export_config( |
| 337 | - int mask, /* Mask indicating which configuration to export */ | |
| 707 | + int groupMask, /* Mask indicating which configuration to export */ | |
| 338 | 708 | const char *zMask, /* Name of the configuration */ |
| 709 | + sqlite3_int64 iStart, /* Start date */ | |
| 339 | 710 | const char *zFilename /* Write into this file */ |
| 340 | 711 | ){ |
| 341 | - int i; | |
| 342 | 712 | Blob out; |
| 343 | 713 | blob_zero(&out); |
| 344 | - blob_appendf(&out, | |
| 345 | - "-- The \"%s\" configuration exported from\n" | |
| 346 | - "-- repository \"%s\"\n" | |
| 347 | - "-- on %s\n", | |
| 714 | + blob_appendf(&out, | |
| 715 | + "# The \"%s\" configuration exported from\n" | |
| 716 | + "# repository \"%s\"\n" | |
| 717 | + "# on %s\n", | |
| 348 | 718 | zMask, g.zRepositoryName, |
| 349 | 719 | db_text(0, "SELECT datetime('now')") |
| 350 | 720 | ); |
| 351 | - for(i=0; i<count(aConfig); i++){ | |
| 352 | - if( (aConfig[i].groupMask & mask)!=0 ){ | |
| 353 | - const char *zName = aConfig[i].zName; | |
| 354 | - if( zName[0]!='@' ){ | |
| 355 | - char *zValue = db_text(0, | |
| 356 | - "SELECT quote(value) FROM config WHERE name=%Q", zName); | |
| 357 | - if( zValue ){ | |
| 358 | - blob_appendf(&out,"REPLACE INTO config VALUES(%Q,%s);\n", | |
| 359 | - zName, zValue); | |
| 360 | - } | |
| 361 | - free(zValue); | |
| 362 | - }else{ | |
| 363 | - configure_render_special_name(zName, &out); | |
| 364 | - } | |
| 365 | - } | |
| 366 | - } | |
| 721 | + configure_send_group(&out, groupMask, iStart); | |
| 367 | 722 | blob_write_to_file(&out, zFilename); |
| 368 | 723 | blob_reset(&out); |
| 369 | 724 | } |
| 370 | 725 | |
| 371 | 726 | |
| @@ -395,25 +750,31 @@ | ||
| 395 | 750 | ** |
| 396 | 751 | ** %fossil configuration pull AREA ?URL? |
| 397 | 752 | ** |
| 398 | 753 | ** Pull and install the configuration from a different server |
| 399 | 754 | ** identified by URL. If no URL is specified, then the default |
| 400 | -** server is used. | |
| 755 | +** server is used. Use the --legacy option for the older protocol | |
| 756 | +** (when talking to servers compiled prior to 2011-04-27.) Use | |
| 757 | +** the --overwrite flag to completely replace local settings with | |
| 758 | +** content received from URL. | |
| 401 | 759 | ** |
| 402 | 760 | ** %fossil configuration push AREA ?URL? |
| 403 | 761 | ** |
| 404 | 762 | ** Push the local configuration into the remote server identified |
| 405 | 763 | ** by URL. Admin privilege is required on the remote server for |
| 406 | -** this to work. | |
| 764 | +** this to work. When the same record exists both locally and on | |
| 765 | +** the remote end, the one that was most recently changed wins. | |
| 766 | +** Use the --legacy flag when talking to holder servers. | |
| 407 | 767 | ** |
| 408 | 768 | ** %fossil configuration reset AREA |
| 409 | 769 | ** |
| 410 | 770 | ** Restore the configuration to the default. AREA as above. |
| 411 | 771 | ** |
| 412 | -** WARNING: Do not import, merge, or pull configurations from an untrusted | |
| 413 | -** source. The inbound configuration is not checked for safety and can | |
| 414 | -** introduce security vulnerabilities. | |
| 772 | +** %fossil configuration sync AREA ?URL? | |
| 773 | +** | |
| 774 | +** Synchronize configuration changes in the local repository with | |
| 775 | +** the remote repository at URL. | |
| 415 | 776 | ** |
| 416 | 777 | ** |
| 417 | 778 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 418 | 779 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 419 | 780 | ** |
| @@ -438,36 +799,59 @@ | ||
| 438 | 799 | db_find_and_open_repository(0, 0); |
| 439 | 800 | zMethod = g.argv[2]; |
| 440 | 801 | n = strlen(zMethod); |
| 441 | 802 | if( strncmp(zMethod, "export", n)==0 ){ |
| 442 | 803 | int mask; |
| 804 | + const char *zSince = find_option("since",0,1); | |
| 805 | + sqlite3_int64 iStart; | |
| 443 | 806 | if( g.argc!=5 ){ |
| 444 | 807 | usage("export AREA FILENAME"); |
| 445 | 808 | } |
| 446 | - mask = find_area(g.argv[3]); | |
| 447 | - export_config(mask, g.argv[3], g.argv[4]); | |
| 809 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 810 | + if( zSince ){ | |
| 811 | + iStart = db_multi_exec( | |
| 812 | + "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0", | |
| 813 | + zSince, zSince | |
| 814 | + ); | |
| 815 | + }else{ | |
| 816 | + iStart = 0; | |
| 817 | + } | |
| 818 | + export_config(mask, g.argv[3], iStart, g.argv[4]); | |
| 448 | 819 | }else |
| 449 | 820 | if( strncmp(zMethod, "import", n)==0 |
| 450 | 821 | || strncmp(zMethod, "merge", n)==0 ){ |
| 451 | 822 | Blob in; |
| 823 | + int groupMask; | |
| 452 | 824 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 453 | 825 | blob_read_from_file(&in, g.argv[3]); |
| 454 | 826 | db_begin_transaction(); |
| 455 | - configure_prepare_to_receive(zMethod[0]=='i'); | |
| 456 | - db_multi_exec("%s", blob_str(&in)); | |
| 457 | - configure_finalize_receive(); | |
| 827 | + if( zMethod[0]=='i' ){ | |
| 828 | + groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; | |
| 829 | + }else{ | |
| 830 | + groupMask = CONFIGSET_ALL; | |
| 831 | + } | |
| 832 | + configure_receive_all(&in, groupMask); | |
| 458 | 833 | db_end_transaction(0); |
| 459 | 834 | }else |
| 460 | - if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ | |
| 835 | + if( strncmp(zMethod, "pull", n)==0 | |
| 836 | + || strncmp(zMethod, "push", n)==0 | |
| 837 | + || strncmp(zMethod, "sync", n)==0 | |
| 838 | + ){ | |
| 461 | 839 | int mask; |
| 462 | 840 | const char *zServer; |
| 463 | 841 | const char *zPw; |
| 842 | + int legacyFlag = 0; | |
| 843 | + int overwriteFlag = 0; | |
| 844 | + if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0; | |
| 845 | + if( strncmp(zMethod,"pull",n)==0 ){ | |
| 846 | + overwriteFlag = find_option("overwrite",0,0)!=0; | |
| 847 | + } | |
| 464 | 848 | url_proxy_options(); |
| 465 | 849 | if( g.argc!=4 && g.argc!=5 ){ |
| 466 | 850 | usage("pull AREA ?URL?"); |
| 467 | 851 | } |
| 468 | - mask = find_area(g.argv[3]); | |
| 852 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 469 | 853 | if( g.argc==5 ){ |
| 470 | 854 | zServer = g.argv[4]; |
| 471 | 855 | zPw = 0; |
| 472 | 856 | g.dontKeepUrl = 1; |
| 473 | 857 | }else{ |
| @@ -479,25 +863,29 @@ | ||
| 479 | 863 | } |
| 480 | 864 | url_parse(zServer); |
| 481 | 865 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 482 | 866 | user_select(); |
| 483 | 867 | url_enable_proxy("via proxy: "); |
| 868 | + if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; | |
| 869 | + if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; | |
| 484 | 870 | if( strncmp(zMethod, "push", n)==0 ){ |
| 485 | 871 | client_sync(0,0,0,0,0,mask); |
| 486 | - }else{ | |
| 872 | + }else if( strncmp(zMethod, "pull", n)==0 ){ | |
| 487 | 873 | client_sync(0,0,0,0,mask,0); |
| 874 | + }else{ | |
| 875 | + client_sync(0,0,0,0,mask,mask); | |
| 488 | 876 | } |
| 489 | 877 | }else |
| 490 | 878 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 491 | 879 | int mask, i; |
| 492 | 880 | char *zBackup; |
| 493 | 881 | if( g.argc!=4 ) usage("reset AREA"); |
| 494 | - mask = find_area(g.argv[3]); | |
| 882 | + mask = configure_name_to_mask(g.argv[3], 1); | |
| 495 | 883 | zBackup = db_text(0, |
| 496 | 884 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 497 | 885 | db_begin_transaction(); |
| 498 | - export_config(mask, g.argv[3], zBackup); | |
| 886 | + export_config(mask, g.argv[3], 0, zBackup); | |
| 499 | 887 | for(i=0; i<count(aConfig); i++){ |
| 500 | 888 | const char *zName = aConfig[i].zName; |
| 501 | 889 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 502 | 890 | if( zName[0]!='@' ){ |
| 503 | 891 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | ||
| 511 | 899 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 512 | 900 | db_multi_exec("DELETE FROM reportfmt"); |
| 513 | 901 | } |
| 514 | 902 | } |
| 515 | 903 | db_end_transaction(0); |
| 516 | - printf("Configuration reset to factory defaults.\n"); | |
| 517 | - printf("To recover, use: %s %s import %s\n", | |
| 904 | + fossil_print("Configuration reset to factory defaults.\n"); | |
| 905 | + fossil_print("To recover, use: %s %s import %s\n", | |
| 518 | 906 | fossil_nameofexe(), g.argv[1], zBackup); |
| 519 | 907 | }else |
| 520 | 908 | { |
| 521 | 909 | fossil_fatal("METHOD should be one of:" |
| 522 | 910 | " export import merge pull push reset"); |
| 523 | 911 | } |
| 524 | 912 | } |
| 525 | 913 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code used to manage repository configurations. |
| 19 | ** By "responsitory configure" we mean the local state of a repository |
| 20 | ** distinct from the versioned files. |
| 21 | */ |
| 22 | #include "config.h" |
| 23 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | |
| 26 | #if INTERFACE |
| 27 | /* |
| 28 | ** Configuration transfers occur in groups. These are the allowed |
| 29 | ** groupings: |
| 30 | */ |
| 31 | #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ |
| 32 | #define CONFIGSET_TKT 0x000002 /* Ticket configuration */ |
| 33 | #define CONFIGSET_PROJ 0x000004 /* Project name */ |
| 34 | #define CONFIGSET_SHUN 0x000008 /* Shun settings */ |
| 35 | #define CONFIGSET_USER 0x000010 /* The USER table */ |
| 36 | #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ |
| 37 | |
| 38 | #define CONFIGSET_ALL 0xffffff /* Everything */ |
| 39 | |
| 40 | #endif /* INTERFACE */ |
| 41 | |
| 42 | /* |
| 43 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | |
| 45 | static struct { |
| 46 | const char *zName; /* Name of the configuration set */ |
| 47 | int groupMask; /* Mask for that configuration set */ |
| 48 | const char *zHelp; /* What it does */ |
| 49 | } aGroupName[] = { |
| 50 | { "email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, |
| 51 | { "project", CONFIGSET_PROJ, "Project name and description" }, |
| 52 | { "skin", CONFIGSET_SKIN, "Web interface apparance settings" }, |
| 53 | { "shun", CONFIGSET_SHUN, "List of shunned artifacts" }, |
| 54 | { "ticket", CONFIGSET_TKT, "Ticket setup", }, |
| 55 | { "user", CONFIGSET_USER, "Users and privilege settings" }, |
| 56 | { "all", CONFIGSET_ALL, "All of the above" }, |
| 57 | }; |
| 58 | |
| 59 | |
| 60 | /* |
| 61 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | |
| 105 | const char *configure_first_name(int iMask){ |
| 106 | iConfig = 0; |
| 107 | return configure_next_name(iMask); |
| 108 | } |
| 109 | const char *configure_next_name(int iMask){ |
| 110 | while( iConfig<count(aConfig) ){ |
| 111 | if( aConfig[iConfig].groupMask & iMask ){ |
| 112 | return aConfig[iConfig++].zName; |
| 113 | }else{ |
| 114 | iConfig++; |
| 115 | } |
| 116 | } |
| 117 | return 0; |
| 118 | } |
| 119 | |
| 120 | /* |
| 121 | ** Return the mask for the named configuration parameter if it can be |
| 122 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 123 | */ |
| 124 | int configure_is_exportable(const char *zName){ |
| 125 | int i; |
| 126 | for(i=0; i<count(aConfig); i++){ |
| 127 | if( fossil_strcmp(zName, aConfig[i].zName)==0 ){ |
| 128 | int m = aConfig[i].groupMask; |
| 129 | if( !g.okAdmin ){ |
| 130 | m &= ~CONFIGSET_USER; |
| 131 | } |
| 132 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | |
| 194 | } |
| 195 | |
| 196 | /* |
| 197 | ** Two SQL functions: |
| 198 | ** |
| 199 | ** flag_test(int) |
| 200 | ** flag_clear(int) |
| 201 | ** |
| 202 | ** The flag_test() function takes the integer valued argument and |
| 203 | ** ANDs it against the static variable "flag_value" below. The |
| 204 | ** function returns TRUE or false depending on the result. The |
| 205 | ** flag_clear() function masks off the bits from "flag_value" that |
| 206 | ** are given in the argument. |
| 207 | ** |
| 208 | ** These functions are used below in the WHEN clause of a trigger to |
| 209 | ** get the trigger to fire exactly once. |
| 210 | */ |
| 211 | static int flag_value = 0xffff; |
| 212 | static void flag_test_function( |
| 213 | sqlite3_context *context, |
| 214 | int argc, |
| 215 | sqlite3_value **argv |
| 216 | ){ |
| 217 | int m = sqlite3_value_int(argv[0]); |
| 218 | sqlite3_result_int(context, (flag_value&m)!=0 ); |
| 219 | } |
| 220 | static void flag_clear_function( |
| 221 | sqlite3_context *context, |
| 222 | int argc, |
| 223 | sqlite3_value **argv |
| 224 | ){ |
| 225 | int m = sqlite3_value_int(argv[0]); |
| 226 | flag_value &= ~m; |
| 227 | } |
| 228 | |
| 229 | /* |
| 230 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 231 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | |
| 255 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 256 | @ cexpire DATETIME, -- Time when cookie expires |
| 257 | @ info TEXT, -- contact information |
| 258 | @ photo BLOB -- JPEG image of this user |
| 259 | @ ); |
| 260 | @ INSERT INTO _xfer_reportfmt SELECT * FROM reportfmt; |
| 261 | @ INSERT INTO _xfer_user SELECT * FROM user; |
| 262 | ; |
| 263 | db_multi_exec(zSQL1); |
| 264 | |
| 265 | /* When the replace flag is set, add triggers that run the first time |
| 266 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | |
| 267 | ** existing data. |
| 268 | */ |
| 269 | if( replaceFlag ){ |
| 270 | static const char zSQL2[] = |
| 271 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 272 | @ WHEN flag_test(1) BEGIN |
| 273 | @ DELETE FROM _xfer_reportfmt; |
| 274 | @ SELECT flag_clear(1); |
| 275 | @ END; |
| 276 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 277 | @ WHEN flag_test(2) BEGIN |
| 278 | @ DELETE FROM _xfer_user; |
| 279 | @ SELECT flag_clear(2); |
| 280 | @ END; |
| 281 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 282 | @ WHEN flag_test(4) BEGIN |
| 283 | @ DELETE FROM shun; |
| 284 | @ SELECT flag_clear(4); |
| 285 | @ END; |
| 286 | ; |
| 287 | sqlite3_create_function(g.db, "flag_test", 1, SQLITE_UTF8, 0, |
| 288 | flag_test_function, 0, 0); |
| 289 | sqlite3_create_function(g.db, "flag_clear", 1, SQLITE_UTF8, 0, |
| 290 | flag_clear_function, 0, 0); |
| 291 | flag_value = 0xffff; |
| 292 | db_multi_exec(zSQL2); |
| 293 | } |
| 294 | } |
| 295 | |
| 296 | /* |
| @@ -306,66 +337,390 @@ | |
| 306 | @ DROP TABLE _xfer_user; |
| 307 | @ DROP TABLE _xfer_reportfmt; |
| 308 | ; |
| 309 | db_multi_exec(zSQL); |
| 310 | } |
| 311 | |
| 312 | /* |
| 313 | ** Identify a configuration group by name. Return its mask. |
| 314 | ** Throw an error if no match. |
| 315 | */ |
| 316 | static int find_area(const char *z){ |
| 317 | int i; |
| 318 | int n = strlen(z); |
| 319 | for(i=0; i<count(aGroupName); i++){ |
| 320 | if( strncmp(z, aGroupName[i].zName, n)==0 ){ |
| 321 | return aGroupName[i].groupMask; |
| 322 | } |
| 323 | } |
| 324 | printf("Available configuration areas:\n"); |
| 325 | for(i=0; i<count(aGroupName); i++){ |
| 326 | printf(" %-10s %s\n", aGroupName[i].zName, aGroupName[i].zHelp); |
| 327 | } |
| 328 | fossil_fatal("no such configuration area: \"%s\"", z); |
| 329 | return 0; |
| 330 | } |
| 331 | |
| 332 | /* |
| 333 | ** Write SQL text into file zFilename that will restore the configuration |
| 334 | ** area identified by mask to its current state from any other state. |
| 335 | */ |
| 336 | static void export_config( |
| 337 | int mask, /* Mask indicating which configuration to export */ |
| 338 | const char *zMask, /* Name of the configuration */ |
| 339 | const char *zFilename /* Write into this file */ |
| 340 | ){ |
| 341 | int i; |
| 342 | Blob out; |
| 343 | blob_zero(&out); |
| 344 | blob_appendf(&out, |
| 345 | "-- The \"%s\" configuration exported from\n" |
| 346 | "-- repository \"%s\"\n" |
| 347 | "-- on %s\n", |
| 348 | zMask, g.zRepositoryName, |
| 349 | db_text(0, "SELECT datetime('now')") |
| 350 | ); |
| 351 | for(i=0; i<count(aConfig); i++){ |
| 352 | if( (aConfig[i].groupMask & mask)!=0 ){ |
| 353 | const char *zName = aConfig[i].zName; |
| 354 | if( zName[0]!='@' ){ |
| 355 | char *zValue = db_text(0, |
| 356 | "SELECT quote(value) FROM config WHERE name=%Q", zName); |
| 357 | if( zValue ){ |
| 358 | blob_appendf(&out,"REPLACE INTO config VALUES(%Q,%s);\n", |
| 359 | zName, zValue); |
| 360 | } |
| 361 | free(zValue); |
| 362 | }else{ |
| 363 | configure_render_special_name(zName, &out); |
| 364 | } |
| 365 | } |
| 366 | } |
| 367 | blob_write_to_file(&out, zFilename); |
| 368 | blob_reset(&out); |
| 369 | } |
| 370 | |
| 371 | |
| @@ -395,25 +750,31 @@ | |
| 395 | ** |
| 396 | ** %fossil configuration pull AREA ?URL? |
| 397 | ** |
| 398 | ** Pull and install the configuration from a different server |
| 399 | ** identified by URL. If no URL is specified, then the default |
| 400 | ** server is used. |
| 401 | ** |
| 402 | ** %fossil configuration push AREA ?URL? |
| 403 | ** |
| 404 | ** Push the local configuration into the remote server identified |
| 405 | ** by URL. Admin privilege is required on the remote server for |
| 406 | ** this to work. |
| 407 | ** |
| 408 | ** %fossil configuration reset AREA |
| 409 | ** |
| 410 | ** Restore the configuration to the default. AREA as above. |
| 411 | ** |
| 412 | ** WARNING: Do not import, merge, or pull configurations from an untrusted |
| 413 | ** source. The inbound configuration is not checked for safety and can |
| 414 | ** introduce security vulnerabilities. |
| 415 | ** |
| 416 | ** |
| 417 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 418 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 419 | ** |
| @@ -438,36 +799,59 @@ | |
| 438 | db_find_and_open_repository(0, 0); |
| 439 | zMethod = g.argv[2]; |
| 440 | n = strlen(zMethod); |
| 441 | if( strncmp(zMethod, "export", n)==0 ){ |
| 442 | int mask; |
| 443 | if( g.argc!=5 ){ |
| 444 | usage("export AREA FILENAME"); |
| 445 | } |
| 446 | mask = find_area(g.argv[3]); |
| 447 | export_config(mask, g.argv[3], g.argv[4]); |
| 448 | }else |
| 449 | if( strncmp(zMethod, "import", n)==0 |
| 450 | || strncmp(zMethod, "merge", n)==0 ){ |
| 451 | Blob in; |
| 452 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 453 | blob_read_from_file(&in, g.argv[3]); |
| 454 | db_begin_transaction(); |
| 455 | configure_prepare_to_receive(zMethod[0]=='i'); |
| 456 | db_multi_exec("%s", blob_str(&in)); |
| 457 | configure_finalize_receive(); |
| 458 | db_end_transaction(0); |
| 459 | }else |
| 460 | if( strncmp(zMethod, "pull", n)==0 || strncmp(zMethod, "push", n)==0 ){ |
| 461 | int mask; |
| 462 | const char *zServer; |
| 463 | const char *zPw; |
| 464 | url_proxy_options(); |
| 465 | if( g.argc!=4 && g.argc!=5 ){ |
| 466 | usage("pull AREA ?URL?"); |
| 467 | } |
| 468 | mask = find_area(g.argv[3]); |
| 469 | if( g.argc==5 ){ |
| 470 | zServer = g.argv[4]; |
| 471 | zPw = 0; |
| 472 | g.dontKeepUrl = 1; |
| 473 | }else{ |
| @@ -479,25 +863,29 @@ | |
| 479 | } |
| 480 | url_parse(zServer); |
| 481 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 482 | user_select(); |
| 483 | url_enable_proxy("via proxy: "); |
| 484 | if( strncmp(zMethod, "push", n)==0 ){ |
| 485 | client_sync(0,0,0,0,0,mask); |
| 486 | }else{ |
| 487 | client_sync(0,0,0,0,mask,0); |
| 488 | } |
| 489 | }else |
| 490 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 491 | int mask, i; |
| 492 | char *zBackup; |
| 493 | if( g.argc!=4 ) usage("reset AREA"); |
| 494 | mask = find_area(g.argv[3]); |
| 495 | zBackup = db_text(0, |
| 496 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 497 | db_begin_transaction(); |
| 498 | export_config(mask, g.argv[3], zBackup); |
| 499 | for(i=0; i<count(aConfig); i++){ |
| 500 | const char *zName = aConfig[i].zName; |
| 501 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 502 | if( zName[0]!='@' ){ |
| 503 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | |
| 511 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 512 | db_multi_exec("DELETE FROM reportfmt"); |
| 513 | } |
| 514 | } |
| 515 | db_end_transaction(0); |
| 516 | printf("Configuration reset to factory defaults.\n"); |
| 517 | printf("To recover, use: %s %s import %s\n", |
| 518 | fossil_nameofexe(), g.argv[1], zBackup); |
| 519 | }else |
| 520 | { |
| 521 | fossil_fatal("METHOD should be one of:" |
| 522 | " export import merge pull push reset"); |
| 523 | } |
| 524 | } |
| 525 |
| --- src/configure.c | |
| +++ src/configure.c | |
| @@ -2,11 +2,11 @@ | |
| 2 | ** Copyright (c) 2008 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | ** |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| @@ -14,10 +14,11 @@ | |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code used to manage repository configurations. |
| 19 | ** |
| 20 | ** By "responsitory configure" we mean the local state of a repository |
| 21 | ** distinct from the versioned files. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #include "configure.h" |
| @@ -26,18 +27,21 @@ | |
| 27 | #if INTERFACE |
| 28 | /* |
| 29 | ** Configuration transfers occur in groups. These are the allowed |
| 30 | ** groupings: |
| 31 | */ |
| 32 | #define CONFIGSET_SKIN 0x000001 /* WWW interface appearance */ |
| 33 | #define CONFIGSET_TKT 0x000002 /* Ticket configuration */ |
| 34 | #define CONFIGSET_PROJ 0x000004 /* Project name */ |
| 35 | #define CONFIGSET_SHUN 0x000008 /* Shun settings */ |
| 36 | #define CONFIGSET_USER 0x000010 /* The USER table */ |
| 37 | #define CONFIGSET_ADDR 0x000020 /* The CONCEALED table */ |
| 38 | |
| 39 | #define CONFIGSET_ALL 0x0000ff /* Everything */ |
| 40 | |
| 41 | #define CONFIGSET_OVERWRITE 0x100000 /* Causes overwrite instead of merge */ |
| 42 | #define CONFIGSET_OLDFORMAT 0x200000 /* Use the legacy format */ |
| 43 | |
| 44 | #endif /* INTERFACE */ |
| 45 | |
| 46 | /* |
| 47 | ** Names of the configuration sets |
| @@ -45,17 +49,17 @@ | |
| 49 | static struct { |
| 50 | const char *zName; /* Name of the configuration set */ |
| 51 | int groupMask; /* Mask for that configuration set */ |
| 52 | const char *zHelp; /* What it does */ |
| 53 | } aGroupName[] = { |
| 54 | { "/email", CONFIGSET_ADDR, "Concealed email addresses in tickets" }, |
| 55 | { "/project", CONFIGSET_PROJ, "Project name and description" }, |
| 56 | { "/skin", CONFIGSET_SKIN, "Web interface apparance settings" }, |
| 57 | { "/shun", CONFIGSET_SHUN, "List of shunned artifacts" }, |
| 58 | { "/ticket", CONFIGSET_TKT, "Ticket setup", }, |
| 59 | { "/user", CONFIGSET_USER, "Users and privilege settings" }, |
| 60 | { "/all", CONFIGSET_ALL, "All of the above" }, |
| 61 | }; |
| 62 | |
| 63 | |
| 64 | /* |
| 65 | ** The following is a list of settings that we are willing to |
| @@ -105,28 +109,52 @@ | |
| 109 | const char *configure_first_name(int iMask){ |
| 110 | iConfig = 0; |
| 111 | return configure_next_name(iMask); |
| 112 | } |
| 113 | const char *configure_next_name(int iMask){ |
| 114 | if( iMask & CONFIGSET_OLDFORMAT ){ |
| 115 | while( iConfig<count(aConfig) ){ |
| 116 | if( aConfig[iConfig].groupMask & iMask ){ |
| 117 | return aConfig[iConfig++].zName; |
| 118 | }else{ |
| 119 | iConfig++; |
| 120 | } |
| 121 | } |
| 122 | }else{ |
| 123 | if( iConfig==0 && (iMask & CONFIGSET_ALL)==CONFIGSET_ALL ){ |
| 124 | iConfig = count(aGroupName); |
| 125 | return "/all"; |
| 126 | } |
| 127 | while( iConfig<count(aGroupName)-1 ){ |
| 128 | if( aGroupName[iConfig].groupMask & iMask ){ |
| 129 | return aGroupName[iConfig++].zName; |
| 130 | }else{ |
| 131 | iConfig++; |
| 132 | } |
| 133 | } |
| 134 | } |
| 135 | return 0; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ** Return the mask for the named configuration parameter if it can be |
| 140 | ** safely exported. Return 0 if the parameter is not safe to export. |
| 141 | ** |
| 142 | ** "Safe" in the previous paragraph means the permission is created to |
| 143 | ** export the property. In other words, the requesting side has presented |
| 144 | ** login credentials and has sufficient capabilities to access the requested |
| 145 | ** information. |
| 146 | */ |
| 147 | int configure_is_exportable(const char *zName){ |
| 148 | int i; |
| 149 | int n = strlen(zName); |
| 150 | if( n>2 && zName[0]=='\'' && zName[n-1]=='\'' ){ |
| 151 | zName++; |
| 152 | n -= 2; |
| 153 | } |
| 154 | for(i=0; i<count(aConfig); i++){ |
| 155 | if( memcmp(zName, aConfig[i].zName, n)==0 && aConfig[i].zName[n]==0 ){ |
| 156 | int m = aConfig[i].groupMask; |
| 157 | if( !g.okAdmin ){ |
| 158 | m &= ~CONFIGSET_USER; |
| 159 | } |
| 160 | if( !g.okRdAddr ){ |
| @@ -194,38 +222,39 @@ | |
| 222 | } |
| 223 | |
| 224 | /* |
| 225 | ** Two SQL functions: |
| 226 | ** |
| 227 | ** config_is_reset(int) |
| 228 | ** config_reset(int) |
| 229 | ** |
| 230 | ** The config_is_reset() function takes the integer valued argument and |
| 231 | ** ANDs it against the static variable "configHasBeenReset" below. The |
| 232 | ** function returns TRUE or FALSE depending on the result depending on |
| 233 | ** whether or not the corresponding configuration table has been reset. The |
| 234 | ** config_reset() function adds the bits to "configHasBeenReset" that |
| 235 | ** are given in the argument. |
| 236 | ** |
| 237 | ** These functions are used below in the WHEN clause of a trigger to |
| 238 | ** get the trigger to fire exactly once. |
| 239 | */ |
| 240 | static int configHasBeenReset = 0; |
| 241 | static void config_is_reset_function( |
| 242 | sqlite3_context *context, |
| 243 | int argc, |
| 244 | sqlite3_value **argv |
| 245 | ){ |
| 246 | int m = sqlite3_value_int(argv[0]); |
| 247 | sqlite3_result_int(context, (configHasBeenReset&m)!=0 ); |
| 248 | } |
| 249 | static void config_reset_function( |
| 250 | sqlite3_context *context, |
| 251 | int argc, |
| 252 | sqlite3_value **argv |
| 253 | ){ |
| 254 | int m = sqlite3_value_int(argv[0]); |
| 255 | configHasBeenReset |= m; |
| 256 | } |
| 257 | |
| 258 | /* |
| 259 | ** Create the temporary _xfer_reportfmt and _xfer_user tables that are |
| 260 | ** necessary in order to evalute the SQL text generated by the |
| @@ -255,12 +284,14 @@ | |
| 284 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 285 | @ cexpire DATETIME, -- Time when cookie expires |
| 286 | @ info TEXT, -- contact information |
| 287 | @ photo BLOB -- JPEG image of this user |
| 288 | @ ); |
| 289 | @ INSERT INTO _xfer_reportfmt |
| 290 | @ SELECT rn,owner,title,cols,sqlcode FROM reportfmt; |
| 291 | @ INSERT INTO _xfer_user |
| 292 | @ SELECT uid,login,pw,cap,cookie,ipaddr,cexpire,info,photo FROM user; |
| 293 | ; |
| 294 | db_multi_exec(zSQL1); |
| 295 | |
| 296 | /* When the replace flag is set, add triggers that run the first time |
| 297 | ** that new data is seen. The triggers run only once and delete all the |
| @@ -267,30 +298,30 @@ | |
| 298 | ** existing data. |
| 299 | */ |
| 300 | if( replaceFlag ){ |
| 301 | static const char zSQL2[] = |
| 302 | @ CREATE TRIGGER _xfer_r1 BEFORE INSERT ON _xfer_reportfmt |
| 303 | @ WHEN NOT config_is_reset(2) BEGIN |
| 304 | @ DELETE FROM _xfer_reportfmt; |
| 305 | @ SELECT config_reset(2); |
| 306 | @ END; |
| 307 | @ CREATE TRIGGER _xfer_r2 BEFORE INSERT ON _xfer_user |
| 308 | @ WHEN NOT config_is_reset(16) BEGIN |
| 309 | @ DELETE FROM _xfer_user; |
| 310 | @ SELECT config_reset(16); |
| 311 | @ END; |
| 312 | @ CREATE TEMP TRIGGER _xfer_r3 BEFORE INSERT ON shun |
| 313 | @ WHEN NOT config_is_reset(8) BEGIN |
| 314 | @ DELETE FROM shun; |
| 315 | @ SELECT config_reset(8); |
| 316 | @ END; |
| 317 | ; |
| 318 | sqlite3_create_function(g.db, "config_is_reset", 1, SQLITE_UTF8, 0, |
| 319 | config_is_reset_function, 0, 0); |
| 320 | sqlite3_create_function(g.db, "config_reset", 1, SQLITE_UTF8, 0, |
| 321 | config_reset_function, 0, 0); |
| 322 | configHasBeenReset = 0; |
| 323 | db_multi_exec(zSQL2); |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | /* |
| @@ -306,66 +337,390 @@ | |
| 337 | @ DROP TABLE _xfer_user; |
| 338 | @ DROP TABLE _xfer_reportfmt; |
| 339 | ; |
| 340 | db_multi_exec(zSQL); |
| 341 | } |
| 342 | |
| 343 | /* |
| 344 | ** Return true if z[] is not a "safe" SQL token. A safe token is one of: |
| 345 | ** |
| 346 | ** * A string literal |
| 347 | ** * A blob literal |
| 348 | ** * An integer literal (no floating point) |
| 349 | ** * NULL |
| 350 | */ |
| 351 | static int safeSql(const char *z){ |
| 352 | int i; |
| 353 | if( z==0 || z[0]==0 ) return 0; |
| 354 | if( (z[0]=='x' || z[0]=='X') && z[1]=='\'' ) z++; |
| 355 | if( z[0]=='\'' ){ |
| 356 | for(i=1; z[i]; i++){ |
| 357 | if( z[i]=='\'' ){ |
| 358 | i++; |
| 359 | if( z[i]=='\'' ){ continue; } |
| 360 | return z[i]==0; |
| 361 | } |
| 362 | } |
| 363 | return 0; |
| 364 | }else{ |
| 365 | char c; |
| 366 | for(i=0; (c = z[i])!=0; i++){ |
| 367 | if( !fossil_isalnum(c) ) return 0; |
| 368 | } |
| 369 | } |
| 370 | return 1; |
| 371 | } |
| 372 | |
| 373 | /* |
| 374 | ** Return true if z[] consists of nothing but digits |
| 375 | */ |
| 376 | static int safeInt(const char *z){ |
| 377 | int i; |
| 378 | if( z==0 || z[0]==0 ) return 0; |
| 379 | for(i=0; fossil_isdigit(z[i]); i++){} |
| 380 | return z[i]==0; |
| 381 | } |
| 382 | |
| 383 | /* |
| 384 | ** Process a single "config" card received from the other side of a |
| 385 | ** sync session. |
| 386 | ** |
| 387 | ** Mask consists of one or more CONFIGSET_* values ORed together, to |
| 388 | ** designate what types of configuration we are allowed to receive. |
| 389 | ** |
| 390 | ** NEW FORMAT: |
| 391 | ** |
| 392 | ** zName is one of "/config", "/user", "/shun", "/reportfmt", or "/concealed". |
| 393 | ** zName indicates the table that holds the configuration information being |
| 394 | ** transferred. pContent is a string that consist of alternating Fossil |
| 395 | ** and SQL tokens. The First token is a timestamp in seconds since 1970. |
| 396 | ** The second token is a primary key for the table identified by zName. If |
| 397 | ** The entry with the corresponding primary key exists and has a more recent |
| 398 | ** mtime, then nothing happens. If the entry does not exist or if it has |
| 399 | ** an older mtime, then the content described by subsequent token pairs is |
| 400 | ** inserted. The first element of each token pair is a column name and |
| 401 | ** the second is its value. |
| 402 | ** |
| 403 | ** In overview, we have: |
| 404 | ** |
| 405 | ** NAME CONTENT |
| 406 | ** ------- ----------------------------------------------------------- |
| 407 | ** /config $MTIME $NAME value $VALUE |
| 408 | ** /user $MTIME $LOGIN pw $VALUE cap $VALUE info $VALUE photo $VALUE |
| 409 | ** /shun $MTIME $UUID scom $VALUE |
| 410 | ** /reportfmt $MTIME $TITLE owner $VALUE cols $VALUE sqlcode $VALUE |
| 411 | ** /concealed $MTIME $HASH content $VALUE |
| 412 | ** |
| 413 | ** OLD FORMAT: |
| 414 | ** |
| 415 | ** The old format is retained for backwards compatiblity, but is deprecated. |
| 416 | ** The cutover from old format to new was on 2011-04-25. After sufficient |
| 417 | ** time has passed, support for the old format will be removed. |
| 418 | ** |
| 419 | ** zName is either the NAME of an element of the CONFIG table, or else |
| 420 | ** one of the special names "@shun", "@reportfmt", "@user", or "@concealed". |
| 421 | ** If zName is a CONFIG table name, then CONTENT replaces (overwrites) the |
| 422 | ** element in the CONFIG table. For one of the @-labels, CONTENT is raw |
| 423 | ** SQL that is evaluated. Note that the raw SQL in CONTENT might not |
| 424 | ** insert directly into the target table but might instead use a proxy |
| 425 | ** table like _fer_reportfmt or _xfer_user. Such tables must be created |
| 426 | ** ahead of time using configure_prepare_to_receive(). Then after multiple |
| 427 | ** calls to this routine, configure_finalize_receive() to transfer the |
| 428 | ** information received into the true target table. |
| 429 | */ |
| 430 | void configure_receive(const char *zName, Blob *pContent, int groupMask){ |
| 431 | if( zName[0]=='/' ){ |
| 432 | /* The new format */ |
| 433 | char *azToken[12]; |
| 434 | int nToken = 0; |
| 435 | int ii, jj; |
| 436 | int thisMask; |
| 437 | Blob name, value, sql; |
| 438 | static const struct receiveType { |
| 439 | const char *zName; |
| 440 | const char *zPrimKey; |
| 441 | int nField; |
| 442 | const char *azField[4]; |
| 443 | } aType[] = { |
| 444 | { "/config", "name", 1, { "value", 0, 0, 0 } }, |
| 445 | { "@user", "login", 4, { "pw", "cap", "info", "photo" } }, |
| 446 | { "@shun", "uuid", 1, { "scom", 0, 0, 0 } }, |
| 447 | { "@reportfmt", "title", 3, { "owner", "cols", "sqlcode", 0 } }, |
| 448 | { "@concealed", "hash", 1, { "content", 0, 0, 0 } }, |
| 449 | }; |
| 450 | for(ii=0; ii<count(aType); ii++){ |
| 451 | if( fossil_strcmp(&aType[ii].zName[1],&zName[1])==0 ) break; |
| 452 | } |
| 453 | if( ii>=count(aType) ) return; |
| 454 | while( blob_token(pContent, &name) && blob_sqltoken(pContent, &value) ){ |
| 455 | char *z = blob_terminate(&name); |
| 456 | if( !safeSql(z) ) return; |
| 457 | if( nToken>0 ){ |
| 458 | for(jj=0; jj<aType[ii].nField; jj++){ |
| 459 | if( fossil_strcmp(aType[ii].azField[jj], z)==0 ) break; |
| 460 | } |
| 461 | if( jj>=aType[ii].nField ) continue; |
| 462 | }else{ |
| 463 | if( !safeInt(z) ) return; |
| 464 | } |
| 465 | azToken[nToken++] = z; |
| 466 | azToken[nToken++] = z = blob_terminate(&value); |
| 467 | if( !safeSql(z) ) return; |
| 468 | if( nToken>=count(azToken) ) break; |
| 469 | } |
| 470 | if( nToken<2 ) return; |
| 471 | if( aType[ii].zName[0]=='/' ){ |
| 472 | thisMask = configure_is_exportable(azToken[1]); |
| 473 | }else{ |
| 474 | thisMask = configure_is_exportable(aType[ii].zName); |
| 475 | } |
| 476 | if( (thisMask & groupMask)==0 ) return; |
| 477 | |
| 478 | blob_zero(&sql); |
| 479 | if( groupMask & CONFIGSET_OVERWRITE ){ |
| 480 | if( (thisMask & configHasBeenReset)==0 && aType[ii].zName[0]!='/' ){ |
| 481 | db_multi_exec("DELETE FROM %s", &aType[ii].zName[1]); |
| 482 | configHasBeenReset |= thisMask; |
| 483 | } |
| 484 | blob_append(&sql, "REPLACE INTO ", -1); |
| 485 | }else{ |
| 486 | blob_append(&sql, "INSERT OR IGNORE INTO ", -1); |
| 487 | } |
| 488 | blob_appendf(&sql, "%s(%s, mtime", &zName[1], aType[ii].zPrimKey); |
| 489 | for(jj=2; jj<nToken; jj+=2){ |
| 490 | blob_appendf(&sql, ",%s", azToken[jj]); |
| 491 | } |
| 492 | blob_appendf(&sql,") VALUES(%s,%s", azToken[1], azToken[0]); |
| 493 | for(jj=2; jj<nToken; jj+=2){ |
| 494 | blob_appendf(&sql, ",%s", azToken[jj+1]); |
| 495 | } |
| 496 | db_multi_exec("%s)", blob_str(&sql)); |
| 497 | if( db_changes()==0 ){ |
| 498 | blob_reset(&sql); |
| 499 | blob_appendf(&sql, "UPDATE %s SET mtime=%s", &zName[1], azToken[0]); |
| 500 | for(jj=2; jj<nToken; jj+=2){ |
| 501 | blob_appendf(&sql, ", %s=%s", azToken[jj], azToken[jj+1]); |
| 502 | } |
| 503 | blob_appendf(&sql, " WHERE %s=%s AND mtime<%s", |
| 504 | aType[ii].zPrimKey, azToken[1], azToken[0]); |
| 505 | db_multi_exec("%s", blob_str(&sql)); |
| 506 | } |
| 507 | blob_reset(&sql); |
| 508 | }else{ |
| 509 | /* Otherwise, the old format */ |
| 510 | if( (configure_is_exportable(zName) & groupMask)==0 ) return; |
| 511 | if( strcmp(zName, "logo-image")==0 ){ |
| 512 | Stmt ins; |
| 513 | db_prepare(&ins, |
| 514 | "REPLACE INTO config(name, value, mtime) VALUES(:name, :value, now())" |
| 515 | ); |
| 516 | db_bind_text(&ins, ":name", zName); |
| 517 | db_bind_blob(&ins, ":value", pContent); |
| 518 | db_step(&ins); |
| 519 | db_finalize(&ins); |
| 520 | }else if( zName[0]=='@' ){ |
| 521 | /* Notice that we are evaluating arbitrary SQL received from the |
| 522 | ** client. But this can only happen if the client has authenticated |
| 523 | ** as an administrator, so presumably we trust the client at this |
| 524 | ** point. |
| 525 | */ |
| 526 | db_multi_exec("%s", blob_str(pContent)); |
| 527 | }else{ |
| 528 | db_multi_exec( |
| 529 | "REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", |
| 530 | zName, blob_str(pContent) |
| 531 | ); |
| 532 | } |
| 533 | } |
| 534 | } |
| 535 | |
| 536 | /* |
| 537 | ** Process a file full of "config" cards. |
| 538 | */ |
| 539 | void configure_receive_all(Blob *pIn, int groupMask){ |
| 540 | Blob line; |
| 541 | int nToken; |
| 542 | int size; |
| 543 | Blob aToken[4]; |
| 544 | |
| 545 | configHasBeenReset = 0; |
| 546 | while( blob_line(pIn, &line) ){ |
| 547 | if( blob_buffer(&line)[0]=='#' ) continue; |
| 548 | nToken = blob_tokenize(&line, aToken, count(aToken)); |
| 549 | if( blob_eq(&aToken[0],"config") |
| 550 | && nToken==3 |
| 551 | && blob_is_int(&aToken[2], &size) |
| 552 | ){ |
| 553 | const char *zName = blob_str(&aToken[1]); |
| 554 | Blob content; |
| 555 | blob_zero(&content); |
| 556 | blob_extract(pIn, size, &content); |
| 557 | g.okAdmin = g.okRdAddr = 1; |
| 558 | configure_receive(zName, &content, groupMask); |
| 559 | blob_reset(&content); |
| 560 | blob_seek(pIn, 1, BLOB_SEEK_CUR); |
| 561 | } |
| 562 | } |
| 563 | } |
| 564 | |
| 565 | |
| 566 | /* |
| 567 | ** Send "config" cards using the new format for all elements of a group |
| 568 | ** that have recently changed. |
| 569 | ** |
| 570 | ** Output goes into pOut. The groupMask identifies the group(s) to be sent. |
| 571 | ** Send only entries whose timestamp is later than or equal to iStart. |
| 572 | ** |
| 573 | ** Return the number of cards sent. |
| 574 | */ |
| 575 | int configure_send_group( |
| 576 | Blob *pOut, /* Write output here */ |
| 577 | int groupMask, /* Mask of groups to be send */ |
| 578 | sqlite3_int64 iStart /* Only write values changed since this time */ |
| 579 | ){ |
| 580 | Stmt q; |
| 581 | Blob rec; |
| 582 | int ii; |
| 583 | int nCard = 0; |
| 584 | |
| 585 | blob_zero(&rec); |
| 586 | if( groupMask & CONFIGSET_SHUN ){ |
| 587 | db_prepare(&q, "SELECT mtime, quote(uuid), quote(scom) FROM shun" |
| 588 | " WHERE mtime>=%lld", iStart); |
| 589 | while( db_step(&q)==SQLITE_ROW ){ |
| 590 | blob_appendf(&rec,"%s %s scom %s", |
| 591 | db_column_text(&q, 0), |
| 592 | db_column_text(&q, 1), |
| 593 | db_column_text(&q, 2) |
| 594 | ); |
| 595 | blob_appendf(pOut, "config /shun %d\n%s\n", |
| 596 | blob_size(&rec), blob_str(&rec)); |
| 597 | nCard++; |
| 598 | blob_reset(&rec); |
| 599 | } |
| 600 | db_finalize(&q); |
| 601 | } |
| 602 | if( groupMask & CONFIGSET_USER ){ |
| 603 | db_prepare(&q, "SELECT mtime, quote(login), quote(pw), quote(cap)," |
| 604 | " quote(info), quote(photo) FROM user" |
| 605 | " WHERE mtime>=%lld", iStart); |
| 606 | while( db_step(&q)==SQLITE_ROW ){ |
| 607 | blob_appendf(&rec,"%s %s pw %s cap %s info %s photo %s", |
| 608 | db_column_text(&q, 0), |
| 609 | db_column_text(&q, 1), |
| 610 | db_column_text(&q, 2), |
| 611 | db_column_text(&q, 3), |
| 612 | db_column_text(&q, 4), |
| 613 | db_column_text(&q, 5) |
| 614 | ); |
| 615 | blob_appendf(pOut, "config /user %d\n%s\n", |
| 616 | blob_size(&rec), blob_str(&rec)); |
| 617 | nCard++; |
| 618 | blob_reset(&rec); |
| 619 | } |
| 620 | db_finalize(&q); |
| 621 | } |
| 622 | if( groupMask & CONFIGSET_TKT ){ |
| 623 | db_prepare(&q, "SELECT mtime, quote(title), quote(owner), quote(cols)," |
| 624 | " quote(sqlcode) FROM reportfmt" |
| 625 | " WHERE mtime>=%lld", iStart); |
| 626 | while( db_step(&q)==SQLITE_ROW ){ |
| 627 | blob_appendf(&rec,"%s %s owner %s cols %s sqlcode %s", |
| 628 | db_column_text(&q, 0), |
| 629 | db_column_text(&q, 1), |
| 630 | db_column_text(&q, 2), |
| 631 | db_column_text(&q, 3), |
| 632 | db_column_text(&q, 4) |
| 633 | ); |
| 634 | blob_appendf(pOut, "config /reportfmt %d\n%s\n", |
| 635 | blob_size(&rec), blob_str(&rec)); |
| 636 | nCard++; |
| 637 | blob_reset(&rec); |
| 638 | } |
| 639 | db_finalize(&q); |
| 640 | } |
| 641 | if( groupMask & CONFIGSET_ADDR ){ |
| 642 | db_prepare(&q, "SELECT mtime, quote(hash), quote(content) FROM concealed" |
| 643 | " WHERE mtime>=%lld", iStart); |
| 644 | while( db_step(&q)==SQLITE_ROW ){ |
| 645 | blob_appendf(&rec,"%s %s content %s", |
| 646 | db_column_text(&q, 0), |
| 647 | db_column_text(&q, 1), |
| 648 | db_column_text(&q, 2) |
| 649 | ); |
| 650 | blob_appendf(pOut, "config /concealed %d\n%s\n", |
| 651 | blob_size(&rec), blob_str(&rec)); |
| 652 | nCard++; |
| 653 | blob_reset(&rec); |
| 654 | } |
| 655 | db_finalize(&q); |
| 656 | } |
| 657 | db_prepare(&q, "SELECT mtime, quote(name), quote(value) FROM config" |
| 658 | " WHERE name=:name AND mtime>=%lld", iStart); |
| 659 | for(ii=0; ii<count(aConfig); ii++){ |
| 660 | if( (aConfig[ii].groupMask & groupMask)!=0 && aConfig[ii].zName[0]!='@' ){ |
| 661 | db_bind_text(&q, ":name", aConfig[ii].zName); |
| 662 | while( db_step(&q)==SQLITE_ROW ){ |
| 663 | blob_appendf(&rec,"%s %s value %s", |
| 664 | db_column_text(&q, 0), |
| 665 | db_column_text(&q, 1), |
| 666 | db_column_text(&q, 2) |
| 667 | ); |
| 668 | blob_appendf(pOut, "config /config %d\n%s\n", |
| 669 | blob_size(&rec), blob_str(&rec)); |
| 670 | nCard++; |
| 671 | blob_reset(&rec); |
| 672 | } |
| 673 | db_reset(&q); |
| 674 | } |
| 675 | } |
| 676 | db_finalize(&q); |
| 677 | return nCard; |
| 678 | } |
| 679 | |
| 680 | /* |
| 681 | ** Identify a configuration group by name. Return its mask. |
| 682 | ** Throw an error if no match. |
| 683 | */ |
| 684 | int configure_name_to_mask(const char *z, int notFoundIsFatal){ |
| 685 | int i; |
| 686 | int n = strlen(z); |
| 687 | for(i=0; i<count(aGroupName); i++){ |
| 688 | if( strncmp(z, &aGroupName[i].zName[1], n)==0 ){ |
| 689 | return aGroupName[i].groupMask; |
| 690 | } |
| 691 | } |
| 692 | if( notFoundIsFatal ){ |
| 693 | fossil_print("Available configuration areas:\n"); |
| 694 | for(i=0; i<count(aGroupName); i++){ |
| 695 | fossil_print(" %-10s %s\n", &aGroupName[i].zName[1], aGroupName[i].zHelp); |
| 696 | } |
| 697 | fossil_fatal("no such configuration area: \"%s\"", z); |
| 698 | } |
| 699 | return 0; |
| 700 | } |
| 701 | |
| 702 | /* |
| 703 | ** Write SQL text into file zFilename that will restore the configuration |
| 704 | ** area identified by mask to its current state from any other state. |
| 705 | */ |
| 706 | static void export_config( |
| 707 | int groupMask, /* Mask indicating which configuration to export */ |
| 708 | const char *zMask, /* Name of the configuration */ |
| 709 | sqlite3_int64 iStart, /* Start date */ |
| 710 | const char *zFilename /* Write into this file */ |
| 711 | ){ |
| 712 | Blob out; |
| 713 | blob_zero(&out); |
| 714 | blob_appendf(&out, |
| 715 | "# The \"%s\" configuration exported from\n" |
| 716 | "# repository \"%s\"\n" |
| 717 | "# on %s\n", |
| 718 | zMask, g.zRepositoryName, |
| 719 | db_text(0, "SELECT datetime('now')") |
| 720 | ); |
| 721 | configure_send_group(&out, groupMask, iStart); |
| 722 | blob_write_to_file(&out, zFilename); |
| 723 | blob_reset(&out); |
| 724 | } |
| 725 | |
| 726 | |
| @@ -395,25 +750,31 @@ | |
| 750 | ** |
| 751 | ** %fossil configuration pull AREA ?URL? |
| 752 | ** |
| 753 | ** Pull and install the configuration from a different server |
| 754 | ** identified by URL. If no URL is specified, then the default |
| 755 | ** server is used. Use the --legacy option for the older protocol |
| 756 | ** (when talking to servers compiled prior to 2011-04-27.) Use |
| 757 | ** the --overwrite flag to completely replace local settings with |
| 758 | ** content received from URL. |
| 759 | ** |
| 760 | ** %fossil configuration push AREA ?URL? |
| 761 | ** |
| 762 | ** Push the local configuration into the remote server identified |
| 763 | ** by URL. Admin privilege is required on the remote server for |
| 764 | ** this to work. When the same record exists both locally and on |
| 765 | ** the remote end, the one that was most recently changed wins. |
| 766 | ** Use the --legacy flag when talking to holder servers. |
| 767 | ** |
| 768 | ** %fossil configuration reset AREA |
| 769 | ** |
| 770 | ** Restore the configuration to the default. AREA as above. |
| 771 | ** |
| 772 | ** %fossil configuration sync AREA ?URL? |
| 773 | ** |
| 774 | ** Synchronize configuration changes in the local repository with |
| 775 | ** the remote repository at URL. |
| 776 | ** |
| 777 | ** |
| 778 | ** SUMMARY: fossil configure METHOD ... ?-R|--repository REPOSITORY? |
| 779 | ** Where: METHOD = export, import, merge, pull, push or reset |
| 780 | ** |
| @@ -438,36 +799,59 @@ | |
| 799 | db_find_and_open_repository(0, 0); |
| 800 | zMethod = g.argv[2]; |
| 801 | n = strlen(zMethod); |
| 802 | if( strncmp(zMethod, "export", n)==0 ){ |
| 803 | int mask; |
| 804 | const char *zSince = find_option("since",0,1); |
| 805 | sqlite3_int64 iStart; |
| 806 | if( g.argc!=5 ){ |
| 807 | usage("export AREA FILENAME"); |
| 808 | } |
| 809 | mask = configure_name_to_mask(g.argv[3], 1); |
| 810 | if( zSince ){ |
| 811 | iStart = db_multi_exec( |
| 812 | "SELECT coalesce(strftime('%%s',%Q),strftime('%%s','now',%Q))+0", |
| 813 | zSince, zSince |
| 814 | ); |
| 815 | }else{ |
| 816 | iStart = 0; |
| 817 | } |
| 818 | export_config(mask, g.argv[3], iStart, g.argv[4]); |
| 819 | }else |
| 820 | if( strncmp(zMethod, "import", n)==0 |
| 821 | || strncmp(zMethod, "merge", n)==0 ){ |
| 822 | Blob in; |
| 823 | int groupMask; |
| 824 | if( g.argc!=4 ) usage(mprintf("%s FILENAME",zMethod)); |
| 825 | blob_read_from_file(&in, g.argv[3]); |
| 826 | db_begin_transaction(); |
| 827 | if( zMethod[0]=='i' ){ |
| 828 | groupMask = CONFIGSET_ALL | CONFIGSET_OVERWRITE; |
| 829 | }else{ |
| 830 | groupMask = CONFIGSET_ALL; |
| 831 | } |
| 832 | configure_receive_all(&in, groupMask); |
| 833 | db_end_transaction(0); |
| 834 | }else |
| 835 | if( strncmp(zMethod, "pull", n)==0 |
| 836 | || strncmp(zMethod, "push", n)==0 |
| 837 | || strncmp(zMethod, "sync", n)==0 |
| 838 | ){ |
| 839 | int mask; |
| 840 | const char *zServer; |
| 841 | const char *zPw; |
| 842 | int legacyFlag = 0; |
| 843 | int overwriteFlag = 0; |
| 844 | if( zMethod[0]!='s' ) legacyFlag = find_option("legacy",0,0)!=0; |
| 845 | if( strncmp(zMethod,"pull",n)==0 ){ |
| 846 | overwriteFlag = find_option("overwrite",0,0)!=0; |
| 847 | } |
| 848 | url_proxy_options(); |
| 849 | if( g.argc!=4 && g.argc!=5 ){ |
| 850 | usage("pull AREA ?URL?"); |
| 851 | } |
| 852 | mask = configure_name_to_mask(g.argv[3], 1); |
| 853 | if( g.argc==5 ){ |
| 854 | zServer = g.argv[4]; |
| 855 | zPw = 0; |
| 856 | g.dontKeepUrl = 1; |
| 857 | }else{ |
| @@ -479,25 +863,29 @@ | |
| 863 | } |
| 864 | url_parse(zServer); |
| 865 | if( g.urlPasswd==0 && zPw ) g.urlPasswd = mprintf("%s", zPw); |
| 866 | user_select(); |
| 867 | url_enable_proxy("via proxy: "); |
| 868 | if( legacyFlag ) mask |= CONFIGSET_OLDFORMAT; |
| 869 | if( overwriteFlag ) mask |= CONFIGSET_OVERWRITE; |
| 870 | if( strncmp(zMethod, "push", n)==0 ){ |
| 871 | client_sync(0,0,0,0,0,mask); |
| 872 | }else if( strncmp(zMethod, "pull", n)==0 ){ |
| 873 | client_sync(0,0,0,0,mask,0); |
| 874 | }else{ |
| 875 | client_sync(0,0,0,0,mask,mask); |
| 876 | } |
| 877 | }else |
| 878 | if( strncmp(zMethod, "reset", n)==0 ){ |
| 879 | int mask, i; |
| 880 | char *zBackup; |
| 881 | if( g.argc!=4 ) usage("reset AREA"); |
| 882 | mask = configure_name_to_mask(g.argv[3], 1); |
| 883 | zBackup = db_text(0, |
| 884 | "SELECT strftime('config-backup-%%Y%%m%%d%%H%%M%%f','now')"); |
| 885 | db_begin_transaction(); |
| 886 | export_config(mask, g.argv[3], 0, zBackup); |
| 887 | for(i=0; i<count(aConfig); i++){ |
| 888 | const char *zName = aConfig[i].zName; |
| 889 | if( (aConfig[i].groupMask & mask)==0 ) continue; |
| 890 | if( zName[0]!='@' ){ |
| 891 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| @@ -511,14 +899,14 @@ | |
| 899 | }else if( fossil_strcmp(zName,"@reportfmt")==0 ){ |
| 900 | db_multi_exec("DELETE FROM reportfmt"); |
| 901 | } |
| 902 | } |
| 903 | db_end_transaction(0); |
| 904 | fossil_print("Configuration reset to factory defaults.\n"); |
| 905 | fossil_print("To recover, use: %s %s import %s\n", |
| 906 | fossil_nameofexe(), g.argv[1], zBackup); |
| 907 | }else |
| 908 | { |
| 909 | fossil_fatal("METHOD should be one of:" |
| 910 | " export import merge pull push reset"); |
| 911 | } |
| 912 | } |
| 913 |
+9
-5
| --- src/content.c | ||
| +++ src/content.c | ||
| @@ -79,11 +79,15 @@ | ||
| 79 | 79 | ** The cache will deallocate memory when it has finished with it. |
| 80 | 80 | */ |
| 81 | 81 | void content_cache_insert(int rid, Blob *pBlob){ |
| 82 | 82 | struct cacheLine *p; |
| 83 | 83 | if( contentCache.n>500 || contentCache.szTotal>50000000 ){ |
| 84 | - content_cache_expire_oldest(); | |
| 84 | + i64 szBefore; | |
| 85 | + do{ | |
| 86 | + szBefore = contentCache.szTotal; | |
| 87 | + content_cache_expire_oldest(); | |
| 88 | + }while( contentCache.szTotal>50000000 && contentCache.szTotal<szBefore ); | |
| 85 | 89 | } |
| 86 | 90 | if( contentCache.n>=contentCache.nAlloc ){ |
| 87 | 91 | contentCache.nAlloc = contentCache.nAlloc*2 + 10; |
| 88 | 92 | contentCache.a = fossil_realloc(contentCache.a, |
| 89 | 93 | contentCache.nAlloc*sizeof(contentCache.a[0])); |
| @@ -666,11 +670,11 @@ | ||
| 666 | 670 | if( g.argc!=3 ) usage("FILENAME"); |
| 667 | 671 | db_must_be_within_tree(); |
| 668 | 672 | user_select(); |
| 669 | 673 | blob_read_from_file(&content, g.argv[2]); |
| 670 | 674 | rid = content_put(&content); |
| 671 | - printf("inserted as record %d\n", rid); | |
| 675 | + fossil_print("inserted as record %d\n", rid); | |
| 672 | 676 | } |
| 673 | 677 | |
| 674 | 678 | /* |
| 675 | 679 | ** Make sure the content at rid is the original content and is not a |
| 676 | 680 | ** delta. |
| @@ -834,14 +838,14 @@ | ||
| 834 | 838 | while( db_step(&q)==SQLITE_ROW ){ |
| 835 | 839 | int rid = db_column_int(&q, 0); |
| 836 | 840 | const char *zUuid = db_column_text(&q, 1); |
| 837 | 841 | int size = db_column_int(&q, 2); |
| 838 | 842 | n1++; |
| 839 | - printf(" %d/%d\r", n1, total); | |
| 843 | + fossil_print(" %d/%d\r", n1, total); | |
| 840 | 844 | fflush(stdout); |
| 841 | 845 | if( size<0 ){ |
| 842 | - printf("skip phantom %d %s\n", rid, zUuid); | |
| 846 | + fossil_print("skip phantom %d %s\n", rid, zUuid); | |
| 843 | 847 | continue; /* Ignore phantoms */ |
| 844 | 848 | } |
| 845 | 849 | content_get(rid, &content); |
| 846 | 850 | if( blob_size(&content)!=size ){ |
| 847 | 851 | fossil_warning("size mismatch on blob rid=%d: %d vs %d", |
| @@ -855,7 +859,7 @@ | ||
| 855 | 859 | blob_reset(&cksum); |
| 856 | 860 | blob_reset(&content); |
| 857 | 861 | n2++; |
| 858 | 862 | } |
| 859 | 863 | db_finalize(&q); |
| 860 | - printf("%d non-phantom blobs (out of %d total) verified\n", n2, n1); | |
| 864 | + fossil_print("%d non-phantom blobs (out of %d total) verified\n", n2, n1); | |
| 861 | 865 | } |
| 862 | 866 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -79,11 +79,15 @@ | |
| 79 | ** The cache will deallocate memory when it has finished with it. |
| 80 | */ |
| 81 | void content_cache_insert(int rid, Blob *pBlob){ |
| 82 | struct cacheLine *p; |
| 83 | if( contentCache.n>500 || contentCache.szTotal>50000000 ){ |
| 84 | content_cache_expire_oldest(); |
| 85 | } |
| 86 | if( contentCache.n>=contentCache.nAlloc ){ |
| 87 | contentCache.nAlloc = contentCache.nAlloc*2 + 10; |
| 88 | contentCache.a = fossil_realloc(contentCache.a, |
| 89 | contentCache.nAlloc*sizeof(contentCache.a[0])); |
| @@ -666,11 +670,11 @@ | |
| 666 | if( g.argc!=3 ) usage("FILENAME"); |
| 667 | db_must_be_within_tree(); |
| 668 | user_select(); |
| 669 | blob_read_from_file(&content, g.argv[2]); |
| 670 | rid = content_put(&content); |
| 671 | printf("inserted as record %d\n", rid); |
| 672 | } |
| 673 | |
| 674 | /* |
| 675 | ** Make sure the content at rid is the original content and is not a |
| 676 | ** delta. |
| @@ -834,14 +838,14 @@ | |
| 834 | while( db_step(&q)==SQLITE_ROW ){ |
| 835 | int rid = db_column_int(&q, 0); |
| 836 | const char *zUuid = db_column_text(&q, 1); |
| 837 | int size = db_column_int(&q, 2); |
| 838 | n1++; |
| 839 | printf(" %d/%d\r", n1, total); |
| 840 | fflush(stdout); |
| 841 | if( size<0 ){ |
| 842 | printf("skip phantom %d %s\n", rid, zUuid); |
| 843 | continue; /* Ignore phantoms */ |
| 844 | } |
| 845 | content_get(rid, &content); |
| 846 | if( blob_size(&content)!=size ){ |
| 847 | fossil_warning("size mismatch on blob rid=%d: %d vs %d", |
| @@ -855,7 +859,7 @@ | |
| 855 | blob_reset(&cksum); |
| 856 | blob_reset(&content); |
| 857 | n2++; |
| 858 | } |
| 859 | db_finalize(&q); |
| 860 | printf("%d non-phantom blobs (out of %d total) verified\n", n2, n1); |
| 861 | } |
| 862 |
| --- src/content.c | |
| +++ src/content.c | |
| @@ -79,11 +79,15 @@ | |
| 79 | ** The cache will deallocate memory when it has finished with it. |
| 80 | */ |
| 81 | void content_cache_insert(int rid, Blob *pBlob){ |
| 82 | struct cacheLine *p; |
| 83 | if( contentCache.n>500 || contentCache.szTotal>50000000 ){ |
| 84 | i64 szBefore; |
| 85 | do{ |
| 86 | szBefore = contentCache.szTotal; |
| 87 | content_cache_expire_oldest(); |
| 88 | }while( contentCache.szTotal>50000000 && contentCache.szTotal<szBefore ); |
| 89 | } |
| 90 | if( contentCache.n>=contentCache.nAlloc ){ |
| 91 | contentCache.nAlloc = contentCache.nAlloc*2 + 10; |
| 92 | contentCache.a = fossil_realloc(contentCache.a, |
| 93 | contentCache.nAlloc*sizeof(contentCache.a[0])); |
| @@ -666,11 +670,11 @@ | |
| 670 | if( g.argc!=3 ) usage("FILENAME"); |
| 671 | db_must_be_within_tree(); |
| 672 | user_select(); |
| 673 | blob_read_from_file(&content, g.argv[2]); |
| 674 | rid = content_put(&content); |
| 675 | fossil_print("inserted as record %d\n", rid); |
| 676 | } |
| 677 | |
| 678 | /* |
| 679 | ** Make sure the content at rid is the original content and is not a |
| 680 | ** delta. |
| @@ -834,14 +838,14 @@ | |
| 838 | while( db_step(&q)==SQLITE_ROW ){ |
| 839 | int rid = db_column_int(&q, 0); |
| 840 | const char *zUuid = db_column_text(&q, 1); |
| 841 | int size = db_column_int(&q, 2); |
| 842 | n1++; |
| 843 | fossil_print(" %d/%d\r", n1, total); |
| 844 | fflush(stdout); |
| 845 | if( size<0 ){ |
| 846 | fossil_print("skip phantom %d %s\n", rid, zUuid); |
| 847 | continue; /* Ignore phantoms */ |
| 848 | } |
| 849 | content_get(rid, &content); |
| 850 | if( blob_size(&content)!=size ){ |
| 851 | fossil_warning("size mismatch on blob rid=%d: %d vs %d", |
| @@ -855,7 +859,7 @@ | |
| 859 | blob_reset(&cksum); |
| 860 | blob_reset(&content); |
| 861 | n2++; |
| 862 | } |
| 863 | db_finalize(&q); |
| 864 | fossil_print("%d non-phantom blobs (out of %d total) verified\n", n2, n1); |
| 865 | } |
| 866 |
M
src/db.c
+60
-47
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -34,10 +34,11 @@ | ||
| 34 | 34 | #endif |
| 35 | 35 | #include <sqlite3.h> |
| 36 | 36 | #include <sys/types.h> |
| 37 | 37 | #include <sys/stat.h> |
| 38 | 38 | #include <unistd.h> |
| 39 | +#include <time.h> | |
| 39 | 40 | #include "db.h" |
| 40 | 41 | |
| 41 | 42 | #if INTERFACE |
| 42 | 43 | /* |
| 43 | 44 | ** An single SQL statement is represented as an instance of the following |
| @@ -80,19 +81,29 @@ | ||
| 80 | 81 | db_force_rollback(); |
| 81 | 82 | fossil_exit(1); |
| 82 | 83 | } |
| 83 | 84 | |
| 84 | 85 | static int nBegin = 0; /* Nesting depth of BEGIN */ |
| 85 | -static int isNewRepo = 0; /* True if the repository is newly created */ | |
| 86 | 86 | static int doRollback = 0; /* True to force a rollback */ |
| 87 | 87 | static int nCommitHook = 0; /* Number of commit hooks */ |
| 88 | 88 | static struct sCommitHook { |
| 89 | 89 | int (*xHook)(void); /* Functions to call at db_end_transaction() */ |
| 90 | 90 | int sequence; /* Call functions in sequence order */ |
| 91 | 91 | } aHook[5]; |
| 92 | 92 | static Stmt *pAllStmt = 0; /* List of all unfinalized statements */ |
| 93 | 93 | static int nPrepare = 0; /* Number of calls to sqlite3_prepare() */ |
| 94 | +static int nDeleteOnFail = 0; /* Number of entries in azDeleteOnFail[] */ | |
| 95 | +static char *azDeleteOnFail[3]; /* Files to delete on a failure */ | |
| 96 | + | |
| 97 | + | |
| 98 | +/* | |
| 99 | +** Arrange for the given file to be deleted on a failure. | |
| 100 | +*/ | |
| 101 | +void db_delete_on_failure(const char *zFilename){ | |
| 102 | + assert( nDeleteOnFail<count(azDeleteOnFail) ); | |
| 103 | + azDeleteOnFail[nDeleteOnFail++] = fossil_strdup(zFilename); | |
| 104 | +} | |
| 94 | 105 | |
| 95 | 106 | /* |
| 96 | 107 | ** This routine is called by the SQLite commit-hook mechanism |
| 97 | 108 | ** just prior to each commit. All this routine does is verify |
| 98 | 109 | ** that nBegin really is zero. That insures that transactions |
| @@ -140,10 +151,11 @@ | ||
| 140 | 151 | |
| 141 | 152 | /* |
| 142 | 153 | ** Force a rollback and shutdown the database |
| 143 | 154 | */ |
| 144 | 155 | void db_force_rollback(void){ |
| 156 | + int i; | |
| 145 | 157 | static int busy = 0; |
| 146 | 158 | if( busy || g.db==0 ) return; |
| 147 | 159 | busy = 1; |
| 148 | 160 | undo_rollback(); |
| 149 | 161 | while( pAllStmt ){ |
| @@ -150,17 +162,16 @@ | ||
| 150 | 162 | db_finalize(pAllStmt); |
| 151 | 163 | } |
| 152 | 164 | if( nBegin ){ |
| 153 | 165 | sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0); |
| 154 | 166 | nBegin = 0; |
| 155 | - if( isNewRepo ){ | |
| 156 | - db_close(0); | |
| 157 | - unlink(g.zRepositoryName); | |
| 158 | - } | |
| 159 | 167 | } |
| 160 | 168 | busy = 0; |
| 161 | 169 | db_close(0); |
| 170 | + for(i=0; i<nDeleteOnFail; i++){ | |
| 171 | + file_delete(azDeleteOnFail[i]); | |
| 172 | + } | |
| 162 | 173 | } |
| 163 | 174 | |
| 164 | 175 | /* |
| 165 | 176 | ** Install a commit hook. Hooks are installed in sequence order. |
| 166 | 177 | ** It is an error to install the same commit hook more than once. |
| @@ -564,14 +575,10 @@ | ||
| 564 | 575 | } |
| 565 | 576 | db_finalize(&s); |
| 566 | 577 | return z; |
| 567 | 578 | } |
| 568 | 579 | |
| 569 | -#if defined(_WIN32) | |
| 570 | -extern char *sqlite3_win32_mbcs_to_utf8(const char*); | |
| 571 | -#endif | |
| 572 | - | |
| 573 | 580 | /* |
| 574 | 581 | ** Initialize a new database file with the given schema. If anything |
| 575 | 582 | ** goes wrong, call db_err() to exit. |
| 576 | 583 | */ |
| 577 | 584 | void db_init_database( |
| @@ -582,13 +589,10 @@ | ||
| 582 | 589 | sqlite3 *db; |
| 583 | 590 | int rc; |
| 584 | 591 | const char *zSql; |
| 585 | 592 | va_list ap; |
| 586 | 593 | |
| 587 | -#if defined(_WIN32) | |
| 588 | - zFileName = sqlite3_win32_mbcs_to_utf8(zFileName); | |
| 589 | -#endif | |
| 590 | 594 | rc = sqlite3_open(zFileName, &db); |
| 591 | 595 | if( rc!=SQLITE_OK ){ |
| 592 | 596 | db_err(sqlite3_errmsg(db)); |
| 593 | 597 | } |
| 594 | 598 | sqlite3_busy_timeout(db, 5000); |
| @@ -606,10 +610,23 @@ | ||
| 606 | 610 | } |
| 607 | 611 | va_end(ap); |
| 608 | 612 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 609 | 613 | sqlite3_close(db); |
| 610 | 614 | } |
| 615 | + | |
| 616 | +/* | |
| 617 | +** Function to return the number of seconds since 1970. This is | |
| 618 | +** the same as strftime('%s','now') but is more compact. | |
| 619 | +*/ | |
| 620 | +static void db_now_function( | |
| 621 | + sqlite3_context *context, | |
| 622 | + int argc, | |
| 623 | + sqlite3_value **argv | |
| 624 | +){ | |
| 625 | + sqlite3_result_int64(context, time(0)); | |
| 626 | +} | |
| 627 | + | |
| 611 | 628 | |
| 612 | 629 | /* |
| 613 | 630 | ** Open a database file. Return a pointer to the new database |
| 614 | 631 | ** connection. An error results in process abort. |
| 615 | 632 | */ |
| @@ -617,13 +634,10 @@ | ||
| 617 | 634 | int rc; |
| 618 | 635 | const char *zVfs; |
| 619 | 636 | sqlite3 *db; |
| 620 | 637 | |
| 621 | 638 | zVfs = getenv("FOSSIL_VFS"); |
| 622 | -#if defined(_WIN32) | |
| 623 | - zDbName = sqlite3_win32_mbcs_to_utf8(zDbName); | |
| 624 | -#endif | |
| 625 | 639 | rc = sqlite3_open_v2( |
| 626 | 640 | zDbName, &db, |
| 627 | 641 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 628 | 642 | zVfs |
| 629 | 643 | ); |
| @@ -630,10 +644,11 @@ | ||
| 630 | 644 | if( rc!=SQLITE_OK ){ |
| 631 | 645 | db_err(sqlite3_errmsg(db)); |
| 632 | 646 | } |
| 633 | 647 | sqlite3_busy_timeout(db, 5000); |
| 634 | 648 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 649 | + sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); | |
| 635 | 650 | return db; |
| 636 | 651 | } |
| 637 | 652 | |
| 638 | 653 | |
| 639 | 654 | /* |
| @@ -645,13 +660,10 @@ | ||
| 645 | 660 | if( !g.db ){ |
| 646 | 661 | g.db = openDatabase(zDbName); |
| 647 | 662 | g.zMainDbType = zLabel; |
| 648 | 663 | db_connection_init(); |
| 649 | 664 | }else{ |
| 650 | -#if defined(_WIN32) | |
| 651 | - zDbName = sqlite3_win32_mbcs_to_utf8(zDbName); | |
| 652 | -#endif | |
| 653 | 665 | db_multi_exec("ATTACH DATABASE %Q AS %s", zDbName, zLabel); |
| 654 | 666 | } |
| 655 | 667 | } |
| 656 | 668 | |
| 657 | 669 | /* |
| @@ -673,17 +685,21 @@ | ||
| 673 | 685 | #if defined(_WIN32) |
| 674 | 686 | zHome = getenv("LOCALAPPDATA"); |
| 675 | 687 | if( zHome==0 ){ |
| 676 | 688 | zHome = getenv("APPDATA"); |
| 677 | 689 | if( zHome==0 ){ |
| 690 | + char *zDrive = getenv("HOMEDRIVE"); | |
| 678 | 691 | zHome = getenv("HOMEPATH"); |
| 692 | + if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome); | |
| 679 | 693 | } |
| 680 | 694 | } |
| 681 | 695 | if( zHome==0 ){ |
| 682 | 696 | fossil_fatal("cannot locate home directory - " |
| 683 | - "please set the HOMEPATH environment variable"); | |
| 697 | + "please set the LOCALAPPDATA or APPDATA or HOMEPATH " | |
| 698 | + "environment variables"); | |
| 684 | 699 | } |
| 700 | + zHome = fossil_mbcs_to_utf8(zHome); | |
| 685 | 701 | #else |
| 686 | 702 | zHome = getenv("HOME"); |
| 687 | 703 | if( zHome==0 ){ |
| 688 | 704 | fossil_fatal("cannot locate home directory - " |
| 689 | 705 | "please set the HOME environment variable"); |
| @@ -725,11 +741,11 @@ | ||
| 725 | 741 | static int isValidLocalDb(const char *zDbName){ |
| 726 | 742 | i64 lsize; |
| 727 | 743 | int rc; |
| 728 | 744 | sqlite3_stmt *pStmt; |
| 729 | 745 | |
| 730 | - if( access(zDbName, F_OK) ) return 0; | |
| 746 | + if( file_access(zDbName, F_OK) ) return 0; | |
| 731 | 747 | lsize = file_size(zDbName); |
| 732 | 748 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 733 | 749 | db_open_or_attach(zDbName, "localdb"); |
| 734 | 750 | g.localOpen = 1; |
| 735 | 751 | db_open_config(0); |
| @@ -788,23 +804,17 @@ | ||
| 788 | 804 | ** is found, it is attached to the open database connection too. |
| 789 | 805 | */ |
| 790 | 806 | int db_open_local(void){ |
| 791 | 807 | int i, n; |
| 792 | 808 | char zPwd[2000]; |
| 793 | - char *zPwdConv; | |
| 794 | 809 | static const char *aDbName[] = { "/_FOSSIL_", "/.fos" }; |
| 795 | 810 | |
| 796 | 811 | if( g.localOpen) return 1; |
| 797 | - if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ | |
| 798 | - db_err("pwd too big: max %d", sizeof(zPwd)-20); | |
| 799 | - } | |
| 812 | + file_getcwd(zPwd, sizeof(zPwd)-20); | |
| 800 | 813 | n = strlen(zPwd); |
| 801 | - zPwdConv = mprintf("%/", zPwd); | |
| 802 | - strncpy(zPwd, zPwdConv, 2000-20); | |
| 803 | - free(zPwdConv); | |
| 804 | 814 | while( n>0 ){ |
| 805 | - if( access(zPwd, W_OK) ) break; | |
| 815 | + if( file_access(zPwd, W_OK) ) break; | |
| 806 | 816 | for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){ |
| 807 | 817 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]); |
| 808 | 818 | if( isValidLocalDb(zPwd) ){ |
| 809 | 819 | /* Found a valid checkout database file */ |
| 810 | 820 | zPwd[n] = 0; |
| @@ -838,15 +848,15 @@ | ||
| 838 | 848 | } |
| 839 | 849 | if( zDbName==0 ){ |
| 840 | 850 | db_err("unable to find the name of a repository database"); |
| 841 | 851 | } |
| 842 | 852 | } |
| 843 | - if( access(zDbName, R_OK) || file_size(zDbName)<1024 ){ | |
| 844 | - if( access(zDbName, 0) ){ | |
| 853 | + if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){ | |
| 854 | + if( file_access(zDbName, 0) ){ | |
| 845 | 855 | fossil_panic("repository does not exist or" |
| 846 | 856 | " is in an unreadable directory: %s", zDbName); |
| 847 | - }else if( access(zDbName, R_OK) ){ | |
| 857 | + }else if( file_access(zDbName, R_OK) ){ | |
| 848 | 858 | fossil_panic("read permission denied for repository %s", zDbName); |
| 849 | 859 | }else{ |
| 850 | 860 | fossil_panic("not a valid repository: %s", zDbName); |
| 851 | 861 | } |
| 852 | 862 | } |
| @@ -949,11 +959,11 @@ | ||
| 949 | 959 | fossil_fatal("not in a local checkout"); |
| 950 | 960 | return; |
| 951 | 961 | } |
| 952 | 962 | file_canonical_name(g.argv[2], &repo); |
| 953 | 963 | zRepo = blob_str(&repo); |
| 954 | - if( access(zRepo, 0) ){ | |
| 964 | + if( file_access(zRepo, 0) ){ | |
| 955 | 965 | fossil_fatal("no such file: %s", zRepo); |
| 956 | 966 | } |
| 957 | 967 | db_open_or_attach(zRepo, "test_repo"); |
| 958 | 968 | db_lset("repository", blob_str(&repo)); |
| 959 | 969 | db_close(1); |
| @@ -1041,11 +1051,11 @@ | ||
| 1041 | 1051 | zFilename, |
| 1042 | 1052 | zRepositorySchema1, |
| 1043 | 1053 | zRepositorySchema2, |
| 1044 | 1054 | (char*)0 |
| 1045 | 1055 | ); |
| 1046 | - isNewRepo = 1; | |
| 1056 | + db_delete_on_failure(zFilename); | |
| 1047 | 1057 | } |
| 1048 | 1058 | |
| 1049 | 1059 | /* |
| 1050 | 1060 | ** Create the default user accounts in the USER table. |
| 1051 | 1061 | */ |
| @@ -1105,14 +1115,14 @@ | ||
| 1105 | 1115 | |
| 1106 | 1116 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1107 | 1117 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 1108 | 1118 | if( makeServerCodes ){ |
| 1109 | 1119 | db_multi_exec( |
| 1110 | - "INSERT INTO config(name,value)" | |
| 1111 | - " VALUES('server-code', lower(hex(randomblob(20))));" | |
| 1112 | - "INSERT INTO config(name,value)" | |
| 1113 | - " VALUES('project-code', lower(hex(randomblob(20))));" | |
| 1120 | + "INSERT INTO config(name,value,mtime)" | |
| 1121 | + " VALUES('server-code', lower(hex(randomblob(20))),now());" | |
| 1122 | + "INSERT INTO config(name,value,mtime)" | |
| 1123 | + " VALUES('project-code', lower(hex(randomblob(20))),now());" | |
| 1114 | 1124 | ); |
| 1115 | 1125 | } |
| 1116 | 1126 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1117 | 1127 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1118 | 1128 | db_create_default_users(0, zDefaultUser); |
| @@ -1174,14 +1184,15 @@ | ||
| 1174 | 1184 | db_open_repository(g.argv[2]); |
| 1175 | 1185 | db_open_config(0); |
| 1176 | 1186 | db_begin_transaction(); |
| 1177 | 1187 | db_initial_setup(zDate, zDefaultUser, 1); |
| 1178 | 1188 | db_end_transaction(0); |
| 1179 | - printf("project-id: %s\n", db_get("project-code", 0)); | |
| 1180 | - printf("server-id: %s\n", db_get("server-code", 0)); | |
| 1189 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 1190 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 1181 | 1191 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 1182 | - printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); | |
| 1192 | + fossil_print("admin-user: %s (initial password is \"%s\")\n", | |
| 1193 | + g.zLogin, zPassword); | |
| 1183 | 1194 | } |
| 1184 | 1195 | |
| 1185 | 1196 | /* |
| 1186 | 1197 | ** SQL functions for debugging. |
| 1187 | 1198 | ** |
| @@ -1195,11 +1206,11 @@ | ||
| 1195 | 1206 | ){ |
| 1196 | 1207 | int i; |
| 1197 | 1208 | if( g.fSqlPrint ){ |
| 1198 | 1209 | for(i=0; i<argc; i++){ |
| 1199 | 1210 | char c = i==argc-1 ? '\n' : ' '; |
| 1200 | - printf("%s%c", sqlite3_value_text(argv[i]), c); | |
| 1211 | + fossil_print("%s%c", sqlite3_value_text(argv[i]), c); | |
| 1201 | 1212 | } |
| 1202 | 1213 | } |
| 1203 | 1214 | } |
| 1204 | 1215 | static void db_sql_trace(void *notUsed, const char *zSql){ |
| 1205 | 1216 | int n = strlen(zSql); |
| @@ -1295,11 +1306,12 @@ | ||
| 1295 | 1306 | sha1sum_step_text(zContent, n); |
| 1296 | 1307 | sha1sum_finish(&out); |
| 1297 | 1308 | sqlite3_snprintf(sizeof(zHash), zHash, "%s", blob_str(&out)); |
| 1298 | 1309 | blob_reset(&out); |
| 1299 | 1310 | db_multi_exec( |
| 1300 | - "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)", | |
| 1311 | + "INSERT OR IGNORE INTO concealed(hash,content,mtime)" | |
| 1312 | + " VALUES(%Q,%#Q,now())", | |
| 1301 | 1313 | zHash, n, zContent |
| 1302 | 1314 | ); |
| 1303 | 1315 | } |
| 1304 | 1316 | return zHash; |
| 1305 | 1317 | } |
| @@ -1406,11 +1418,11 @@ | ||
| 1406 | 1418 | db_swap_connections(); |
| 1407 | 1419 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", |
| 1408 | 1420 | zName, zValue); |
| 1409 | 1421 | db_swap_connections(); |
| 1410 | 1422 | }else{ |
| 1411 | - db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%Q)", | |
| 1423 | + db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", | |
| 1412 | 1424 | zName, zValue); |
| 1413 | 1425 | } |
| 1414 | 1426 | if( globalFlag && g.repositoryOpen ){ |
| 1415 | 1427 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1416 | 1428 | } |
| @@ -1465,11 +1477,11 @@ | ||
| 1465 | 1477 | db_swap_connections(); |
| 1466 | 1478 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", |
| 1467 | 1479 | zName, value); |
| 1468 | 1480 | db_swap_connections(); |
| 1469 | 1481 | }else{ |
| 1470 | - db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%d)", | |
| 1482 | + db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%d,now())", | |
| 1471 | 1483 | zName, value); |
| 1472 | 1484 | } |
| 1473 | 1485 | if( globalFlag && g.repositoryOpen ){ |
| 1474 | 1486 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1475 | 1487 | } |
| @@ -1550,10 +1562,11 @@ | ||
| 1550 | 1562 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1551 | 1563 | } |
| 1552 | 1564 | file_canonical_name(g.argv[2], &path); |
| 1553 | 1565 | db_open_repository(blob_str(&path)); |
| 1554 | 1566 | db_init_database("./_FOSSIL_", zLocalSchema, (char*)0); |
| 1567 | + db_delete_on_failure("./_FOSSIL_"); | |
| 1555 | 1568 | db_open_local(); |
| 1556 | 1569 | db_lset("repository", blob_str(&path)); |
| 1557 | 1570 | db_record_repository_filename(blob_str(&path)); |
| 1558 | 1571 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1559 | 1572 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| @@ -1597,14 +1610,14 @@ | ||
| 1597 | 1610 | "SELECT '(global)', value FROM global_config WHERE name=%Q", |
| 1598 | 1611 | zName |
| 1599 | 1612 | ); |
| 1600 | 1613 | } |
| 1601 | 1614 | if( db_step(&q)==SQLITE_ROW ){ |
| 1602 | - printf("%-20s %-8s %s\n", zName, db_column_text(&q, 0), | |
| 1615 | + fossil_print("%-20s %-8s %s\n", zName, db_column_text(&q, 0), | |
| 1603 | 1616 | db_column_text(&q, 1)); |
| 1604 | 1617 | }else{ |
| 1605 | - printf("%-20s\n", zName); | |
| 1618 | + fossil_print("%-20s\n", zName); | |
| 1606 | 1619 | } |
| 1607 | 1620 | db_finalize(&q); |
| 1608 | 1621 | } |
| 1609 | 1622 | |
| 1610 | 1623 | |
| @@ -1853,9 +1866,9 @@ | ||
| 1853 | 1866 | void test_timespan_cmd(void){ |
| 1854 | 1867 | double rDiff; |
| 1855 | 1868 | if( g.argc!=3 ) usage("TIMESTAMP"); |
| 1856 | 1869 | sqlite3_open(":memory:", &g.db); |
| 1857 | 1870 | rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); |
| 1858 | - printf("Time differences: %s\n", db_timespan_name(rDiff)); | |
| 1871 | + fossil_print("Time differences: %s\n", db_timespan_name(rDiff)); | |
| 1859 | 1872 | sqlite3_close(g.db); |
| 1860 | 1873 | g.db = 0; |
| 1861 | 1874 | } |
| 1862 | 1875 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -34,10 +34,11 @@ | |
| 34 | #endif |
| 35 | #include <sqlite3.h> |
| 36 | #include <sys/types.h> |
| 37 | #include <sys/stat.h> |
| 38 | #include <unistd.h> |
| 39 | #include "db.h" |
| 40 | |
| 41 | #if INTERFACE |
| 42 | /* |
| 43 | ** An single SQL statement is represented as an instance of the following |
| @@ -80,19 +81,29 @@ | |
| 80 | db_force_rollback(); |
| 81 | fossil_exit(1); |
| 82 | } |
| 83 | |
| 84 | static int nBegin = 0; /* Nesting depth of BEGIN */ |
| 85 | static int isNewRepo = 0; /* True if the repository is newly created */ |
| 86 | static int doRollback = 0; /* True to force a rollback */ |
| 87 | static int nCommitHook = 0; /* Number of commit hooks */ |
| 88 | static struct sCommitHook { |
| 89 | int (*xHook)(void); /* Functions to call at db_end_transaction() */ |
| 90 | int sequence; /* Call functions in sequence order */ |
| 91 | } aHook[5]; |
| 92 | static Stmt *pAllStmt = 0; /* List of all unfinalized statements */ |
| 93 | static int nPrepare = 0; /* Number of calls to sqlite3_prepare() */ |
| 94 | |
| 95 | /* |
| 96 | ** This routine is called by the SQLite commit-hook mechanism |
| 97 | ** just prior to each commit. All this routine does is verify |
| 98 | ** that nBegin really is zero. That insures that transactions |
| @@ -140,10 +151,11 @@ | |
| 140 | |
| 141 | /* |
| 142 | ** Force a rollback and shutdown the database |
| 143 | */ |
| 144 | void db_force_rollback(void){ |
| 145 | static int busy = 0; |
| 146 | if( busy || g.db==0 ) return; |
| 147 | busy = 1; |
| 148 | undo_rollback(); |
| 149 | while( pAllStmt ){ |
| @@ -150,17 +162,16 @@ | |
| 150 | db_finalize(pAllStmt); |
| 151 | } |
| 152 | if( nBegin ){ |
| 153 | sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0); |
| 154 | nBegin = 0; |
| 155 | if( isNewRepo ){ |
| 156 | db_close(0); |
| 157 | unlink(g.zRepositoryName); |
| 158 | } |
| 159 | } |
| 160 | busy = 0; |
| 161 | db_close(0); |
| 162 | } |
| 163 | |
| 164 | /* |
| 165 | ** Install a commit hook. Hooks are installed in sequence order. |
| 166 | ** It is an error to install the same commit hook more than once. |
| @@ -564,14 +575,10 @@ | |
| 564 | } |
| 565 | db_finalize(&s); |
| 566 | return z; |
| 567 | } |
| 568 | |
| 569 | #if defined(_WIN32) |
| 570 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 571 | #endif |
| 572 | |
| 573 | /* |
| 574 | ** Initialize a new database file with the given schema. If anything |
| 575 | ** goes wrong, call db_err() to exit. |
| 576 | */ |
| 577 | void db_init_database( |
| @@ -582,13 +589,10 @@ | |
| 582 | sqlite3 *db; |
| 583 | int rc; |
| 584 | const char *zSql; |
| 585 | va_list ap; |
| 586 | |
| 587 | #if defined(_WIN32) |
| 588 | zFileName = sqlite3_win32_mbcs_to_utf8(zFileName); |
| 589 | #endif |
| 590 | rc = sqlite3_open(zFileName, &db); |
| 591 | if( rc!=SQLITE_OK ){ |
| 592 | db_err(sqlite3_errmsg(db)); |
| 593 | } |
| 594 | sqlite3_busy_timeout(db, 5000); |
| @@ -606,10 +610,23 @@ | |
| 606 | } |
| 607 | va_end(ap); |
| 608 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 609 | sqlite3_close(db); |
| 610 | } |
| 611 | |
| 612 | /* |
| 613 | ** Open a database file. Return a pointer to the new database |
| 614 | ** connection. An error results in process abort. |
| 615 | */ |
| @@ -617,13 +634,10 @@ | |
| 617 | int rc; |
| 618 | const char *zVfs; |
| 619 | sqlite3 *db; |
| 620 | |
| 621 | zVfs = getenv("FOSSIL_VFS"); |
| 622 | #if defined(_WIN32) |
| 623 | zDbName = sqlite3_win32_mbcs_to_utf8(zDbName); |
| 624 | #endif |
| 625 | rc = sqlite3_open_v2( |
| 626 | zDbName, &db, |
| 627 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 628 | zVfs |
| 629 | ); |
| @@ -630,10 +644,11 @@ | |
| 630 | if( rc!=SQLITE_OK ){ |
| 631 | db_err(sqlite3_errmsg(db)); |
| 632 | } |
| 633 | sqlite3_busy_timeout(db, 5000); |
| 634 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 635 | return db; |
| 636 | } |
| 637 | |
| 638 | |
| 639 | /* |
| @@ -645,13 +660,10 @@ | |
| 645 | if( !g.db ){ |
| 646 | g.db = openDatabase(zDbName); |
| 647 | g.zMainDbType = zLabel; |
| 648 | db_connection_init(); |
| 649 | }else{ |
| 650 | #if defined(_WIN32) |
| 651 | zDbName = sqlite3_win32_mbcs_to_utf8(zDbName); |
| 652 | #endif |
| 653 | db_multi_exec("ATTACH DATABASE %Q AS %s", zDbName, zLabel); |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | /* |
| @@ -673,17 +685,21 @@ | |
| 673 | #if defined(_WIN32) |
| 674 | zHome = getenv("LOCALAPPDATA"); |
| 675 | if( zHome==0 ){ |
| 676 | zHome = getenv("APPDATA"); |
| 677 | if( zHome==0 ){ |
| 678 | zHome = getenv("HOMEPATH"); |
| 679 | } |
| 680 | } |
| 681 | if( zHome==0 ){ |
| 682 | fossil_fatal("cannot locate home directory - " |
| 683 | "please set the HOMEPATH environment variable"); |
| 684 | } |
| 685 | #else |
| 686 | zHome = getenv("HOME"); |
| 687 | if( zHome==0 ){ |
| 688 | fossil_fatal("cannot locate home directory - " |
| 689 | "please set the HOME environment variable"); |
| @@ -725,11 +741,11 @@ | |
| 725 | static int isValidLocalDb(const char *zDbName){ |
| 726 | i64 lsize; |
| 727 | int rc; |
| 728 | sqlite3_stmt *pStmt; |
| 729 | |
| 730 | if( access(zDbName, F_OK) ) return 0; |
| 731 | lsize = file_size(zDbName); |
| 732 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 733 | db_open_or_attach(zDbName, "localdb"); |
| 734 | g.localOpen = 1; |
| 735 | db_open_config(0); |
| @@ -788,23 +804,17 @@ | |
| 788 | ** is found, it is attached to the open database connection too. |
| 789 | */ |
| 790 | int db_open_local(void){ |
| 791 | int i, n; |
| 792 | char zPwd[2000]; |
| 793 | char *zPwdConv; |
| 794 | static const char *aDbName[] = { "/_FOSSIL_", "/.fos" }; |
| 795 | |
| 796 | if( g.localOpen) return 1; |
| 797 | if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ |
| 798 | db_err("pwd too big: max %d", sizeof(zPwd)-20); |
| 799 | } |
| 800 | n = strlen(zPwd); |
| 801 | zPwdConv = mprintf("%/", zPwd); |
| 802 | strncpy(zPwd, zPwdConv, 2000-20); |
| 803 | free(zPwdConv); |
| 804 | while( n>0 ){ |
| 805 | if( access(zPwd, W_OK) ) break; |
| 806 | for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){ |
| 807 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]); |
| 808 | if( isValidLocalDb(zPwd) ){ |
| 809 | /* Found a valid checkout database file */ |
| 810 | zPwd[n] = 0; |
| @@ -838,15 +848,15 @@ | |
| 838 | } |
| 839 | if( zDbName==0 ){ |
| 840 | db_err("unable to find the name of a repository database"); |
| 841 | } |
| 842 | } |
| 843 | if( access(zDbName, R_OK) || file_size(zDbName)<1024 ){ |
| 844 | if( access(zDbName, 0) ){ |
| 845 | fossil_panic("repository does not exist or" |
| 846 | " is in an unreadable directory: %s", zDbName); |
| 847 | }else if( access(zDbName, R_OK) ){ |
| 848 | fossil_panic("read permission denied for repository %s", zDbName); |
| 849 | }else{ |
| 850 | fossil_panic("not a valid repository: %s", zDbName); |
| 851 | } |
| 852 | } |
| @@ -949,11 +959,11 @@ | |
| 949 | fossil_fatal("not in a local checkout"); |
| 950 | return; |
| 951 | } |
| 952 | file_canonical_name(g.argv[2], &repo); |
| 953 | zRepo = blob_str(&repo); |
| 954 | if( access(zRepo, 0) ){ |
| 955 | fossil_fatal("no such file: %s", zRepo); |
| 956 | } |
| 957 | db_open_or_attach(zRepo, "test_repo"); |
| 958 | db_lset("repository", blob_str(&repo)); |
| 959 | db_close(1); |
| @@ -1041,11 +1051,11 @@ | |
| 1041 | zFilename, |
| 1042 | zRepositorySchema1, |
| 1043 | zRepositorySchema2, |
| 1044 | (char*)0 |
| 1045 | ); |
| 1046 | isNewRepo = 1; |
| 1047 | } |
| 1048 | |
| 1049 | /* |
| 1050 | ** Create the default user accounts in the USER table. |
| 1051 | */ |
| @@ -1105,14 +1115,14 @@ | |
| 1105 | |
| 1106 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1107 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 1108 | if( makeServerCodes ){ |
| 1109 | db_multi_exec( |
| 1110 | "INSERT INTO config(name,value)" |
| 1111 | " VALUES('server-code', lower(hex(randomblob(20))));" |
| 1112 | "INSERT INTO config(name,value)" |
| 1113 | " VALUES('project-code', lower(hex(randomblob(20))));" |
| 1114 | ); |
| 1115 | } |
| 1116 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1117 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1118 | db_create_default_users(0, zDefaultUser); |
| @@ -1174,14 +1184,15 @@ | |
| 1174 | db_open_repository(g.argv[2]); |
| 1175 | db_open_config(0); |
| 1176 | db_begin_transaction(); |
| 1177 | db_initial_setup(zDate, zDefaultUser, 1); |
| 1178 | db_end_transaction(0); |
| 1179 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 1180 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 1181 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 1182 | printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| 1183 | } |
| 1184 | |
| 1185 | /* |
| 1186 | ** SQL functions for debugging. |
| 1187 | ** |
| @@ -1195,11 +1206,11 @@ | |
| 1195 | ){ |
| 1196 | int i; |
| 1197 | if( g.fSqlPrint ){ |
| 1198 | for(i=0; i<argc; i++){ |
| 1199 | char c = i==argc-1 ? '\n' : ' '; |
| 1200 | printf("%s%c", sqlite3_value_text(argv[i]), c); |
| 1201 | } |
| 1202 | } |
| 1203 | } |
| 1204 | static void db_sql_trace(void *notUsed, const char *zSql){ |
| 1205 | int n = strlen(zSql); |
| @@ -1295,11 +1306,12 @@ | |
| 1295 | sha1sum_step_text(zContent, n); |
| 1296 | sha1sum_finish(&out); |
| 1297 | sqlite3_snprintf(sizeof(zHash), zHash, "%s", blob_str(&out)); |
| 1298 | blob_reset(&out); |
| 1299 | db_multi_exec( |
| 1300 | "INSERT OR IGNORE INTO concealed VALUES(%Q,%#Q)", |
| 1301 | zHash, n, zContent |
| 1302 | ); |
| 1303 | } |
| 1304 | return zHash; |
| 1305 | } |
| @@ -1406,11 +1418,11 @@ | |
| 1406 | db_swap_connections(); |
| 1407 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", |
| 1408 | zName, zValue); |
| 1409 | db_swap_connections(); |
| 1410 | }else{ |
| 1411 | db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%Q)", |
| 1412 | zName, zValue); |
| 1413 | } |
| 1414 | if( globalFlag && g.repositoryOpen ){ |
| 1415 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1416 | } |
| @@ -1465,11 +1477,11 @@ | |
| 1465 | db_swap_connections(); |
| 1466 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", |
| 1467 | zName, value); |
| 1468 | db_swap_connections(); |
| 1469 | }else{ |
| 1470 | db_multi_exec("REPLACE INTO config(name,value) VALUES(%Q,%d)", |
| 1471 | zName, value); |
| 1472 | } |
| 1473 | if( globalFlag && g.repositoryOpen ){ |
| 1474 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1475 | } |
| @@ -1550,10 +1562,11 @@ | |
| 1550 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1551 | } |
| 1552 | file_canonical_name(g.argv[2], &path); |
| 1553 | db_open_repository(blob_str(&path)); |
| 1554 | db_init_database("./_FOSSIL_", zLocalSchema, (char*)0); |
| 1555 | db_open_local(); |
| 1556 | db_lset("repository", blob_str(&path)); |
| 1557 | db_record_repository_filename(blob_str(&path)); |
| 1558 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1559 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| @@ -1597,14 +1610,14 @@ | |
| 1597 | "SELECT '(global)', value FROM global_config WHERE name=%Q", |
| 1598 | zName |
| 1599 | ); |
| 1600 | } |
| 1601 | if( db_step(&q)==SQLITE_ROW ){ |
| 1602 | printf("%-20s %-8s %s\n", zName, db_column_text(&q, 0), |
| 1603 | db_column_text(&q, 1)); |
| 1604 | }else{ |
| 1605 | printf("%-20s\n", zName); |
| 1606 | } |
| 1607 | db_finalize(&q); |
| 1608 | } |
| 1609 | |
| 1610 | |
| @@ -1853,9 +1866,9 @@ | |
| 1853 | void test_timespan_cmd(void){ |
| 1854 | double rDiff; |
| 1855 | if( g.argc!=3 ) usage("TIMESTAMP"); |
| 1856 | sqlite3_open(":memory:", &g.db); |
| 1857 | rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); |
| 1858 | printf("Time differences: %s\n", db_timespan_name(rDiff)); |
| 1859 | sqlite3_close(g.db); |
| 1860 | g.db = 0; |
| 1861 | } |
| 1862 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -34,10 +34,11 @@ | |
| 34 | #endif |
| 35 | #include <sqlite3.h> |
| 36 | #include <sys/types.h> |
| 37 | #include <sys/stat.h> |
| 38 | #include <unistd.h> |
| 39 | #include <time.h> |
| 40 | #include "db.h" |
| 41 | |
| 42 | #if INTERFACE |
| 43 | /* |
| 44 | ** An single SQL statement is represented as an instance of the following |
| @@ -80,19 +81,29 @@ | |
| 81 | db_force_rollback(); |
| 82 | fossil_exit(1); |
| 83 | } |
| 84 | |
| 85 | static int nBegin = 0; /* Nesting depth of BEGIN */ |
| 86 | static int doRollback = 0; /* True to force a rollback */ |
| 87 | static int nCommitHook = 0; /* Number of commit hooks */ |
| 88 | static struct sCommitHook { |
| 89 | int (*xHook)(void); /* Functions to call at db_end_transaction() */ |
| 90 | int sequence; /* Call functions in sequence order */ |
| 91 | } aHook[5]; |
| 92 | static Stmt *pAllStmt = 0; /* List of all unfinalized statements */ |
| 93 | static int nPrepare = 0; /* Number of calls to sqlite3_prepare() */ |
| 94 | static int nDeleteOnFail = 0; /* Number of entries in azDeleteOnFail[] */ |
| 95 | static char *azDeleteOnFail[3]; /* Files to delete on a failure */ |
| 96 | |
| 97 | |
| 98 | /* |
| 99 | ** Arrange for the given file to be deleted on a failure. |
| 100 | */ |
| 101 | void db_delete_on_failure(const char *zFilename){ |
| 102 | assert( nDeleteOnFail<count(azDeleteOnFail) ); |
| 103 | azDeleteOnFail[nDeleteOnFail++] = fossil_strdup(zFilename); |
| 104 | } |
| 105 | |
| 106 | /* |
| 107 | ** This routine is called by the SQLite commit-hook mechanism |
| 108 | ** just prior to each commit. All this routine does is verify |
| 109 | ** that nBegin really is zero. That insures that transactions |
| @@ -140,10 +151,11 @@ | |
| 151 | |
| 152 | /* |
| 153 | ** Force a rollback and shutdown the database |
| 154 | */ |
| 155 | void db_force_rollback(void){ |
| 156 | int i; |
| 157 | static int busy = 0; |
| 158 | if( busy || g.db==0 ) return; |
| 159 | busy = 1; |
| 160 | undo_rollback(); |
| 161 | while( pAllStmt ){ |
| @@ -150,17 +162,16 @@ | |
| 162 | db_finalize(pAllStmt); |
| 163 | } |
| 164 | if( nBegin ){ |
| 165 | sqlite3_exec(g.db, "ROLLBACK", 0, 0, 0); |
| 166 | nBegin = 0; |
| 167 | } |
| 168 | busy = 0; |
| 169 | db_close(0); |
| 170 | for(i=0; i<nDeleteOnFail; i++){ |
| 171 | file_delete(azDeleteOnFail[i]); |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | /* |
| 176 | ** Install a commit hook. Hooks are installed in sequence order. |
| 177 | ** It is an error to install the same commit hook more than once. |
| @@ -564,14 +575,10 @@ | |
| 575 | } |
| 576 | db_finalize(&s); |
| 577 | return z; |
| 578 | } |
| 579 | |
| 580 | /* |
| 581 | ** Initialize a new database file with the given schema. If anything |
| 582 | ** goes wrong, call db_err() to exit. |
| 583 | */ |
| 584 | void db_init_database( |
| @@ -582,13 +589,10 @@ | |
| 589 | sqlite3 *db; |
| 590 | int rc; |
| 591 | const char *zSql; |
| 592 | va_list ap; |
| 593 | |
| 594 | rc = sqlite3_open(zFileName, &db); |
| 595 | if( rc!=SQLITE_OK ){ |
| 596 | db_err(sqlite3_errmsg(db)); |
| 597 | } |
| 598 | sqlite3_busy_timeout(db, 5000); |
| @@ -606,10 +610,23 @@ | |
| 610 | } |
| 611 | va_end(ap); |
| 612 | sqlite3_exec(db, "COMMIT", 0, 0, 0); |
| 613 | sqlite3_close(db); |
| 614 | } |
| 615 | |
| 616 | /* |
| 617 | ** Function to return the number of seconds since 1970. This is |
| 618 | ** the same as strftime('%s','now') but is more compact. |
| 619 | */ |
| 620 | static void db_now_function( |
| 621 | sqlite3_context *context, |
| 622 | int argc, |
| 623 | sqlite3_value **argv |
| 624 | ){ |
| 625 | sqlite3_result_int64(context, time(0)); |
| 626 | } |
| 627 | |
| 628 | |
| 629 | /* |
| 630 | ** Open a database file. Return a pointer to the new database |
| 631 | ** connection. An error results in process abort. |
| 632 | */ |
| @@ -617,13 +634,10 @@ | |
| 634 | int rc; |
| 635 | const char *zVfs; |
| 636 | sqlite3 *db; |
| 637 | |
| 638 | zVfs = getenv("FOSSIL_VFS"); |
| 639 | rc = sqlite3_open_v2( |
| 640 | zDbName, &db, |
| 641 | SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, |
| 642 | zVfs |
| 643 | ); |
| @@ -630,10 +644,11 @@ | |
| 644 | if( rc!=SQLITE_OK ){ |
| 645 | db_err(sqlite3_errmsg(db)); |
| 646 | } |
| 647 | sqlite3_busy_timeout(db, 5000); |
| 648 | sqlite3_wal_autocheckpoint(db, 1); /* Set to checkpoint frequently */ |
| 649 | sqlite3_create_function(db, "now", 0, SQLITE_ANY, 0, db_now_function, 0, 0); |
| 650 | return db; |
| 651 | } |
| 652 | |
| 653 | |
| 654 | /* |
| @@ -645,13 +660,10 @@ | |
| 660 | if( !g.db ){ |
| 661 | g.db = openDatabase(zDbName); |
| 662 | g.zMainDbType = zLabel; |
| 663 | db_connection_init(); |
| 664 | }else{ |
| 665 | db_multi_exec("ATTACH DATABASE %Q AS %s", zDbName, zLabel); |
| 666 | } |
| 667 | } |
| 668 | |
| 669 | /* |
| @@ -673,17 +685,21 @@ | |
| 685 | #if defined(_WIN32) |
| 686 | zHome = getenv("LOCALAPPDATA"); |
| 687 | if( zHome==0 ){ |
| 688 | zHome = getenv("APPDATA"); |
| 689 | if( zHome==0 ){ |
| 690 | char *zDrive = getenv("HOMEDRIVE"); |
| 691 | zHome = getenv("HOMEPATH"); |
| 692 | if( zDrive && zHome ) zHome = mprintf("%s%s", zDrive, zHome); |
| 693 | } |
| 694 | } |
| 695 | if( zHome==0 ){ |
| 696 | fossil_fatal("cannot locate home directory - " |
| 697 | "please set the LOCALAPPDATA or APPDATA or HOMEPATH " |
| 698 | "environment variables"); |
| 699 | } |
| 700 | zHome = fossil_mbcs_to_utf8(zHome); |
| 701 | #else |
| 702 | zHome = getenv("HOME"); |
| 703 | if( zHome==0 ){ |
| 704 | fossil_fatal("cannot locate home directory - " |
| 705 | "please set the HOME environment variable"); |
| @@ -725,11 +741,11 @@ | |
| 741 | static int isValidLocalDb(const char *zDbName){ |
| 742 | i64 lsize; |
| 743 | int rc; |
| 744 | sqlite3_stmt *pStmt; |
| 745 | |
| 746 | if( file_access(zDbName, F_OK) ) return 0; |
| 747 | lsize = file_size(zDbName); |
| 748 | if( lsize%1024!=0 || lsize<4096 ) return 0; |
| 749 | db_open_or_attach(zDbName, "localdb"); |
| 750 | g.localOpen = 1; |
| 751 | db_open_config(0); |
| @@ -788,23 +804,17 @@ | |
| 804 | ** is found, it is attached to the open database connection too. |
| 805 | */ |
| 806 | int db_open_local(void){ |
| 807 | int i, n; |
| 808 | char zPwd[2000]; |
| 809 | static const char *aDbName[] = { "/_FOSSIL_", "/.fos" }; |
| 810 | |
| 811 | if( g.localOpen) return 1; |
| 812 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 813 | n = strlen(zPwd); |
| 814 | while( n>0 ){ |
| 815 | if( file_access(zPwd, W_OK) ) break; |
| 816 | for(i=0; i<sizeof(aDbName)/sizeof(aDbName[0]); i++){ |
| 817 | sqlite3_snprintf(sizeof(zPwd)-n, &zPwd[n], "%s", aDbName[i]); |
| 818 | if( isValidLocalDb(zPwd) ){ |
| 819 | /* Found a valid checkout database file */ |
| 820 | zPwd[n] = 0; |
| @@ -838,15 +848,15 @@ | |
| 848 | } |
| 849 | if( zDbName==0 ){ |
| 850 | db_err("unable to find the name of a repository database"); |
| 851 | } |
| 852 | } |
| 853 | if( file_access(zDbName, R_OK) || file_size(zDbName)<1024 ){ |
| 854 | if( file_access(zDbName, 0) ){ |
| 855 | fossil_panic("repository does not exist or" |
| 856 | " is in an unreadable directory: %s", zDbName); |
| 857 | }else if( file_access(zDbName, R_OK) ){ |
| 858 | fossil_panic("read permission denied for repository %s", zDbName); |
| 859 | }else{ |
| 860 | fossil_panic("not a valid repository: %s", zDbName); |
| 861 | } |
| 862 | } |
| @@ -949,11 +959,11 @@ | |
| 959 | fossil_fatal("not in a local checkout"); |
| 960 | return; |
| 961 | } |
| 962 | file_canonical_name(g.argv[2], &repo); |
| 963 | zRepo = blob_str(&repo); |
| 964 | if( file_access(zRepo, 0) ){ |
| 965 | fossil_fatal("no such file: %s", zRepo); |
| 966 | } |
| 967 | db_open_or_attach(zRepo, "test_repo"); |
| 968 | db_lset("repository", blob_str(&repo)); |
| 969 | db_close(1); |
| @@ -1041,11 +1051,11 @@ | |
| 1051 | zFilename, |
| 1052 | zRepositorySchema1, |
| 1053 | zRepositorySchema2, |
| 1054 | (char*)0 |
| 1055 | ); |
| 1056 | db_delete_on_failure(zFilename); |
| 1057 | } |
| 1058 | |
| 1059 | /* |
| 1060 | ** Create the default user accounts in the USER table. |
| 1061 | */ |
| @@ -1105,14 +1115,14 @@ | |
| 1115 | |
| 1116 | db_set("content-schema", CONTENT_SCHEMA, 0); |
| 1117 | db_set("aux-schema", AUX_SCHEMA, 0); |
| 1118 | if( makeServerCodes ){ |
| 1119 | db_multi_exec( |
| 1120 | "INSERT INTO config(name,value,mtime)" |
| 1121 | " VALUES('server-code', lower(hex(randomblob(20))),now());" |
| 1122 | "INSERT INTO config(name,value,mtime)" |
| 1123 | " VALUES('project-code', lower(hex(randomblob(20))),now());" |
| 1124 | ); |
| 1125 | } |
| 1126 | if( !db_is_global("autosync") ) db_set_int("autosync", 1, 0); |
| 1127 | if( !db_is_global("localauth") ) db_set_int("localauth", 0, 0); |
| 1128 | db_create_default_users(0, zDefaultUser); |
| @@ -1174,14 +1184,15 @@ | |
| 1184 | db_open_repository(g.argv[2]); |
| 1185 | db_open_config(0); |
| 1186 | db_begin_transaction(); |
| 1187 | db_initial_setup(zDate, zDefaultUser, 1); |
| 1188 | db_end_transaction(0); |
| 1189 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 1190 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 1191 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 1192 | fossil_print("admin-user: %s (initial password is \"%s\")\n", |
| 1193 | g.zLogin, zPassword); |
| 1194 | } |
| 1195 | |
| 1196 | /* |
| 1197 | ** SQL functions for debugging. |
| 1198 | ** |
| @@ -1195,11 +1206,11 @@ | |
| 1206 | ){ |
| 1207 | int i; |
| 1208 | if( g.fSqlPrint ){ |
| 1209 | for(i=0; i<argc; i++){ |
| 1210 | char c = i==argc-1 ? '\n' : ' '; |
| 1211 | fossil_print("%s%c", sqlite3_value_text(argv[i]), c); |
| 1212 | } |
| 1213 | } |
| 1214 | } |
| 1215 | static void db_sql_trace(void *notUsed, const char *zSql){ |
| 1216 | int n = strlen(zSql); |
| @@ -1295,11 +1306,12 @@ | |
| 1306 | sha1sum_step_text(zContent, n); |
| 1307 | sha1sum_finish(&out); |
| 1308 | sqlite3_snprintf(sizeof(zHash), zHash, "%s", blob_str(&out)); |
| 1309 | blob_reset(&out); |
| 1310 | db_multi_exec( |
| 1311 | "INSERT OR IGNORE INTO concealed(hash,content,mtime)" |
| 1312 | " VALUES(%Q,%#Q,now())", |
| 1313 | zHash, n, zContent |
| 1314 | ); |
| 1315 | } |
| 1316 | return zHash; |
| 1317 | } |
| @@ -1406,11 +1418,11 @@ | |
| 1418 | db_swap_connections(); |
| 1419 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%Q)", |
| 1420 | zName, zValue); |
| 1421 | db_swap_connections(); |
| 1422 | }else{ |
| 1423 | db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%Q,now())", |
| 1424 | zName, zValue); |
| 1425 | } |
| 1426 | if( globalFlag && g.repositoryOpen ){ |
| 1427 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1428 | } |
| @@ -1465,11 +1477,11 @@ | |
| 1477 | db_swap_connections(); |
| 1478 | db_multi_exec("REPLACE INTO global_config(name,value) VALUES(%Q,%d)", |
| 1479 | zName, value); |
| 1480 | db_swap_connections(); |
| 1481 | }else{ |
| 1482 | db_multi_exec("REPLACE INTO config(name,value,mtime) VALUES(%Q,%d,now())", |
| 1483 | zName, value); |
| 1484 | } |
| 1485 | if( globalFlag && g.repositoryOpen ){ |
| 1486 | db_multi_exec("DELETE FROM config WHERE name=%Q", zName); |
| 1487 | } |
| @@ -1550,10 +1562,11 @@ | |
| 1562 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1563 | } |
| 1564 | file_canonical_name(g.argv[2], &path); |
| 1565 | db_open_repository(blob_str(&path)); |
| 1566 | db_init_database("./_FOSSIL_", zLocalSchema, (char*)0); |
| 1567 | db_delete_on_failure("./_FOSSIL_"); |
| 1568 | db_open_local(); |
| 1569 | db_lset("repository", blob_str(&path)); |
| 1570 | db_record_repository_filename(blob_str(&path)); |
| 1571 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1572 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| @@ -1597,14 +1610,14 @@ | |
| 1610 | "SELECT '(global)', value FROM global_config WHERE name=%Q", |
| 1611 | zName |
| 1612 | ); |
| 1613 | } |
| 1614 | if( db_step(&q)==SQLITE_ROW ){ |
| 1615 | fossil_print("%-20s %-8s %s\n", zName, db_column_text(&q, 0), |
| 1616 | db_column_text(&q, 1)); |
| 1617 | }else{ |
| 1618 | fossil_print("%-20s\n", zName); |
| 1619 | } |
| 1620 | db_finalize(&q); |
| 1621 | } |
| 1622 | |
| 1623 | |
| @@ -1853,9 +1866,9 @@ | |
| 1866 | void test_timespan_cmd(void){ |
| 1867 | double rDiff; |
| 1868 | if( g.argc!=3 ) usage("TIMESTAMP"); |
| 1869 | sqlite3_open(":memory:", &g.db); |
| 1870 | rDiff = db_double(0.0, "SELECT julianday('now') - julianday(%Q)", g.argv[2]); |
| 1871 | fossil_print("Time differences: %s\n", db_timespan_name(rDiff)); |
| 1872 | sqlite3_close(g.db); |
| 1873 | g.db = 0; |
| 1874 | } |
| 1875 |
+7
-13
| --- src/deltacmd.c | ||
| +++ src/deltacmd.c | ||
| @@ -52,21 +52,18 @@ | ||
| 52 | 52 | Blob orig, target, delta; |
| 53 | 53 | if( g.argc!=5 ){ |
| 54 | 54 | usage("ORIGIN TARGET DELTA"); |
| 55 | 55 | } |
| 56 | 56 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 57 | - fprintf(stderr,"cannot read %s\n", g.argv[2]); | |
| 58 | - fossil_exit(1); | |
| 57 | + fossil_fatal("cannot read %s\n", g.argv[2]); | |
| 59 | 58 | } |
| 60 | 59 | if( blob_read_from_file(&target, g.argv[3])<0 ){ |
| 61 | - fprintf(stderr,"cannot read %s\n", g.argv[3]); | |
| 62 | - fossil_exit(1); | |
| 60 | + fossil_fatal("cannot read %s\n", g.argv[3]); | |
| 63 | 61 | } |
| 64 | 62 | blob_delta_create(&orig, &target, &delta); |
| 65 | 63 | if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){ |
| 66 | - fprintf(stderr,"cannot write %s\n", g.argv[4]); | |
| 67 | - fossil_exit(1); | |
| 64 | + fossil_fatal("cannot write %s\n", g.argv[4]); | |
| 68 | 65 | } |
| 69 | 66 | blob_reset(&orig); |
| 70 | 67 | blob_reset(&target); |
| 71 | 68 | blob_reset(&delta); |
| 72 | 69 | } |
| @@ -114,21 +111,18 @@ | ||
| 114 | 111 | Blob orig, target, delta; |
| 115 | 112 | if( g.argc!=5 ){ |
| 116 | 113 | usage("ORIGIN DELTA TARGET"); |
| 117 | 114 | } |
| 118 | 115 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 119 | - fprintf(stderr,"cannot read %s\n", g.argv[2]); | |
| 120 | - fossil_exit(1); | |
| 116 | + fossil_fatal("cannot read %s\n", g.argv[2]); | |
| 121 | 117 | } |
| 122 | 118 | if( blob_read_from_file(&delta, g.argv[3])<0 ){ |
| 123 | - fprintf(stderr,"cannot read %s\n", g.argv[3]); | |
| 124 | - fossil_exit(1); | |
| 119 | + fossil_fatal("cannot read %s\n", g.argv[3]); | |
| 125 | 120 | } |
| 126 | 121 | blob_delta_apply(&orig, &delta, &target); |
| 127 | 122 | if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){ |
| 128 | - fprintf(stderr,"cannot write %s\n", g.argv[4]); | |
| 129 | - fossil_exit(1); | |
| 123 | + fossil_fatal("cannot write %s\n", g.argv[4]); | |
| 130 | 124 | } |
| 131 | 125 | blob_reset(&orig); |
| 132 | 126 | blob_reset(&target); |
| 133 | 127 | blob_reset(&delta); |
| 134 | 128 | } |
| @@ -152,7 +146,7 @@ | ||
| 152 | 146 | blob_delta_apply(&f1, &d12, &a2); |
| 153 | 147 | blob_delta_apply(&f2, &d21, &a1); |
| 154 | 148 | if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){ |
| 155 | 149 | fossil_panic("delta test failed"); |
| 156 | 150 | } |
| 157 | - printf("ok\n"); | |
| 151 | + fossil_print("ok\n"); | |
| 158 | 152 | } |
| 159 | 153 |
| --- src/deltacmd.c | |
| +++ src/deltacmd.c | |
| @@ -52,21 +52,18 @@ | |
| 52 | Blob orig, target, delta; |
| 53 | if( g.argc!=5 ){ |
| 54 | usage("ORIGIN TARGET DELTA"); |
| 55 | } |
| 56 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 57 | fprintf(stderr,"cannot read %s\n", g.argv[2]); |
| 58 | fossil_exit(1); |
| 59 | } |
| 60 | if( blob_read_from_file(&target, g.argv[3])<0 ){ |
| 61 | fprintf(stderr,"cannot read %s\n", g.argv[3]); |
| 62 | fossil_exit(1); |
| 63 | } |
| 64 | blob_delta_create(&orig, &target, &delta); |
| 65 | if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){ |
| 66 | fprintf(stderr,"cannot write %s\n", g.argv[4]); |
| 67 | fossil_exit(1); |
| 68 | } |
| 69 | blob_reset(&orig); |
| 70 | blob_reset(&target); |
| 71 | blob_reset(&delta); |
| 72 | } |
| @@ -114,21 +111,18 @@ | |
| 114 | Blob orig, target, delta; |
| 115 | if( g.argc!=5 ){ |
| 116 | usage("ORIGIN DELTA TARGET"); |
| 117 | } |
| 118 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 119 | fprintf(stderr,"cannot read %s\n", g.argv[2]); |
| 120 | fossil_exit(1); |
| 121 | } |
| 122 | if( blob_read_from_file(&delta, g.argv[3])<0 ){ |
| 123 | fprintf(stderr,"cannot read %s\n", g.argv[3]); |
| 124 | fossil_exit(1); |
| 125 | } |
| 126 | blob_delta_apply(&orig, &delta, &target); |
| 127 | if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){ |
| 128 | fprintf(stderr,"cannot write %s\n", g.argv[4]); |
| 129 | fossil_exit(1); |
| 130 | } |
| 131 | blob_reset(&orig); |
| 132 | blob_reset(&target); |
| 133 | blob_reset(&delta); |
| 134 | } |
| @@ -152,7 +146,7 @@ | |
| 152 | blob_delta_apply(&f1, &d12, &a2); |
| 153 | blob_delta_apply(&f2, &d21, &a1); |
| 154 | if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){ |
| 155 | fossil_panic("delta test failed"); |
| 156 | } |
| 157 | printf("ok\n"); |
| 158 | } |
| 159 |
| --- src/deltacmd.c | |
| +++ src/deltacmd.c | |
| @@ -52,21 +52,18 @@ | |
| 52 | Blob orig, target, delta; |
| 53 | if( g.argc!=5 ){ |
| 54 | usage("ORIGIN TARGET DELTA"); |
| 55 | } |
| 56 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 57 | fossil_fatal("cannot read %s\n", g.argv[2]); |
| 58 | } |
| 59 | if( blob_read_from_file(&target, g.argv[3])<0 ){ |
| 60 | fossil_fatal("cannot read %s\n", g.argv[3]); |
| 61 | } |
| 62 | blob_delta_create(&orig, &target, &delta); |
| 63 | if( blob_write_to_file(&delta, g.argv[4])<blob_size(&delta) ){ |
| 64 | fossil_fatal("cannot write %s\n", g.argv[4]); |
| 65 | } |
| 66 | blob_reset(&orig); |
| 67 | blob_reset(&target); |
| 68 | blob_reset(&delta); |
| 69 | } |
| @@ -114,21 +111,18 @@ | |
| 111 | Blob orig, target, delta; |
| 112 | if( g.argc!=5 ){ |
| 113 | usage("ORIGIN DELTA TARGET"); |
| 114 | } |
| 115 | if( blob_read_from_file(&orig, g.argv[2])<0 ){ |
| 116 | fossil_fatal("cannot read %s\n", g.argv[2]); |
| 117 | } |
| 118 | if( blob_read_from_file(&delta, g.argv[3])<0 ){ |
| 119 | fossil_fatal("cannot read %s\n", g.argv[3]); |
| 120 | } |
| 121 | blob_delta_apply(&orig, &delta, &target); |
| 122 | if( blob_write_to_file(&target, g.argv[4])<blob_size(&target) ){ |
| 123 | fossil_fatal("cannot write %s\n", g.argv[4]); |
| 124 | } |
| 125 | blob_reset(&orig); |
| 126 | blob_reset(&target); |
| 127 | blob_reset(&delta); |
| 128 | } |
| @@ -152,7 +146,7 @@ | |
| 146 | blob_delta_apply(&f1, &d12, &a2); |
| 147 | blob_delta_apply(&f2, &d21, &a1); |
| 148 | if( blob_compare(&f1,&a1) || blob_compare(&f2, &a2) ){ |
| 149 | fossil_panic("delta test failed"); |
| 150 | } |
| 151 | fossil_print("ok\n"); |
| 152 | } |
| 153 |
+26
-11
| --- src/descendants.c | ||
| +++ src/descendants.c | ||
| @@ -159,60 +159,75 @@ | ||
| 159 | 159 | ** the "ok" table. |
| 160 | 160 | */ |
| 161 | 161 | void compute_ancestors(int rid, int N){ |
| 162 | 162 | Bag seen; |
| 163 | 163 | PQueue queue; |
| 164 | + Stmt ins; | |
| 165 | + Stmt q; | |
| 164 | 166 | bag_init(&seen); |
| 165 | 167 | pqueue_init(&queue); |
| 166 | 168 | bag_insert(&seen, rid); |
| 167 | 169 | pqueue_insert(&queue, rid, 0.0, 0); |
| 170 | + db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); | |
| 171 | + db_prepare(&q, | |
| 172 | + "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" | |
| 173 | + " WHERE a.cid=:rid" | |
| 174 | + ); | |
| 168 | 175 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 169 | - Stmt q; | |
| 170 | - db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid); | |
| 171 | - db_prepare(&q, | |
| 172 | - "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" | |
| 173 | - " WHERE a.cid=%d", rid | |
| 174 | - ); | |
| 176 | + db_bind_int(&ins, ":rid", rid); | |
| 177 | + db_step(&ins); | |
| 178 | + db_reset(&ins); | |
| 179 | + db_bind_int(&q, ":rid", rid); | |
| 175 | 180 | while( db_step(&q)==SQLITE_ROW ){ |
| 176 | 181 | int pid = db_column_int(&q, 0); |
| 177 | 182 | double mtime = db_column_double(&q, 1); |
| 178 | 183 | if( bag_insert(&seen, pid) ){ |
| 179 | 184 | pqueue_insert(&queue, pid, -mtime, 0); |
| 180 | 185 | } |
| 181 | 186 | } |
| 182 | - db_finalize(&q); | |
| 187 | + db_reset(&q); | |
| 183 | 188 | } |
| 184 | 189 | bag_clear(&seen); |
| 185 | 190 | pqueue_clear(&queue); |
| 191 | + db_finalize(&ins); | |
| 192 | + db_finalize(&q); | |
| 186 | 193 | } |
| 187 | 194 | |
| 188 | 195 | /* |
| 189 | 196 | ** Load the record ID rid and up to N-1 closest descendants into |
| 190 | 197 | ** the "ok" table. |
| 191 | 198 | */ |
| 192 | 199 | void compute_descendants(int rid, int N){ |
| 193 | 200 | Bag seen; |
| 194 | 201 | PQueue queue; |
| 202 | + Stmt ins; | |
| 203 | + Stmt q; | |
| 204 | + | |
| 195 | 205 | bag_init(&seen); |
| 196 | 206 | pqueue_init(&queue); |
| 197 | 207 | bag_insert(&seen, rid); |
| 198 | 208 | pqueue_insert(&queue, rid, 0.0, 0); |
| 209 | + db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); | |
| 210 | + db_prepare(&q, "SELECT cid, mtime FROM plink WHERE pid=:rid"); | |
| 199 | 211 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 200 | - Stmt q; | |
| 201 | - db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid); | |
| 202 | - db_prepare(&q,"SELECT cid, mtime FROM plink WHERE pid=%d", rid); | |
| 212 | + db_bind_int(&ins, ":rid", rid); | |
| 213 | + db_step(&ins); | |
| 214 | + db_reset(&ins); | |
| 215 | + db_bind_int(&q, ":rid", rid); | |
| 203 | 216 | while( db_step(&q)==SQLITE_ROW ){ |
| 204 | 217 | int pid = db_column_int(&q, 0); |
| 205 | 218 | double mtime = db_column_double(&q, 1); |
| 206 | 219 | if( bag_insert(&seen, pid) ){ |
| 207 | 220 | pqueue_insert(&queue, pid, mtime, 0); |
| 208 | 221 | } |
| 209 | 222 | } |
| 210 | - db_finalize(&q); | |
| 223 | + db_reset(&q); | |
| 211 | 224 | } |
| 212 | 225 | bag_clear(&seen); |
| 213 | 226 | pqueue_clear(&queue); |
| 227 | + db_finalize(&ins); | |
| 228 | + db_finalize(&q); | |
| 214 | 229 | } |
| 215 | 230 | |
| 216 | 231 | /* |
| 217 | 232 | ** COMMAND: descendants |
| 218 | 233 | ** |
| 219 | 234 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -159,60 +159,75 @@ | |
| 159 | ** the "ok" table. |
| 160 | */ |
| 161 | void compute_ancestors(int rid, int N){ |
| 162 | Bag seen; |
| 163 | PQueue queue; |
| 164 | bag_init(&seen); |
| 165 | pqueue_init(&queue); |
| 166 | bag_insert(&seen, rid); |
| 167 | pqueue_insert(&queue, rid, 0.0, 0); |
| 168 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 169 | Stmt q; |
| 170 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid); |
| 171 | db_prepare(&q, |
| 172 | "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" |
| 173 | " WHERE a.cid=%d", rid |
| 174 | ); |
| 175 | while( db_step(&q)==SQLITE_ROW ){ |
| 176 | int pid = db_column_int(&q, 0); |
| 177 | double mtime = db_column_double(&q, 1); |
| 178 | if( bag_insert(&seen, pid) ){ |
| 179 | pqueue_insert(&queue, pid, -mtime, 0); |
| 180 | } |
| 181 | } |
| 182 | db_finalize(&q); |
| 183 | } |
| 184 | bag_clear(&seen); |
| 185 | pqueue_clear(&queue); |
| 186 | } |
| 187 | |
| 188 | /* |
| 189 | ** Load the record ID rid and up to N-1 closest descendants into |
| 190 | ** the "ok" table. |
| 191 | */ |
| 192 | void compute_descendants(int rid, int N){ |
| 193 | Bag seen; |
| 194 | PQueue queue; |
| 195 | bag_init(&seen); |
| 196 | pqueue_init(&queue); |
| 197 | bag_insert(&seen, rid); |
| 198 | pqueue_insert(&queue, rid, 0.0, 0); |
| 199 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 200 | Stmt q; |
| 201 | db_multi_exec("INSERT OR IGNORE INTO ok VALUES(%d)", rid); |
| 202 | db_prepare(&q,"SELECT cid, mtime FROM plink WHERE pid=%d", rid); |
| 203 | while( db_step(&q)==SQLITE_ROW ){ |
| 204 | int pid = db_column_int(&q, 0); |
| 205 | double mtime = db_column_double(&q, 1); |
| 206 | if( bag_insert(&seen, pid) ){ |
| 207 | pqueue_insert(&queue, pid, mtime, 0); |
| 208 | } |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | } |
| 212 | bag_clear(&seen); |
| 213 | pqueue_clear(&queue); |
| 214 | } |
| 215 | |
| 216 | /* |
| 217 | ** COMMAND: descendants |
| 218 | ** |
| 219 |
| --- src/descendants.c | |
| +++ src/descendants.c | |
| @@ -159,60 +159,75 @@ | |
| 159 | ** the "ok" table. |
| 160 | */ |
| 161 | void compute_ancestors(int rid, int N){ |
| 162 | Bag seen; |
| 163 | PQueue queue; |
| 164 | Stmt ins; |
| 165 | Stmt q; |
| 166 | bag_init(&seen); |
| 167 | pqueue_init(&queue); |
| 168 | bag_insert(&seen, rid); |
| 169 | pqueue_insert(&queue, rid, 0.0, 0); |
| 170 | db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); |
| 171 | db_prepare(&q, |
| 172 | "SELECT a.pid, b.mtime FROM plink a LEFT JOIN plink b ON b.cid=a.pid" |
| 173 | " WHERE a.cid=:rid" |
| 174 | ); |
| 175 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 176 | db_bind_int(&ins, ":rid", rid); |
| 177 | db_step(&ins); |
| 178 | db_reset(&ins); |
| 179 | db_bind_int(&q, ":rid", rid); |
| 180 | while( db_step(&q)==SQLITE_ROW ){ |
| 181 | int pid = db_column_int(&q, 0); |
| 182 | double mtime = db_column_double(&q, 1); |
| 183 | if( bag_insert(&seen, pid) ){ |
| 184 | pqueue_insert(&queue, pid, -mtime, 0); |
| 185 | } |
| 186 | } |
| 187 | db_reset(&q); |
| 188 | } |
| 189 | bag_clear(&seen); |
| 190 | pqueue_clear(&queue); |
| 191 | db_finalize(&ins); |
| 192 | db_finalize(&q); |
| 193 | } |
| 194 | |
| 195 | /* |
| 196 | ** Load the record ID rid and up to N-1 closest descendants into |
| 197 | ** the "ok" table. |
| 198 | */ |
| 199 | void compute_descendants(int rid, int N){ |
| 200 | Bag seen; |
| 201 | PQueue queue; |
| 202 | Stmt ins; |
| 203 | Stmt q; |
| 204 | |
| 205 | bag_init(&seen); |
| 206 | pqueue_init(&queue); |
| 207 | bag_insert(&seen, rid); |
| 208 | pqueue_insert(&queue, rid, 0.0, 0); |
| 209 | db_prepare(&ins, "INSERT OR IGNORE INTO ok VALUES(:rid)"); |
| 210 | db_prepare(&q, "SELECT cid, mtime FROM plink WHERE pid=:rid"); |
| 211 | while( (N--)>0 && (rid = pqueue_extract(&queue, 0))!=0 ){ |
| 212 | db_bind_int(&ins, ":rid", rid); |
| 213 | db_step(&ins); |
| 214 | db_reset(&ins); |
| 215 | db_bind_int(&q, ":rid", rid); |
| 216 | while( db_step(&q)==SQLITE_ROW ){ |
| 217 | int pid = db_column_int(&q, 0); |
| 218 | double mtime = db_column_double(&q, 1); |
| 219 | if( bag_insert(&seen, pid) ){ |
| 220 | pqueue_insert(&queue, pid, mtime, 0); |
| 221 | } |
| 222 | } |
| 223 | db_reset(&q); |
| 224 | } |
| 225 | bag_clear(&seen); |
| 226 | pqueue_clear(&queue); |
| 227 | db_finalize(&ins); |
| 228 | db_finalize(&q); |
| 229 | } |
| 230 | |
| 231 | /* |
| 232 | ** COMMAND: descendants |
| 233 | ** |
| 234 |
+88
-18
| --- src/diff.c | ||
| +++ src/diff.c | ||
| @@ -590,15 +590,15 @@ | ||
| 590 | 590 | int i; |
| 591 | 591 | int *R; |
| 592 | 592 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 593 | 593 | blob_read_from_file(&a, g.argv[2]); |
| 594 | 594 | for(i=3; i<g.argc; i++){ |
| 595 | - if( i>3 ) printf("-------------------------------\n"); | |
| 595 | + if( i>3 ) fossil_print("-------------------------------\n"); | |
| 596 | 596 | blob_read_from_file(&b, g.argv[i]); |
| 597 | 597 | R = text_diff(&a, &b, 0, 0, 0); |
| 598 | 598 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 599 | - printf(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); | |
| 599 | + fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); | |
| 600 | 600 | } |
| 601 | 601 | /* free(R); */ |
| 602 | 602 | blob_reset(&b); |
| 603 | 603 | } |
| 604 | 604 | } |
| @@ -626,17 +626,21 @@ | ||
| 626 | 626 | ** of the following structure. |
| 627 | 627 | */ |
| 628 | 628 | typedef struct Annotator Annotator; |
| 629 | 629 | struct Annotator { |
| 630 | 630 | DContext c; /* The diff-engine context */ |
| 631 | - struct { /* Lines of the original files... */ | |
| 631 | + struct AnnLine { /* Lines of the original files... */ | |
| 632 | 632 | const char *z; /* The text of the line */ |
| 633 | - int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 633 | + short int n; /* Number of bytes (omitting trailing space and \n) */ | |
| 634 | + short int iLevel; /* Level at which tag was set */ | |
| 634 | 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | 636 | } *aOrig; |
| 636 | 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | + int iLevel; /* Current level */ | |
| 640 | + int nVers; /* Number of versions analyzed */ | |
| 641 | + char **azVers; /* Names of versions analyzed */ | |
| 638 | 642 | }; |
| 639 | 643 | |
| 640 | 644 | /* |
| 641 | 645 | ** Initialize the annotation process by specifying the file that is |
| 642 | 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | ||
| 668 | 672 | ** pParent. Memory to hold zPName is leaked. |
| 669 | 673 | */ |
| 670 | 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | 675 | int i, j; |
| 672 | 676 | int lnTo; |
| 677 | + int iPrevLevel; | |
| 678 | + int iThisLevel; | |
| 673 | 679 | |
| 674 | 680 | /* Prepare the parent file to be diffed */ |
| 675 | 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | 682 | &p->c.nFrom, 1); |
| 677 | 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | ||
| 683 | 689 | diff_all(&p->c); |
| 684 | 690 | |
| 685 | 691 | /* Where new lines are inserted on this difference, record the |
| 686 | 692 | ** zPName as the source of the new line. |
| 687 | 693 | */ |
| 694 | + iPrevLevel = p->iLevel; | |
| 695 | + p->iLevel++; | |
| 696 | + iThisLevel = p->iLevel; | |
| 688 | 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | - for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ | |
| 690 | - p->aOrig[lnTo].zSrc = zPName; | |
| 698 | + struct AnnLine *x = &p->aOrig[lnTo]; | |
| 699 | + for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ | |
| 700 | + if( x->zSrc==0 || x->iLevel==iPrevLevel ){ | |
| 701 | + x->zSrc = zPName; | |
| 702 | + x->iLevel = iThisLevel; | |
| 703 | + } | |
| 691 | 704 | } |
| 692 | 705 | lnTo += p->c.aEdit[i+2]; |
| 693 | 706 | } |
| 694 | 707 | |
| 695 | 708 | /* Clear out the diff results */ |
| @@ -730,20 +743,30 @@ | ||
| 730 | 743 | } |
| 731 | 744 | } |
| 732 | 745 | for(i=0; i<x.nOrig; i++){ |
| 733 | 746 | const char *zSrc = x.aOrig[i].zSrc; |
| 734 | 747 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 735 | - printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); | |
| 748 | + fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); | |
| 736 | 749 | } |
| 737 | 750 | } |
| 738 | 751 | |
| 752 | +/* Annotation flags */ | |
| 753 | +#define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ | |
| 754 | + | |
| 739 | 755 | /* |
| 740 | 756 | ** Compute a complete annotation on a file. The file is identified |
| 741 | 757 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | 758 | ** it was checked in (mlink.mid). |
| 743 | 759 | */ |
| 744 | -static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ | |
| 760 | +static void annotate_file( | |
| 761 | + Annotator *p, /* The annotator */ | |
| 762 | + int fnid, /* The name of the file to be annotated */ | |
| 763 | + int mid, /* The specific version of the file for this step */ | |
| 764 | + int webLabel, /* Use web-style annotations if true */ | |
| 765 | + int iLimit, /* Limit the number of levels if greater than zero */ | |
| 766 | + int annFlags /* Flags to alter the annotation */ | |
| 767 | +){ | |
| 745 | 768 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | 769 | Blob step; /* Text of previous revision */ |
| 747 | 770 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | 771 | char *zLabel; /* Label to apply to a line */ |
| 749 | 772 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -759,31 +782,40 @@ | ||
| 759 | 782 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 760 | 783 | compute_ancestors(mid, 1000000000); |
| 761 | 784 | annotation_start(p, &toAnnotate); |
| 762 | 785 | |
| 763 | 786 | db_prepare(&q, |
| 764 | - "SELECT mlink.fid, blob.uuid, date(event.mtime), " | |
| 787 | + "SELECT mlink.fid," | |
| 788 | + " (SELECT uuid FROM blob WHERE rid=mlink.%s)," | |
| 789 | + " date(event.mtime), " | |
| 765 | 790 | " coalesce(event.euser,event.user) " |
| 766 | - " FROM mlink, blob, event" | |
| 791 | + " FROM mlink, event" | |
| 767 | 792 | " WHERE mlink.fnid=%d" |
| 768 | 793 | " AND mlink.mid IN ok" |
| 769 | - " AND blob.rid=mlink.mid" | |
| 770 | 794 | " AND event.objid=mlink.mid" |
| 771 | - " ORDER BY event.mtime DESC", | |
| 772 | - fnid | |
| 795 | + " ORDER BY event.mtime DESC" | |
| 796 | + " LIMIT %d", | |
| 797 | + (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid", | |
| 798 | + fnid, | |
| 799 | + iLimit>0 ? iLimit : 10000000 | |
| 773 | 800 | ); |
| 774 | 801 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | 802 | int pid = db_column_int(&q, 0); |
| 776 | 803 | const char *zUuid = db_column_text(&q, 1); |
| 777 | 804 | const char *zDate = db_column_text(&q, 2); |
| 778 | 805 | const char *zUser = db_column_text(&q, 3); |
| 779 | 806 | if( webLabel ){ |
| 780 | - zLabel = mprintf("<a href='%s/info/%s'>%.10s</a> %s %9.9s", | |
| 781 | - g.zTop, zUuid, zUuid, zDate, zUser); | |
| 807 | + zLabel = mprintf( | |
| 808 | + "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", | |
| 809 | + g.zTop, zUuid, zUuid, zDate, zUser | |
| 810 | + ); | |
| 782 | 811 | }else{ |
| 783 | 812 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 784 | 813 | } |
| 814 | + p->nVers++; | |
| 815 | + p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); | |
| 816 | + p->azVers[p->nVers-1] = zLabel; | |
| 785 | 817 | content_get(pid, &step); |
| 786 | 818 | annotation_step(p, &step, zLabel); |
| 787 | 819 | blob_reset(&step); |
| 788 | 820 | } |
| 789 | 821 | db_finalize(&q); |
| @@ -799,22 +831,37 @@ | ||
| 799 | 831 | */ |
| 800 | 832 | void annotation_page(void){ |
| 801 | 833 | int mid; |
| 802 | 834 | int fnid; |
| 803 | 835 | int i; |
| 836 | + int iLimit; | |
| 837 | + int annFlags = 0; | |
| 804 | 838 | Annotator ann; |
| 805 | 839 | |
| 806 | 840 | login_check_credentials(); |
| 807 | 841 | if( !g.okRead ){ login_needed(); return; } |
| 808 | 842 | mid = name_to_rid(PD("checkin","0")); |
| 809 | 843 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 810 | 844 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 845 | + iLimit = atoi(PD("limit","-1")); | |
| 811 | 846 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 812 | 847 | fossil_redirect_home(); |
| 813 | 848 | } |
| 814 | 849 | style_header("File Annotation"); |
| 815 | - annotate_file(&ann, fnid, mid, g.okHistory); | |
| 850 | + if( P("filevers") ) annFlags |= ANN_FILE_VERS; | |
| 851 | + annotate_file(&ann, fnid, mid, g.okHistory, iLimit, annFlags); | |
| 852 | + if( P("log") ){ | |
| 853 | + int i; | |
| 854 | + @ <h2>Versions analyzed:</h2> | |
| 855 | + @ <ol> | |
| 856 | + for(i=0; i<ann.nVers; i++){ | |
| 857 | + @ <li><tt>%s(ann.azVers[i])</tt></li> | |
| 858 | + } | |
| 859 | + @ </ol> | |
| 860 | + @ <hr> | |
| 861 | + @ <h2>Annotation:</h2> | |
| 862 | + } | |
| 816 | 863 | @ <pre> |
| 817 | 864 | for(i=0; i<ann.nOrig; i++){ |
| 818 | 865 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 819 | 866 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 820 | 867 | } |
| @@ -827,20 +874,35 @@ | ||
| 827 | 874 | ** |
| 828 | 875 | ** %fossil annotate FILENAME |
| 829 | 876 | ** |
| 830 | 877 | ** Output the text of a file with markings to show when each line of |
| 831 | 878 | ** the file was last modified. |
| 879 | +** | |
| 880 | +** Options: | |
| 881 | +** --limit N Only look backwards in time by N versions | |
| 882 | +** --log List all versions analyzed | |
| 883 | +** --filevers Show file version numbers rather than check-in versions | |
| 832 | 884 | */ |
| 833 | 885 | void annotate_cmd(void){ |
| 834 | 886 | int fnid; /* Filename ID */ |
| 835 | 887 | int fid; /* File instance ID */ |
| 836 | 888 | int mid; /* Manifest where file was checked in */ |
| 837 | 889 | Blob treename; /* FILENAME translated to canonical form */ |
| 838 | 890 | char *zFilename; /* Cannonical filename */ |
| 839 | 891 | Annotator ann; /* The annotation of the file */ |
| 840 | 892 | int i; /* Loop counter */ |
| 893 | + const char *zLimit; /* The value to the --limit option */ | |
| 894 | + int iLimit; /* How far back in time to look */ | |
| 895 | + int showLog; /* True to show the log */ | |
| 896 | + int fileVers; /* Show file version instead of check-in versions */ | |
| 897 | + int annFlags = 0; /* Flags to control annotation properties */ | |
| 841 | 898 | |
| 899 | + zLimit = find_option("limit",0,1); | |
| 900 | + if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; | |
| 901 | + iLimit = atoi(zLimit); | |
| 902 | + showLog = find_option("log",0,0)!=0; | |
| 903 | + fileVers = find_option("filevers",0,0)!=0; | |
| 842 | 904 | db_must_be_within_tree(); |
| 843 | 905 | if (g.argc<3) { |
| 844 | 906 | usage("FILENAME"); |
| 845 | 907 | } |
| 846 | 908 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -855,10 +917,18 @@ | ||
| 855 | 917 | } |
| 856 | 918 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 857 | 919 | if( mid==0 ){ |
| 858 | 920 | fossil_panic("unable to find manifest"); |
| 859 | 921 | } |
| 860 | - annotate_file(&ann, fnid, mid, 0); | |
| 922 | + if( fileVers ) annFlags |= ANN_FILE_VERS; | |
| 923 | + annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); | |
| 924 | + if( showLog ){ | |
| 925 | + for(i=0; i<ann.nVers; i++){ | |
| 926 | + printf("version %3d: %s\n", i+1, ann.azVers[i]); | |
| 927 | + } | |
| 928 | + printf("---------------------------------------------------\n"); | |
| 929 | + } | |
| 861 | 930 | for(i=0; i<ann.nOrig; i++){ |
| 862 | - printf("%s: %.*s\n", ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 931 | + fossil_print("%s: %.*s\n", | |
| 932 | + ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); | |
| 863 | 933 | } |
| 864 | 934 | } |
| 865 | 935 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -590,15 +590,15 @@ | |
| 590 | int i; |
| 591 | int *R; |
| 592 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 593 | blob_read_from_file(&a, g.argv[2]); |
| 594 | for(i=3; i<g.argc; i++){ |
| 595 | if( i>3 ) printf("-------------------------------\n"); |
| 596 | blob_read_from_file(&b, g.argv[i]); |
| 597 | R = text_diff(&a, &b, 0, 0, 0); |
| 598 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 599 | printf(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); |
| 600 | } |
| 601 | /* free(R); */ |
| 602 | blob_reset(&b); |
| 603 | } |
| 604 | } |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | const char *zSrc; /* Tag showing origin of this line */ |
| 635 | } *aOrig; |
| 636 | int nOrig; /* Number of elements in aOrig[] */ |
| 637 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 638 | }; |
| 639 | |
| 640 | /* |
| 641 | ** Initialize the annotation process by specifying the file that is |
| 642 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 668 | ** pParent. Memory to hold zPName is leaked. |
| 669 | */ |
| 670 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 671 | int i, j; |
| 672 | int lnTo; |
| 673 | |
| 674 | /* Prepare the parent file to be diffed */ |
| 675 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 676 | &p->c.nFrom, 1); |
| 677 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 683 | diff_all(&p->c); |
| 684 | |
| 685 | /* Where new lines are inserted on this difference, record the |
| 686 | ** zPName as the source of the new line. |
| 687 | */ |
| 688 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 689 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++){ |
| 690 | p->aOrig[lnTo].zSrc = zPName; |
| 691 | } |
| 692 | lnTo += p->c.aEdit[i+2]; |
| 693 | } |
| 694 | |
| 695 | /* Clear out the diff results */ |
| @@ -730,20 +743,30 @@ | |
| 730 | } |
| 731 | } |
| 732 | for(i=0; i<x.nOrig; i++){ |
| 733 | const char *zSrc = x.aOrig[i].zSrc; |
| 734 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 735 | printf("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 736 | } |
| 737 | } |
| 738 | |
| 739 | /* |
| 740 | ** Compute a complete annotation on a file. The file is identified |
| 741 | ** by its filename number (filename.fnid) and the baseline in which |
| 742 | ** it was checked in (mlink.mid). |
| 743 | */ |
| 744 | static void annotate_file(Annotator *p, int fnid, int mid, int webLabel){ |
| 745 | Blob toAnnotate; /* Text of the final version of the file */ |
| 746 | Blob step; /* Text of previous revision */ |
| 747 | int rid; /* Artifact ID of the file being annotated */ |
| 748 | char *zLabel; /* Label to apply to a line */ |
| 749 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -759,31 +782,40 @@ | |
| 759 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 760 | compute_ancestors(mid, 1000000000); |
| 761 | annotation_start(p, &toAnnotate); |
| 762 | |
| 763 | db_prepare(&q, |
| 764 | "SELECT mlink.fid, blob.uuid, date(event.mtime), " |
| 765 | " coalesce(event.euser,event.user) " |
| 766 | " FROM mlink, blob, event" |
| 767 | " WHERE mlink.fnid=%d" |
| 768 | " AND mlink.mid IN ok" |
| 769 | " AND blob.rid=mlink.mid" |
| 770 | " AND event.objid=mlink.mid" |
| 771 | " ORDER BY event.mtime DESC", |
| 772 | fnid |
| 773 | ); |
| 774 | while( db_step(&q)==SQLITE_ROW ){ |
| 775 | int pid = db_column_int(&q, 0); |
| 776 | const char *zUuid = db_column_text(&q, 1); |
| 777 | const char *zDate = db_column_text(&q, 2); |
| 778 | const char *zUser = db_column_text(&q, 3); |
| 779 | if( webLabel ){ |
| 780 | zLabel = mprintf("<a href='%s/info/%s'>%.10s</a> %s %9.9s", |
| 781 | g.zTop, zUuid, zUuid, zDate, zUser); |
| 782 | }else{ |
| 783 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 784 | } |
| 785 | content_get(pid, &step); |
| 786 | annotation_step(p, &step, zLabel); |
| 787 | blob_reset(&step); |
| 788 | } |
| 789 | db_finalize(&q); |
| @@ -799,22 +831,37 @@ | |
| 799 | */ |
| 800 | void annotation_page(void){ |
| 801 | int mid; |
| 802 | int fnid; |
| 803 | int i; |
| 804 | Annotator ann; |
| 805 | |
| 806 | login_check_credentials(); |
| 807 | if( !g.okRead ){ login_needed(); return; } |
| 808 | mid = name_to_rid(PD("checkin","0")); |
| 809 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 810 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 811 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 812 | fossil_redirect_home(); |
| 813 | } |
| 814 | style_header("File Annotation"); |
| 815 | annotate_file(&ann, fnid, mid, g.okHistory); |
| 816 | @ <pre> |
| 817 | for(i=0; i<ann.nOrig; i++){ |
| 818 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 819 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 820 | } |
| @@ -827,20 +874,35 @@ | |
| 827 | ** |
| 828 | ** %fossil annotate FILENAME |
| 829 | ** |
| 830 | ** Output the text of a file with markings to show when each line of |
| 831 | ** the file was last modified. |
| 832 | */ |
| 833 | void annotate_cmd(void){ |
| 834 | int fnid; /* Filename ID */ |
| 835 | int fid; /* File instance ID */ |
| 836 | int mid; /* Manifest where file was checked in */ |
| 837 | Blob treename; /* FILENAME translated to canonical form */ |
| 838 | char *zFilename; /* Cannonical filename */ |
| 839 | Annotator ann; /* The annotation of the file */ |
| 840 | int i; /* Loop counter */ |
| 841 | |
| 842 | db_must_be_within_tree(); |
| 843 | if (g.argc<3) { |
| 844 | usage("FILENAME"); |
| 845 | } |
| 846 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -855,10 +917,18 @@ | |
| 855 | } |
| 856 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 857 | if( mid==0 ){ |
| 858 | fossil_panic("unable to find manifest"); |
| 859 | } |
| 860 | annotate_file(&ann, fnid, mid, 0); |
| 861 | for(i=0; i<ann.nOrig; i++){ |
| 862 | printf("%s: %.*s\n", ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 863 | } |
| 864 | } |
| 865 |
| --- src/diff.c | |
| +++ src/diff.c | |
| @@ -590,15 +590,15 @@ | |
| 590 | int i; |
| 591 | int *R; |
| 592 | if( g.argc<4 ) usage("FILE1 FILE2 ..."); |
| 593 | blob_read_from_file(&a, g.argv[2]); |
| 594 | for(i=3; i<g.argc; i++){ |
| 595 | if( i>3 ) fossil_print("-------------------------------\n"); |
| 596 | blob_read_from_file(&b, g.argv[i]); |
| 597 | R = text_diff(&a, &b, 0, 0, 0); |
| 598 | for(r=0; R[r] || R[r+1] || R[r+2]; r += 3){ |
| 599 | fossil_print(" copy %4d delete %4d insert %4d\n", R[r], R[r+1], R[r+2]); |
| 600 | } |
| 601 | /* free(R); */ |
| 602 | blob_reset(&b); |
| 603 | } |
| 604 | } |
| @@ -626,17 +626,21 @@ | |
| 626 | ** of the following structure. |
| 627 | */ |
| 628 | typedef struct Annotator Annotator; |
| 629 | struct Annotator { |
| 630 | DContext c; /* The diff-engine context */ |
| 631 | struct AnnLine { /* Lines of the original files... */ |
| 632 | const char *z; /* The text of the line */ |
| 633 | short int n; /* Number of bytes (omitting trailing space and \n) */ |
| 634 | short int iLevel; /* Level at which tag was set */ |
| 635 | const char *zSrc; /* Tag showing origin of this line */ |
| 636 | } *aOrig; |
| 637 | int nOrig; /* Number of elements in aOrig[] */ |
| 638 | int nNoSrc; /* Number of entries where aOrig[].zSrc==NULL */ |
| 639 | int iLevel; /* Current level */ |
| 640 | int nVers; /* Number of versions analyzed */ |
| 641 | char **azVers; /* Names of versions analyzed */ |
| 642 | }; |
| 643 | |
| 644 | /* |
| 645 | ** Initialize the annotation process by specifying the file that is |
| 646 | ** to be annotated. The annotator takes control of the input Blob and |
| @@ -668,10 +672,12 @@ | |
| 672 | ** pParent. Memory to hold zPName is leaked. |
| 673 | */ |
| 674 | static int annotation_step(Annotator *p, Blob *pParent, char *zPName){ |
| 675 | int i, j; |
| 676 | int lnTo; |
| 677 | int iPrevLevel; |
| 678 | int iThisLevel; |
| 679 | |
| 680 | /* Prepare the parent file to be diffed */ |
| 681 | p->c.aFrom = break_into_lines(blob_str(pParent), blob_size(pParent), |
| 682 | &p->c.nFrom, 1); |
| 683 | if( p->c.aFrom==0 ){ |
| @@ -683,13 +689,20 @@ | |
| 689 | diff_all(&p->c); |
| 690 | |
| 691 | /* Where new lines are inserted on this difference, record the |
| 692 | ** zPName as the source of the new line. |
| 693 | */ |
| 694 | iPrevLevel = p->iLevel; |
| 695 | p->iLevel++; |
| 696 | iThisLevel = p->iLevel; |
| 697 | for(i=lnTo=0; i<p->c.nEdit; i+=3){ |
| 698 | struct AnnLine *x = &p->aOrig[lnTo]; |
| 699 | for(j=0; j<p->c.aEdit[i]; j++, lnTo++, x++){ |
| 700 | if( x->zSrc==0 || x->iLevel==iPrevLevel ){ |
| 701 | x->zSrc = zPName; |
| 702 | x->iLevel = iThisLevel; |
| 703 | } |
| 704 | } |
| 705 | lnTo += p->c.aEdit[i+2]; |
| 706 | } |
| 707 | |
| 708 | /* Clear out the diff results */ |
| @@ -730,20 +743,30 @@ | |
| 743 | } |
| 744 | } |
| 745 | for(i=0; i<x.nOrig; i++){ |
| 746 | const char *zSrc = x.aOrig[i].zSrc; |
| 747 | if( zSrc==0 ) zSrc = g.argv[g.argc-1]; |
| 748 | fossil_print("%10s: %.*s\n", zSrc, x.aOrig[i].n, x.aOrig[i].z); |
| 749 | } |
| 750 | } |
| 751 | |
| 752 | /* Annotation flags */ |
| 753 | #define ANN_FILE_VERS 0x001 /* Show file version rather than commit version */ |
| 754 | |
| 755 | /* |
| 756 | ** Compute a complete annotation on a file. The file is identified |
| 757 | ** by its filename number (filename.fnid) and the baseline in which |
| 758 | ** it was checked in (mlink.mid). |
| 759 | */ |
| 760 | static void annotate_file( |
| 761 | Annotator *p, /* The annotator */ |
| 762 | int fnid, /* The name of the file to be annotated */ |
| 763 | int mid, /* The specific version of the file for this step */ |
| 764 | int webLabel, /* Use web-style annotations if true */ |
| 765 | int iLimit, /* Limit the number of levels if greater than zero */ |
| 766 | int annFlags /* Flags to alter the annotation */ |
| 767 | ){ |
| 768 | Blob toAnnotate; /* Text of the final version of the file */ |
| 769 | Blob step; /* Text of previous revision */ |
| 770 | int rid; /* Artifact ID of the file being annotated */ |
| 771 | char *zLabel; /* Label to apply to a line */ |
| 772 | Stmt q; /* Query returning all ancestor versions */ |
| @@ -759,31 +782,40 @@ | |
| 782 | db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)"); |
| 783 | compute_ancestors(mid, 1000000000); |
| 784 | annotation_start(p, &toAnnotate); |
| 785 | |
| 786 | db_prepare(&q, |
| 787 | "SELECT mlink.fid," |
| 788 | " (SELECT uuid FROM blob WHERE rid=mlink.%s)," |
| 789 | " date(event.mtime), " |
| 790 | " coalesce(event.euser,event.user) " |
| 791 | " FROM mlink, event" |
| 792 | " WHERE mlink.fnid=%d" |
| 793 | " AND mlink.mid IN ok" |
| 794 | " AND event.objid=mlink.mid" |
| 795 | " ORDER BY event.mtime DESC" |
| 796 | " LIMIT %d", |
| 797 | (annFlags & ANN_FILE_VERS)!=0 ? "fid" : "mid", |
| 798 | fnid, |
| 799 | iLimit>0 ? iLimit : 10000000 |
| 800 | ); |
| 801 | while( db_step(&q)==SQLITE_ROW ){ |
| 802 | int pid = db_column_int(&q, 0); |
| 803 | const char *zUuid = db_column_text(&q, 1); |
| 804 | const char *zDate = db_column_text(&q, 2); |
| 805 | const char *zUser = db_column_text(&q, 3); |
| 806 | if( webLabel ){ |
| 807 | zLabel = mprintf( |
| 808 | "<a href='%s/info/%s' target='infowindow'>%.10s</a> %s %9.9s", |
| 809 | g.zTop, zUuid, zUuid, zDate, zUser |
| 810 | ); |
| 811 | }else{ |
| 812 | zLabel = mprintf("%.10s %s %9.9s", zUuid, zDate, zUser); |
| 813 | } |
| 814 | p->nVers++; |
| 815 | p->azVers = fossil_realloc(p->azVers, p->nVers*sizeof(p->azVers[0]) ); |
| 816 | p->azVers[p->nVers-1] = zLabel; |
| 817 | content_get(pid, &step); |
| 818 | annotation_step(p, &step, zLabel); |
| 819 | blob_reset(&step); |
| 820 | } |
| 821 | db_finalize(&q); |
| @@ -799,22 +831,37 @@ | |
| 831 | */ |
| 832 | void annotation_page(void){ |
| 833 | int mid; |
| 834 | int fnid; |
| 835 | int i; |
| 836 | int iLimit; |
| 837 | int annFlags = 0; |
| 838 | Annotator ann; |
| 839 | |
| 840 | login_check_credentials(); |
| 841 | if( !g.okRead ){ login_needed(); return; } |
| 842 | mid = name_to_rid(PD("checkin","0")); |
| 843 | fnid = db_int(0, "SELECT fnid FROM filename WHERE name=%Q", P("filename")); |
| 844 | if( mid==0 || fnid==0 ){ fossil_redirect_home(); } |
| 845 | iLimit = atoi(PD("limit","-1")); |
| 846 | if( !db_exists("SELECT 1 FROM mlink WHERE mid=%d AND fnid=%d",mid,fnid) ){ |
| 847 | fossil_redirect_home(); |
| 848 | } |
| 849 | style_header("File Annotation"); |
| 850 | if( P("filevers") ) annFlags |= ANN_FILE_VERS; |
| 851 | annotate_file(&ann, fnid, mid, g.okHistory, iLimit, annFlags); |
| 852 | if( P("log") ){ |
| 853 | int i; |
| 854 | @ <h2>Versions analyzed:</h2> |
| 855 | @ <ol> |
| 856 | for(i=0; i<ann.nVers; i++){ |
| 857 | @ <li><tt>%s(ann.azVers[i])</tt></li> |
| 858 | } |
| 859 | @ </ol> |
| 860 | @ <hr> |
| 861 | @ <h2>Annotation:</h2> |
| 862 | } |
| 863 | @ <pre> |
| 864 | for(i=0; i<ann.nOrig; i++){ |
| 865 | ((char*)ann.aOrig[i].z)[ann.aOrig[i].n] = 0; |
| 866 | @ %s(ann.aOrig[i].zSrc): %h(ann.aOrig[i].z) |
| 867 | } |
| @@ -827,20 +874,35 @@ | |
| 874 | ** |
| 875 | ** %fossil annotate FILENAME |
| 876 | ** |
| 877 | ** Output the text of a file with markings to show when each line of |
| 878 | ** the file was last modified. |
| 879 | ** |
| 880 | ** Options: |
| 881 | ** --limit N Only look backwards in time by N versions |
| 882 | ** --log List all versions analyzed |
| 883 | ** --filevers Show file version numbers rather than check-in versions |
| 884 | */ |
| 885 | void annotate_cmd(void){ |
| 886 | int fnid; /* Filename ID */ |
| 887 | int fid; /* File instance ID */ |
| 888 | int mid; /* Manifest where file was checked in */ |
| 889 | Blob treename; /* FILENAME translated to canonical form */ |
| 890 | char *zFilename; /* Cannonical filename */ |
| 891 | Annotator ann; /* The annotation of the file */ |
| 892 | int i; /* Loop counter */ |
| 893 | const char *zLimit; /* The value to the --limit option */ |
| 894 | int iLimit; /* How far back in time to look */ |
| 895 | int showLog; /* True to show the log */ |
| 896 | int fileVers; /* Show file version instead of check-in versions */ |
| 897 | int annFlags = 0; /* Flags to control annotation properties */ |
| 898 | |
| 899 | zLimit = find_option("limit",0,1); |
| 900 | if( zLimit==0 || zLimit[0]==0 ) zLimit = "-1"; |
| 901 | iLimit = atoi(zLimit); |
| 902 | showLog = find_option("log",0,0)!=0; |
| 903 | fileVers = find_option("filevers",0,0)!=0; |
| 904 | db_must_be_within_tree(); |
| 905 | if (g.argc<3) { |
| 906 | usage("FILENAME"); |
| 907 | } |
| 908 | file_tree_name(g.argv[2], &treename, 1); |
| @@ -855,10 +917,18 @@ | |
| 917 | } |
| 918 | mid = db_int(0, "SELECT mid FROM mlink WHERE fid=%d AND fnid=%d", fid, fnid); |
| 919 | if( mid==0 ){ |
| 920 | fossil_panic("unable to find manifest"); |
| 921 | } |
| 922 | if( fileVers ) annFlags |= ANN_FILE_VERS; |
| 923 | annotate_file(&ann, fnid, mid, 0, iLimit, annFlags); |
| 924 | if( showLog ){ |
| 925 | for(i=0; i<ann.nVers; i++){ |
| 926 | printf("version %3d: %s\n", i+1, ann.azVers[i]); |
| 927 | } |
| 928 | printf("---------------------------------------------------\n"); |
| 929 | } |
| 930 | for(i=0; i<ann.nOrig; i++){ |
| 931 | fossil_print("%s: %.*s\n", |
| 932 | ann.aOrig[i].zSrc, ann.aOrig[i].n, ann.aOrig[i].z); |
| 933 | } |
| 934 | } |
| 935 |
+5
-5
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -100,11 +100,11 @@ | ||
| 100 | 100 | ** zFile2 */ |
| 101 | 101 | blob_zero(&nameFile1); |
| 102 | 102 | do{ |
| 103 | 103 | blob_reset(&nameFile1); |
| 104 | 104 | blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); |
| 105 | - }while( access(blob_str(&nameFile1),0)==0 ); | |
| 105 | + }while( file_access(blob_str(&nameFile1),0)==0 ); | |
| 106 | 106 | blob_write_to_file(pFile1, blob_str(&nameFile1)); |
| 107 | 107 | |
| 108 | 108 | /* Construct the external diff command */ |
| 109 | 109 | blob_zero(&cmd); |
| 110 | 110 | blob_appendf(&cmd, "%s ", zDiffCmd); |
| @@ -114,11 +114,11 @@ | ||
| 114 | 114 | |
| 115 | 115 | /* Run the external diff command */ |
| 116 | 116 | fossil_system(blob_str(&cmd)); |
| 117 | 117 | |
| 118 | 118 | /* Delete the temporary file and clean up memory used */ |
| 119 | - unlink(blob_str(&nameFile1)); | |
| 119 | + file_delete(blob_str(&nameFile1)); | |
| 120 | 120 | blob_reset(&nameFile1); |
| 121 | 121 | blob_reset(&cmd); |
| 122 | 122 | } |
| 123 | 123 | } |
| 124 | 124 | |
| @@ -168,12 +168,12 @@ | ||
| 168 | 168 | |
| 169 | 169 | /* Run the external diff command */ |
| 170 | 170 | fossil_system(blob_str(&cmd)); |
| 171 | 171 | |
| 172 | 172 | /* Delete the temporary file and clean up memory used */ |
| 173 | - unlink(zTemp1); | |
| 174 | - unlink(zTemp2); | |
| 173 | + file_delete(zTemp1); | |
| 174 | + file_delete(zTemp2); | |
| 175 | 175 | blob_reset(&cmd); |
| 176 | 176 | } |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | /* |
| @@ -263,11 +263,11 @@ | ||
| 263 | 263 | char *zToFree = zFullName; |
| 264 | 264 | int showDiff = 1; |
| 265 | 265 | if( isDeleted ){ |
| 266 | 266 | diff_printf("DELETED %s\n", zPathname); |
| 267 | 267 | if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; } |
| 268 | - }else if( access(zFullName, 0) ){ | |
| 268 | + }else if( file_access(zFullName, 0) ){ | |
| 269 | 269 | diff_printf("MISSING %s\n", zPathname); |
| 270 | 270 | if( !asNewFile ){ showDiff = 0; } |
| 271 | 271 | }else if( isNew ){ |
| 272 | 272 | diff_printf("ADDED %s\n", zPathname); |
| 273 | 273 | srcid = 0; |
| 274 | 274 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -100,11 +100,11 @@ | |
| 100 | ** zFile2 */ |
| 101 | blob_zero(&nameFile1); |
| 102 | do{ |
| 103 | blob_reset(&nameFile1); |
| 104 | blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); |
| 105 | }while( access(blob_str(&nameFile1),0)==0 ); |
| 106 | blob_write_to_file(pFile1, blob_str(&nameFile1)); |
| 107 | |
| 108 | /* Construct the external diff command */ |
| 109 | blob_zero(&cmd); |
| 110 | blob_appendf(&cmd, "%s ", zDiffCmd); |
| @@ -114,11 +114,11 @@ | |
| 114 | |
| 115 | /* Run the external diff command */ |
| 116 | fossil_system(blob_str(&cmd)); |
| 117 | |
| 118 | /* Delete the temporary file and clean up memory used */ |
| 119 | unlink(blob_str(&nameFile1)); |
| 120 | blob_reset(&nameFile1); |
| 121 | blob_reset(&cmd); |
| 122 | } |
| 123 | } |
| 124 | |
| @@ -168,12 +168,12 @@ | |
| 168 | |
| 169 | /* Run the external diff command */ |
| 170 | fossil_system(blob_str(&cmd)); |
| 171 | |
| 172 | /* Delete the temporary file and clean up memory used */ |
| 173 | unlink(zTemp1); |
| 174 | unlink(zTemp2); |
| 175 | blob_reset(&cmd); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | /* |
| @@ -263,11 +263,11 @@ | |
| 263 | char *zToFree = zFullName; |
| 264 | int showDiff = 1; |
| 265 | if( isDeleted ){ |
| 266 | diff_printf("DELETED %s\n", zPathname); |
| 267 | if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; } |
| 268 | }else if( access(zFullName, 0) ){ |
| 269 | diff_printf("MISSING %s\n", zPathname); |
| 270 | if( !asNewFile ){ showDiff = 0; } |
| 271 | }else if( isNew ){ |
| 272 | diff_printf("ADDED %s\n", zPathname); |
| 273 | srcid = 0; |
| 274 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -100,11 +100,11 @@ | |
| 100 | ** zFile2 */ |
| 101 | blob_zero(&nameFile1); |
| 102 | do{ |
| 103 | blob_reset(&nameFile1); |
| 104 | blob_appendf(&nameFile1, "%s~%d", zFile2, cnt++); |
| 105 | }while( file_access(blob_str(&nameFile1),0)==0 ); |
| 106 | blob_write_to_file(pFile1, blob_str(&nameFile1)); |
| 107 | |
| 108 | /* Construct the external diff command */ |
| 109 | blob_zero(&cmd); |
| 110 | blob_appendf(&cmd, "%s ", zDiffCmd); |
| @@ -114,11 +114,11 @@ | |
| 114 | |
| 115 | /* Run the external diff command */ |
| 116 | fossil_system(blob_str(&cmd)); |
| 117 | |
| 118 | /* Delete the temporary file and clean up memory used */ |
| 119 | file_delete(blob_str(&nameFile1)); |
| 120 | blob_reset(&nameFile1); |
| 121 | blob_reset(&cmd); |
| 122 | } |
| 123 | } |
| 124 | |
| @@ -168,12 +168,12 @@ | |
| 168 | |
| 169 | /* Run the external diff command */ |
| 170 | fossil_system(blob_str(&cmd)); |
| 171 | |
| 172 | /* Delete the temporary file and clean up memory used */ |
| 173 | file_delete(zTemp1); |
| 174 | file_delete(zTemp2); |
| 175 | blob_reset(&cmd); |
| 176 | } |
| 177 | } |
| 178 | |
| 179 | /* |
| @@ -263,11 +263,11 @@ | |
| 263 | char *zToFree = zFullName; |
| 264 | int showDiff = 1; |
| 265 | if( isDeleted ){ |
| 266 | diff_printf("DELETED %s\n", zPathname); |
| 267 | if( !asNewFile ){ showDiff = 0; zFullName = "/dev/null"; } |
| 268 | }else if( file_access(zFullName, 0) ){ |
| 269 | diff_printf("MISSING %s\n", zPathname); |
| 270 | if( !asNewFile ){ showDiff = 0; } |
| 271 | }else if( isNew ){ |
| 272 | diff_printf("ADDED %s\n", zPathname); |
| 273 | srcid = 0; |
| 274 |
+4
-4
| --- src/encode.c | ||
| +++ src/encode.c | ||
| @@ -340,11 +340,11 @@ | ||
| 340 | 340 | void test_encode64_cmd(void){ |
| 341 | 341 | char *z; |
| 342 | 342 | int i; |
| 343 | 343 | for(i=2; i<g.argc; i++){ |
| 344 | 344 | z = encode64(g.argv[i], -1); |
| 345 | - printf("%s\n", z); | |
| 345 | + fossil_print("%s\n", z); | |
| 346 | 346 | free(z); |
| 347 | 347 | } |
| 348 | 348 | } |
| 349 | 349 | |
| 350 | 350 | |
| @@ -405,11 +405,11 @@ | ||
| 405 | 405 | void test_decode64_cmd(void){ |
| 406 | 406 | char *z; |
| 407 | 407 | int i, n; |
| 408 | 408 | for(i=2; i<g.argc; i++){ |
| 409 | 409 | z = decode64(g.argv[i], &n); |
| 410 | - printf("%d: %s\n", n, z); | |
| 410 | + fossil_print("%d: %s\n", n, z); | |
| 411 | 411 | free(z); |
| 412 | 412 | } |
| 413 | 413 | } |
| 414 | 414 | |
| 415 | 415 | /* |
| @@ -579,13 +579,13 @@ | ||
| 579 | 579 | int i; |
| 580 | 580 | char *z, *z2; |
| 581 | 581 | for(i=2; i<g.argc; i++){ |
| 582 | 582 | z = obscure(g.argv[i]); |
| 583 | 583 | z2 = unobscure(z); |
| 584 | - printf("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2); | |
| 584 | + fossil_print("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2); | |
| 585 | 585 | free(z); |
| 586 | 586 | free(z2); |
| 587 | 587 | z = unobscure(g.argv[i]); |
| 588 | - printf("UNOBSCURE: %s -> %s\n", g.argv[i], z); | |
| 588 | + fossil_print("UNOBSCURE: %s -> %s\n", g.argv[i], z); | |
| 589 | 589 | free(z); |
| 590 | 590 | } |
| 591 | 591 | } |
| 592 | 592 |
| --- src/encode.c | |
| +++ src/encode.c | |
| @@ -340,11 +340,11 @@ | |
| 340 | void test_encode64_cmd(void){ |
| 341 | char *z; |
| 342 | int i; |
| 343 | for(i=2; i<g.argc; i++){ |
| 344 | z = encode64(g.argv[i], -1); |
| 345 | printf("%s\n", z); |
| 346 | free(z); |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | |
| @@ -405,11 +405,11 @@ | |
| 405 | void test_decode64_cmd(void){ |
| 406 | char *z; |
| 407 | int i, n; |
| 408 | for(i=2; i<g.argc; i++){ |
| 409 | z = decode64(g.argv[i], &n); |
| 410 | printf("%d: %s\n", n, z); |
| 411 | free(z); |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | /* |
| @@ -579,13 +579,13 @@ | |
| 579 | int i; |
| 580 | char *z, *z2; |
| 581 | for(i=2; i<g.argc; i++){ |
| 582 | z = obscure(g.argv[i]); |
| 583 | z2 = unobscure(z); |
| 584 | printf("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2); |
| 585 | free(z); |
| 586 | free(z2); |
| 587 | z = unobscure(g.argv[i]); |
| 588 | printf("UNOBSCURE: %s -> %s\n", g.argv[i], z); |
| 589 | free(z); |
| 590 | } |
| 591 | } |
| 592 |
| --- src/encode.c | |
| +++ src/encode.c | |
| @@ -340,11 +340,11 @@ | |
| 340 | void test_encode64_cmd(void){ |
| 341 | char *z; |
| 342 | int i; |
| 343 | for(i=2; i<g.argc; i++){ |
| 344 | z = encode64(g.argv[i], -1); |
| 345 | fossil_print("%s\n", z); |
| 346 | free(z); |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | |
| @@ -405,11 +405,11 @@ | |
| 405 | void test_decode64_cmd(void){ |
| 406 | char *z; |
| 407 | int i, n; |
| 408 | for(i=2; i<g.argc; i++){ |
| 409 | z = decode64(g.argv[i], &n); |
| 410 | fossil_print("%d: %s\n", n, z); |
| 411 | free(z); |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | /* |
| @@ -579,13 +579,13 @@ | |
| 579 | int i; |
| 580 | char *z, *z2; |
| 581 | for(i=2; i<g.argc; i++){ |
| 582 | z = obscure(g.argv[i]); |
| 583 | z2 = unobscure(z); |
| 584 | fossil_print("OBSCURE: %s -> %s (%s)\n", g.argv[i], z, z2); |
| 585 | free(z); |
| 586 | free(z2); |
| 587 | z = unobscure(g.argv[i]); |
| 588 | fossil_print("UNOBSCURE: %s -> %s\n", g.argv[i], z); |
| 589 | free(z); |
| 590 | } |
| 591 | } |
| 592 |
+4
-4
| --- src/export.c | ||
| +++ src/export.c | ||
| @@ -139,11 +139,11 @@ | ||
| 139 | 139 | " WHERE type='ci'" |
| 140 | 140 | " ORDER BY mtime ASC", |
| 141 | 141 | TAG_BRANCH |
| 142 | 142 | ); |
| 143 | 143 | while( db_step(&q)==SQLITE_ROW ){ |
| 144 | - sqlite3_int64 secondsSince1970 = db_column_int64(&q, 0); | |
| 144 | + const char *zSecondsSince1970 = db_column_text(&q, 0); | |
| 145 | 145 | int ckinId = db_column_int(&q, 1); |
| 146 | 146 | const char *zComment = db_column_text(&q, 2); |
| 147 | 147 | const char *zUser = db_column_text(&q, 3); |
| 148 | 148 | const char *zBranch = db_column_text(&q, 4); |
| 149 | 149 | char *zBr; |
| @@ -159,11 +159,11 @@ | ||
| 159 | 159 | } |
| 160 | 160 | printf("commit refs/heads/%s\nmark :%d\n", zBr, ckinId+firstCkin); |
| 161 | 161 | free(zBr); |
| 162 | 162 | printf("committer"); |
| 163 | 163 | print_person(zUser); |
| 164 | - printf(" %lld +0000\n", secondsSince1970); | |
| 164 | + printf(" %s +0000\n", zSecondsSince1970); | |
| 165 | 165 | if( zComment==0 ) zComment = "null comment"; |
| 166 | 166 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| 167 | 167 | p = manifest_get(ckinId, CFTYPE_ANY); |
| 168 | 168 | zFromType = "from"; |
| 169 | 169 | for(i=0; i<p->nParent; i++){ |
| @@ -197,16 +197,16 @@ | ||
| 197 | 197 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 198 | 198 | ); |
| 199 | 199 | while( db_step(&q)==SQLITE_ROW ){ |
| 200 | 200 | const char *zTagname = db_column_text(&q, 0); |
| 201 | 201 | int rid = db_column_int(&q, 1); |
| 202 | - sqlite3_int64 secSince1970 = db_column_int64(&q, 2); | |
| 202 | + const char *zSecSince1970 = db_column_text(&q, 2); | |
| 203 | 203 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 204 | 204 | zTagname += 4; |
| 205 | 205 | printf("tag %s\n", zTagname); |
| 206 | 206 | printf("from :%d\n", rid+firstCkin); |
| 207 | - printf("tagger <tagger> %lld +0000\n", secSince1970); | |
| 207 | + printf("tagger <tagger> %s +0000\n", zSecSince1970); | |
| 208 | 208 | printf("data 0\n"); |
| 209 | 209 | } |
| 210 | 210 | db_finalize(&q); |
| 211 | 211 | bag_clear(&vers); |
| 212 | 212 | } |
| 213 | 213 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -139,11 +139,11 @@ | |
| 139 | " WHERE type='ci'" |
| 140 | " ORDER BY mtime ASC", |
| 141 | TAG_BRANCH |
| 142 | ); |
| 143 | while( db_step(&q)==SQLITE_ROW ){ |
| 144 | sqlite3_int64 secondsSince1970 = db_column_int64(&q, 0); |
| 145 | int ckinId = db_column_int(&q, 1); |
| 146 | const char *zComment = db_column_text(&q, 2); |
| 147 | const char *zUser = db_column_text(&q, 3); |
| 148 | const char *zBranch = db_column_text(&q, 4); |
| 149 | char *zBr; |
| @@ -159,11 +159,11 @@ | |
| 159 | } |
| 160 | printf("commit refs/heads/%s\nmark :%d\n", zBr, ckinId+firstCkin); |
| 161 | free(zBr); |
| 162 | printf("committer"); |
| 163 | print_person(zUser); |
| 164 | printf(" %lld +0000\n", secondsSince1970); |
| 165 | if( zComment==0 ) zComment = "null comment"; |
| 166 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| 167 | p = manifest_get(ckinId, CFTYPE_ANY); |
| 168 | zFromType = "from"; |
| 169 | for(i=0; i<p->nParent; i++){ |
| @@ -197,16 +197,16 @@ | |
| 197 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 198 | ); |
| 199 | while( db_step(&q)==SQLITE_ROW ){ |
| 200 | const char *zTagname = db_column_text(&q, 0); |
| 201 | int rid = db_column_int(&q, 1); |
| 202 | sqlite3_int64 secSince1970 = db_column_int64(&q, 2); |
| 203 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 204 | zTagname += 4; |
| 205 | printf("tag %s\n", zTagname); |
| 206 | printf("from :%d\n", rid+firstCkin); |
| 207 | printf("tagger <tagger> %lld +0000\n", secSince1970); |
| 208 | printf("data 0\n"); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | bag_clear(&vers); |
| 212 | } |
| 213 |
| --- src/export.c | |
| +++ src/export.c | |
| @@ -139,11 +139,11 @@ | |
| 139 | " WHERE type='ci'" |
| 140 | " ORDER BY mtime ASC", |
| 141 | TAG_BRANCH |
| 142 | ); |
| 143 | while( db_step(&q)==SQLITE_ROW ){ |
| 144 | const char *zSecondsSince1970 = db_column_text(&q, 0); |
| 145 | int ckinId = db_column_int(&q, 1); |
| 146 | const char *zComment = db_column_text(&q, 2); |
| 147 | const char *zUser = db_column_text(&q, 3); |
| 148 | const char *zBranch = db_column_text(&q, 4); |
| 149 | char *zBr; |
| @@ -159,11 +159,11 @@ | |
| 159 | } |
| 160 | printf("commit refs/heads/%s\nmark :%d\n", zBr, ckinId+firstCkin); |
| 161 | free(zBr); |
| 162 | printf("committer"); |
| 163 | print_person(zUser); |
| 164 | printf(" %s +0000\n", zSecondsSince1970); |
| 165 | if( zComment==0 ) zComment = "null comment"; |
| 166 | printf("data %d\n%s\n", (int)strlen(zComment), zComment); |
| 167 | p = manifest_get(ckinId, CFTYPE_ANY); |
| 168 | zFromType = "from"; |
| 169 | for(i=0; i<p->nParent; i++){ |
| @@ -197,16 +197,16 @@ | |
| 197 | " WHERE tagtype=1 AND tagname GLOB 'sym-*'" |
| 198 | ); |
| 199 | while( db_step(&q)==SQLITE_ROW ){ |
| 200 | const char *zTagname = db_column_text(&q, 0); |
| 201 | int rid = db_column_int(&q, 1); |
| 202 | const char *zSecSince1970 = db_column_text(&q, 2); |
| 203 | if( rid==0 || !bag_find(&vers, rid) ) continue; |
| 204 | zTagname += 4; |
| 205 | printf("tag %s\n", zTagname); |
| 206 | printf("from :%d\n", rid+firstCkin); |
| 207 | printf("tagger <tagger> %s +0000\n", zSecSince1970); |
| 208 | printf("data 0\n"); |
| 209 | } |
| 210 | db_finalize(&q); |
| 211 | bag_clear(&vers); |
| 212 | } |
| 213 |
+176
-28
| --- src/file.c | ||
| +++ src/file.c | ||
| @@ -47,17 +47,19 @@ | ||
| 47 | 47 | static int getStat(const char *zFilename){ |
| 48 | 48 | int rc = 0; |
| 49 | 49 | if( zFilename==0 ){ |
| 50 | 50 | if( fileStatValid==0 ) rc = 1; |
| 51 | 51 | }else{ |
| 52 | - if( stat(zFilename, &fileStat)!=0 ){ | |
| 52 | + char *zMbcs = fossil_utf8_to_mbcs(zFilename); | |
| 53 | + if( stat(zMbcs, &fileStat)!=0 ){ | |
| 53 | 54 | fileStatValid = 0; |
| 54 | 55 | rc = 1; |
| 55 | 56 | }else{ |
| 56 | 57 | fileStatValid = 1; |
| 57 | 58 | rc = 0; |
| 58 | 59 | } |
| 60 | + fossil_mbcs_free(zMbcs); | |
| 59 | 61 | } |
| 60 | 62 | return rc; |
| 61 | 63 | } |
| 62 | 64 | |
| 63 | 65 | |
| @@ -120,10 +122,20 @@ | ||
| 120 | 122 | }else{ |
| 121 | 123 | rc = getStat(0); |
| 122 | 124 | } |
| 123 | 125 | return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); |
| 124 | 126 | } |
| 127 | + | |
| 128 | +/* | |
| 129 | +** Wrapper around the access() system call. | |
| 130 | +*/ | |
| 131 | +int file_access(const char *zFilename, int flags){ | |
| 132 | + char *zMbcs = fossil_utf8_to_mbcs(zFilename); | |
| 133 | + int rc = access(zMbcs, flags); | |
| 134 | + fossil_mbcs_free(zMbcs); | |
| 135 | + return rc; | |
| 136 | +} | |
| 125 | 137 | |
| 126 | 138 | /* |
| 127 | 139 | ** Find an unused filename similar to zBase with zSuffix appended. |
| 128 | 140 | ** |
| 129 | 141 | ** Make the name relative to the working directory if relFlag is true. |
| @@ -166,13 +178,13 @@ | ||
| 166 | 178 | */ |
| 167 | 179 | void file_copy(const char *zFrom, const char *zTo){ |
| 168 | 180 | FILE *in, *out; |
| 169 | 181 | int got; |
| 170 | 182 | char zBuf[8192]; |
| 171 | - in = fopen(zFrom, "rb"); | |
| 183 | + in = fossil_fopen(zFrom, "rb"); | |
| 172 | 184 | if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); |
| 173 | - out = fopen(zTo, "wb"); | |
| 185 | + out = fossil_fopen(zTo, "wb"); | |
| 174 | 186 | if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); |
| 175 | 187 | while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ |
| 176 | 188 | fwrite(zBuf, 1, got, out); |
| 177 | 189 | } |
| 178 | 190 | fclose(in); |
| @@ -200,10 +212,19 @@ | ||
| 200 | 212 | } |
| 201 | 213 | } |
| 202 | 214 | #endif /* _WIN32 */ |
| 203 | 215 | return rc; |
| 204 | 216 | } |
| 217 | + | |
| 218 | +/* | |
| 219 | +** Delete a file. | |
| 220 | +*/ | |
| 221 | +void file_delete(const char *zFilename){ | |
| 222 | + char *z = fossil_utf8_to_mbcs(zFilename); | |
| 223 | + unlink(z); | |
| 224 | + fossil_mbcs_free(z); | |
| 225 | +} | |
| 205 | 226 | |
| 206 | 227 | /* |
| 207 | 228 | ** Create the directory named in the argument, if it does not already |
| 208 | 229 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 209 | 230 | ** with the same name. |
| @@ -212,15 +233,19 @@ | ||
| 212 | 233 | */ |
| 213 | 234 | int file_mkdir(const char *zName, int forceFlag){ |
| 214 | 235 | int rc = file_isdir(zName); |
| 215 | 236 | if( rc==2 ){ |
| 216 | 237 | if( !forceFlag ) return 1; |
| 217 | - unlink(zName); | |
| 238 | + file_delete(zName); | |
| 218 | 239 | } |
| 219 | 240 | if( rc!=1 ){ |
| 220 | 241 | #if defined(_WIN32) |
| 221 | - return mkdir(zName); | |
| 242 | + int rc; | |
| 243 | + char *zMbcs = fossil_utf8_to_mbcs(zName); | |
| 244 | + rc = mkdir(zMbcs); | |
| 245 | + fossil_mbcs_free(zMbcs); | |
| 246 | + return rc; | |
| 222 | 247 | #else |
| 223 | 248 | return mkdir(zName, 0755); |
| 224 | 249 | #endif |
| 225 | 250 | } |
| 226 | 251 | return 0; |
| @@ -350,16 +375,47 @@ | ||
| 350 | 375 | void cmd_test_simplify_name(void){ |
| 351 | 376 | int i; |
| 352 | 377 | char *z; |
| 353 | 378 | for(i=2; i<g.argc; i++){ |
| 354 | 379 | z = mprintf("%s", g.argv[i]); |
| 355 | - printf("[%s] -> ", z); | |
| 380 | + fossil_print("[%s] -> ", z); | |
| 356 | 381 | file_simplify_name(z, -1); |
| 357 | - printf("[%s]\n", z); | |
| 382 | + fossil_print("[%s]\n", z); | |
| 358 | 383 | fossil_free(z); |
| 359 | 384 | } |
| 360 | 385 | } |
| 386 | + | |
| 387 | +/* | |
| 388 | +** Get the current working directory. | |
| 389 | +** | |
| 390 | +** On windows, the name is converted from MBCS to UTF8 and all '\\' | |
| 391 | +** characters are converted to '/'. No conversions are needed on | |
| 392 | +** unix. | |
| 393 | +*/ | |
| 394 | +void file_getcwd(char *zBuf, int nBuf){ | |
| 395 | +#ifdef _WIN32 | |
| 396 | + char *zPwdUtf8; | |
| 397 | + int nPwd; | |
| 398 | + int i; | |
| 399 | + char zPwd[2000]; | |
| 400 | + if( getcwd(zPwd, sizeof(zPwd)-1)==0 ){ | |
| 401 | + fossil_fatal("pwd too big: max %d\n", (int)sizeof(zPwd)-1); | |
| 402 | + } | |
| 403 | + zPwdUtf8 = fossil_mbcs_to_utf8(zPwd); | |
| 404 | + nPwd = strlen(zPwdUtf8); | |
| 405 | + if( nPwd > nBuf-1 ){ | |
| 406 | + fossil_fatal("pwd too big: max %d\n", nBuf-1); | |
| 407 | + } | |
| 408 | + for(i=0; zPwdUtf8[i]; i++) if( zPwdUtf8[i]=='\\' ) zPwdUtf8[i] = '/'; | |
| 409 | + memcpy(zBuf, zPwdUtf8, nPwd+1); | |
| 410 | + fossil_mbcs_free(zPwdUtf8); | |
| 411 | +#else | |
| 412 | + if( getcwd(zBuf, nBuf-1)==0 ){ | |
| 413 | + fossil_fatal("pwd too big: max %d\n", nBuf-1); | |
| 414 | + } | |
| 415 | +#endif | |
| 416 | +} | |
| 361 | 417 | |
| 362 | 418 | /* |
| 363 | 419 | ** Compute a canonical pathname for a file or directory. |
| 364 | 420 | ** Make the name absolute if it is relative. |
| 365 | 421 | ** Remove redundant / characters |
| @@ -376,14 +432,11 @@ | ||
| 376 | 432 | ){ |
| 377 | 433 | blob_set(pOut, zOrigName); |
| 378 | 434 | blob_materialize(pOut); |
| 379 | 435 | }else{ |
| 380 | 436 | char zPwd[2000]; |
| 381 | - if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ | |
| 382 | - fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20); | |
| 383 | - fossil_exit(1); | |
| 384 | - } | |
| 437 | + file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); | |
| 385 | 438 | blob_zero(pOut); |
| 386 | 439 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 387 | 440 | } |
| 388 | 441 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut))); |
| 389 | 442 | } |
| @@ -401,19 +454,19 @@ | ||
| 401 | 454 | blob_zero(&x); |
| 402 | 455 | for(i=2; i<g.argc; i++){ |
| 403 | 456 | char zBuf[100]; |
| 404 | 457 | const char *zName = g.argv[i]; |
| 405 | 458 | file_canonical_name(zName, &x); |
| 406 | - printf("[%s] -> [%s]\n", zName, blob_buffer(&x)); | |
| 459 | + fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x)); | |
| 407 | 460 | blob_reset(&x); |
| 408 | 461 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); |
| 409 | - printf(" file_size = %s\n", zBuf); | |
| 462 | + fossil_print(" file_size = %s\n", zBuf); | |
| 410 | 463 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); |
| 411 | - printf(" file_mtime = %s\n", zBuf); | |
| 412 | - printf(" file_isfile = %d\n", file_isfile(zName)); | |
| 413 | - printf(" file_isexe = %d\n", file_isexe(zName)); | |
| 414 | - printf(" file_isdir = %d\n", file_isdir(zName)); | |
| 464 | + fossil_print(" file_mtime = %s\n", zBuf); | |
| 465 | + fossil_print(" file_isfile = %d\n", file_isfile(zName)); | |
| 466 | + fossil_print(" file_isexe = %d\n", file_isexe(zName)); | |
| 467 | + fossil_print(" file_isdir = %d\n", file_isdir(zName)); | |
| 415 | 468 | } |
| 416 | 469 | } |
| 417 | 470 | |
| 418 | 471 | /* |
| 419 | 472 | ** Return TRUE if the given filename is canonical. |
| @@ -452,14 +505,11 @@ | ||
| 452 | 505 | zPath = blob_buffer(pOut); |
| 453 | 506 | if( zPath[0]=='/' ){ |
| 454 | 507 | int i, j; |
| 455 | 508 | Blob tmp; |
| 456 | 509 | char zPwd[2000]; |
| 457 | - if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ | |
| 458 | - fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20); | |
| 459 | - fossil_exit(1); | |
| 460 | - } | |
| 510 | + file_getcwd(zPwd, sizeof(zPwd)-20); | |
| 461 | 511 | for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){} |
| 462 | 512 | if( zPath[i]==0 ){ |
| 463 | 513 | blob_reset(pOut); |
| 464 | 514 | if( zPwd[i]==0 ){ |
| 465 | 515 | blob_append(pOut, ".", 1); |
| @@ -502,11 +552,11 @@ | ||
| 502 | 552 | int i; |
| 503 | 553 | Blob x; |
| 504 | 554 | blob_zero(&x); |
| 505 | 555 | for(i=2; i<g.argc; i++){ |
| 506 | 556 | file_relative_name(g.argv[i], &x); |
| 507 | - printf("%s\n", blob_buffer(&x)); | |
| 557 | + fossil_print("%s\n", blob_buffer(&x)); | |
| 508 | 558 | blob_reset(&x); |
| 509 | 559 | } |
| 510 | 560 | } |
| 511 | 561 | |
| 512 | 562 | /* |
| @@ -557,11 +607,11 @@ | ||
| 557 | 607 | int i; |
| 558 | 608 | Blob x; |
| 559 | 609 | blob_zero(&x); |
| 560 | 610 | for(i=2; i<g.argc; i++){ |
| 561 | 611 | if( file_tree_name(g.argv[i], &x, 1) ){ |
| 562 | - printf("%s\n", blob_buffer(&x)); | |
| 612 | + fossil_print("%s\n", blob_buffer(&x)); | |
| 563 | 613 | blob_reset(&x); |
| 564 | 614 | } |
| 565 | 615 | } |
| 566 | 616 | } |
| 567 | 617 | |
| @@ -620,17 +670,14 @@ | ||
| 620 | 670 | static const unsigned char zChars[] = |
| 621 | 671 | "abcdefghijklmnopqrstuvwxyz" |
| 622 | 672 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 623 | 673 | "0123456789"; |
| 624 | 674 | unsigned int i, j; |
| 625 | - struct stat buf; | |
| 626 | 675 | const char *zDir = "."; |
| 627 | 676 | |
| 628 | 677 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 629 | - if( stat(azDirs[i], &buf) ) continue; | |
| 630 | - if( !S_ISDIR(buf.st_mode) ) continue; | |
| 631 | - if( access(azDirs[i], 07) ) continue; | |
| 678 | + if( !file_isdir(azDirs[i]) ) continue; | |
| 632 | 679 | zDir = azDirs[i]; |
| 633 | 680 | break; |
| 634 | 681 | } |
| 635 | 682 | |
| 636 | 683 | /* Check that the output buffer is large enough for the temporary file |
| @@ -646,11 +693,11 @@ | ||
| 646 | 693 | sqlite3_randomness(15, &zBuf[j]); |
| 647 | 694 | for(i=0; i<15; i++, j++){ |
| 648 | 695 | zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
| 649 | 696 | } |
| 650 | 697 | zBuf[j] = 0; |
| 651 | - }while( access(zBuf,0)==0 ); | |
| 698 | + }while( file_size(zBuf)<0 ); | |
| 652 | 699 | } |
| 653 | 700 | |
| 654 | 701 | |
| 655 | 702 | /* |
| 656 | 703 | ** Return true if a file named zName exists and has identical content |
| @@ -668,5 +715,106 @@ | ||
| 668 | 715 | blob_read_from_file(&onDisk, zName); |
| 669 | 716 | rc = blob_compare(&onDisk, pContent); |
| 670 | 717 | blob_reset(&onDisk); |
| 671 | 718 | return rc==0; |
| 672 | 719 | } |
| 720 | + | |
| 721 | + | |
| 722 | +/************************************************************************** | |
| 723 | +** The following routines translate between MBCS and UTF8 on windows. | |
| 724 | +** Since everything is always UTF8 on unix, these routines are no-ops | |
| 725 | +** there. | |
| 726 | +*/ | |
| 727 | +#ifdef _WIN32 | |
| 728 | +# include <windows.h> | |
| 729 | +#endif | |
| 730 | + | |
| 731 | +/* | |
| 732 | +** Translate MBCS to UTF8. Return a pointer to the translated text. | |
| 733 | +** Call fossil_mbcs_free() to deallocate any memory used to store the | |
| 734 | +** returned pointer when done. | |
| 735 | +*/ | |
| 736 | +char *fossil_mbcs_to_utf8(const char *zMbcs){ | |
| 737 | +#ifdef _WIN32 | |
| 738 | + extern char *sqlite3_win32_mbcs_to_utf8(const char*); | |
| 739 | + return sqlite3_win32_mbcs_to_utf8(zMbcs); | |
| 740 | +#else | |
| 741 | + return (char*)zMbcs; /* No-op on unix */ | |
| 742 | +#endif | |
| 743 | +} | |
| 744 | + | |
| 745 | +/* | |
| 746 | +** Translate UTF8 to MBCS for use in system calls. Return a pointer to the | |
| 747 | +** translated text.. Call fossil_mbcs_free() to deallocate any memory | |
| 748 | +** used to store the returned pointer when done. | |
| 749 | +*/ | |
| 750 | +char *fossil_utf8_to_mbcs(const char *zUtf8){ | |
| 751 | +#ifdef _WIN32 | |
| 752 | + extern char *sqlite3_win32_utf8_to_mbcs(const char*); | |
| 753 | + return sqlite3_win32_utf8_to_mbcs(zUtf8); | |
| 754 | +#else | |
| 755 | + return (char*)zUtf8; /* No-op on unix */ | |
| 756 | +#endif | |
| 757 | +} | |
| 758 | + | |
| 759 | +/* | |
| 760 | +** Translate UTF8 to MBCS for display on the console. Return a pointer to the | |
| 761 | +** translated text.. Call fossil_mbcs_free() to deallocate any memory | |
| 762 | +** used to store the returned pointer when done. | |
| 763 | +*/ | |
| 764 | +char *fossil_utf8_to_console(const char *zUtf8){ | |
| 765 | +#ifdef _WIN32 | |
| 766 | + int nChar, nByte; | |
| 767 | + WCHAR *zUnicode; /* Unicode version of zUtf8 */ | |
| 768 | + char *zConsole; /* Console version of zUtf8 */ | |
| 769 | + int codepage; /* Console code page */ | |
| 770 | + | |
| 771 | + nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); | |
| 772 | + zUnicode = malloc( nChar*sizeof(zUnicode[0]) ); | |
| 773 | + if( zUnicode==0 ){ | |
| 774 | + return 0; | |
| 775 | + } | |
| 776 | + nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); | |
| 777 | + if( nChar==0 ){ | |
| 778 | + free(zUnicode); | |
| 779 | + return 0; | |
| 780 | + } | |
| 781 | + codepage = GetConsoleCP(); | |
| 782 | + nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, 0, 0, 0, 0); | |
| 783 | + zConsole = malloc( nByte ); | |
| 784 | + if( zConsole==0 ){ | |
| 785 | + free(zUnicode); | |
| 786 | + return 0; | |
| 787 | + } | |
| 788 | + nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, zConsole, nByte, 0, 0); | |
| 789 | + free(zUnicode); | |
| 790 | + if( nByte == 0 ){ | |
| 791 | + free(zConsole); | |
| 792 | + zConsole = 0; | |
| 793 | + } | |
| 794 | + return zConsole; | |
| 795 | +#else | |
| 796 | + return (char*)zUtf8; /* No-op on unix */ | |
| 797 | +#endif | |
| 798 | +} | |
| 799 | + | |
| 800 | +/* | |
| 801 | +** Translate MBCS to UTF8. Return a pointer. Call fossil_mbcs_free() | |
| 802 | +** to deallocate any memory used to store the returned pointer when done. | |
| 803 | +*/ | |
| 804 | +void fossil_mbcs_free(char *zOld){ | |
| 805 | +#ifdef _WIN32 | |
| 806 | + free(zOld); | |
| 807 | +#else | |
| 808 | + /* No-op on unix */ | |
| 809 | +#endif | |
| 810 | +} | |
| 811 | + | |
| 812 | +/* | |
| 813 | +** Like fopen() but always takes a UTF8 argument. | |
| 814 | +*/ | |
| 815 | +FILE *fossil_fopen(const char *zName, const char *zMode){ | |
| 816 | + char *zMbcs = fossil_utf8_to_mbcs(zName); | |
| 817 | + FILE *f = fopen(zMbcs, zMode); | |
| 818 | + fossil_mbcs_free(zMbcs); | |
| 819 | + return f; | |
| 820 | +} | |
| 673 | 821 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -47,17 +47,19 @@ | |
| 47 | static int getStat(const char *zFilename){ |
| 48 | int rc = 0; |
| 49 | if( zFilename==0 ){ |
| 50 | if( fileStatValid==0 ) rc = 1; |
| 51 | }else{ |
| 52 | if( stat(zFilename, &fileStat)!=0 ){ |
| 53 | fileStatValid = 0; |
| 54 | rc = 1; |
| 55 | }else{ |
| 56 | fileStatValid = 1; |
| 57 | rc = 0; |
| 58 | } |
| 59 | } |
| 60 | return rc; |
| 61 | } |
| 62 | |
| 63 | |
| @@ -120,10 +122,20 @@ | |
| 120 | }else{ |
| 121 | rc = getStat(0); |
| 122 | } |
| 123 | return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); |
| 124 | } |
| 125 | |
| 126 | /* |
| 127 | ** Find an unused filename similar to zBase with zSuffix appended. |
| 128 | ** |
| 129 | ** Make the name relative to the working directory if relFlag is true. |
| @@ -166,13 +178,13 @@ | |
| 166 | */ |
| 167 | void file_copy(const char *zFrom, const char *zTo){ |
| 168 | FILE *in, *out; |
| 169 | int got; |
| 170 | char zBuf[8192]; |
| 171 | in = fopen(zFrom, "rb"); |
| 172 | if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); |
| 173 | out = fopen(zTo, "wb"); |
| 174 | if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); |
| 175 | while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ |
| 176 | fwrite(zBuf, 1, got, out); |
| 177 | } |
| 178 | fclose(in); |
| @@ -200,10 +212,19 @@ | |
| 200 | } |
| 201 | } |
| 202 | #endif /* _WIN32 */ |
| 203 | return rc; |
| 204 | } |
| 205 | |
| 206 | /* |
| 207 | ** Create the directory named in the argument, if it does not already |
| 208 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 209 | ** with the same name. |
| @@ -212,15 +233,19 @@ | |
| 212 | */ |
| 213 | int file_mkdir(const char *zName, int forceFlag){ |
| 214 | int rc = file_isdir(zName); |
| 215 | if( rc==2 ){ |
| 216 | if( !forceFlag ) return 1; |
| 217 | unlink(zName); |
| 218 | } |
| 219 | if( rc!=1 ){ |
| 220 | #if defined(_WIN32) |
| 221 | return mkdir(zName); |
| 222 | #else |
| 223 | return mkdir(zName, 0755); |
| 224 | #endif |
| 225 | } |
| 226 | return 0; |
| @@ -350,16 +375,47 @@ | |
| 350 | void cmd_test_simplify_name(void){ |
| 351 | int i; |
| 352 | char *z; |
| 353 | for(i=2; i<g.argc; i++){ |
| 354 | z = mprintf("%s", g.argv[i]); |
| 355 | printf("[%s] -> ", z); |
| 356 | file_simplify_name(z, -1); |
| 357 | printf("[%s]\n", z); |
| 358 | fossil_free(z); |
| 359 | } |
| 360 | } |
| 361 | |
| 362 | /* |
| 363 | ** Compute a canonical pathname for a file or directory. |
| 364 | ** Make the name absolute if it is relative. |
| 365 | ** Remove redundant / characters |
| @@ -376,14 +432,11 @@ | |
| 376 | ){ |
| 377 | blob_set(pOut, zOrigName); |
| 378 | blob_materialize(pOut); |
| 379 | }else{ |
| 380 | char zPwd[2000]; |
| 381 | if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ |
| 382 | fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20); |
| 383 | fossil_exit(1); |
| 384 | } |
| 385 | blob_zero(pOut); |
| 386 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 387 | } |
| 388 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut))); |
| 389 | } |
| @@ -401,19 +454,19 @@ | |
| 401 | blob_zero(&x); |
| 402 | for(i=2; i<g.argc; i++){ |
| 403 | char zBuf[100]; |
| 404 | const char *zName = g.argv[i]; |
| 405 | file_canonical_name(zName, &x); |
| 406 | printf("[%s] -> [%s]\n", zName, blob_buffer(&x)); |
| 407 | blob_reset(&x); |
| 408 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); |
| 409 | printf(" file_size = %s\n", zBuf); |
| 410 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); |
| 411 | printf(" file_mtime = %s\n", zBuf); |
| 412 | printf(" file_isfile = %d\n", file_isfile(zName)); |
| 413 | printf(" file_isexe = %d\n", file_isexe(zName)); |
| 414 | printf(" file_isdir = %d\n", file_isdir(zName)); |
| 415 | } |
| 416 | } |
| 417 | |
| 418 | /* |
| 419 | ** Return TRUE if the given filename is canonical. |
| @@ -452,14 +505,11 @@ | |
| 452 | zPath = blob_buffer(pOut); |
| 453 | if( zPath[0]=='/' ){ |
| 454 | int i, j; |
| 455 | Blob tmp; |
| 456 | char zPwd[2000]; |
| 457 | if( getcwd(zPwd, sizeof(zPwd)-20)==0 ){ |
| 458 | fprintf(stderr, "pwd too big: max %d\n", (int)sizeof(zPwd)-20); |
| 459 | fossil_exit(1); |
| 460 | } |
| 461 | for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){} |
| 462 | if( zPath[i]==0 ){ |
| 463 | blob_reset(pOut); |
| 464 | if( zPwd[i]==0 ){ |
| 465 | blob_append(pOut, ".", 1); |
| @@ -502,11 +552,11 @@ | |
| 502 | int i; |
| 503 | Blob x; |
| 504 | blob_zero(&x); |
| 505 | for(i=2; i<g.argc; i++){ |
| 506 | file_relative_name(g.argv[i], &x); |
| 507 | printf("%s\n", blob_buffer(&x)); |
| 508 | blob_reset(&x); |
| 509 | } |
| 510 | } |
| 511 | |
| 512 | /* |
| @@ -557,11 +607,11 @@ | |
| 557 | int i; |
| 558 | Blob x; |
| 559 | blob_zero(&x); |
| 560 | for(i=2; i<g.argc; i++){ |
| 561 | if( file_tree_name(g.argv[i], &x, 1) ){ |
| 562 | printf("%s\n", blob_buffer(&x)); |
| 563 | blob_reset(&x); |
| 564 | } |
| 565 | } |
| 566 | } |
| 567 | |
| @@ -620,17 +670,14 @@ | |
| 620 | static const unsigned char zChars[] = |
| 621 | "abcdefghijklmnopqrstuvwxyz" |
| 622 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 623 | "0123456789"; |
| 624 | unsigned int i, j; |
| 625 | struct stat buf; |
| 626 | const char *zDir = "."; |
| 627 | |
| 628 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 629 | if( stat(azDirs[i], &buf) ) continue; |
| 630 | if( !S_ISDIR(buf.st_mode) ) continue; |
| 631 | if( access(azDirs[i], 07) ) continue; |
| 632 | zDir = azDirs[i]; |
| 633 | break; |
| 634 | } |
| 635 | |
| 636 | /* Check that the output buffer is large enough for the temporary file |
| @@ -646,11 +693,11 @@ | |
| 646 | sqlite3_randomness(15, &zBuf[j]); |
| 647 | for(i=0; i<15; i++, j++){ |
| 648 | zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
| 649 | } |
| 650 | zBuf[j] = 0; |
| 651 | }while( access(zBuf,0)==0 ); |
| 652 | } |
| 653 | |
| 654 | |
| 655 | /* |
| 656 | ** Return true if a file named zName exists and has identical content |
| @@ -668,5 +715,106 @@ | |
| 668 | blob_read_from_file(&onDisk, zName); |
| 669 | rc = blob_compare(&onDisk, pContent); |
| 670 | blob_reset(&onDisk); |
| 671 | return rc==0; |
| 672 | } |
| 673 |
| --- src/file.c | |
| +++ src/file.c | |
| @@ -47,17 +47,19 @@ | |
| 47 | static int getStat(const char *zFilename){ |
| 48 | int rc = 0; |
| 49 | if( zFilename==0 ){ |
| 50 | if( fileStatValid==0 ) rc = 1; |
| 51 | }else{ |
| 52 | char *zMbcs = fossil_utf8_to_mbcs(zFilename); |
| 53 | if( stat(zMbcs, &fileStat)!=0 ){ |
| 54 | fileStatValid = 0; |
| 55 | rc = 1; |
| 56 | }else{ |
| 57 | fileStatValid = 1; |
| 58 | rc = 0; |
| 59 | } |
| 60 | fossil_mbcs_free(zMbcs); |
| 61 | } |
| 62 | return rc; |
| 63 | } |
| 64 | |
| 65 | |
| @@ -120,10 +122,20 @@ | |
| 122 | }else{ |
| 123 | rc = getStat(0); |
| 124 | } |
| 125 | return rc ? 0 : (S_ISDIR(fileStat.st_mode) ? 1 : 2); |
| 126 | } |
| 127 | |
| 128 | /* |
| 129 | ** Wrapper around the access() system call. |
| 130 | */ |
| 131 | int file_access(const char *zFilename, int flags){ |
| 132 | char *zMbcs = fossil_utf8_to_mbcs(zFilename); |
| 133 | int rc = access(zMbcs, flags); |
| 134 | fossil_mbcs_free(zMbcs); |
| 135 | return rc; |
| 136 | } |
| 137 | |
| 138 | /* |
| 139 | ** Find an unused filename similar to zBase with zSuffix appended. |
| 140 | ** |
| 141 | ** Make the name relative to the working directory if relFlag is true. |
| @@ -166,13 +178,13 @@ | |
| 178 | */ |
| 179 | void file_copy(const char *zFrom, const char *zTo){ |
| 180 | FILE *in, *out; |
| 181 | int got; |
| 182 | char zBuf[8192]; |
| 183 | in = fossil_fopen(zFrom, "rb"); |
| 184 | if( in==0 ) fossil_fatal("cannot open \"%s\" for reading", zFrom); |
| 185 | out = fossil_fopen(zTo, "wb"); |
| 186 | if( out==0 ) fossil_fatal("cannot open \"%s\" for writing", zTo); |
| 187 | while( (got=fread(zBuf, 1, sizeof(zBuf), in))>0 ){ |
| 188 | fwrite(zBuf, 1, got, out); |
| 189 | } |
| 190 | fclose(in); |
| @@ -200,10 +212,19 @@ | |
| 212 | } |
| 213 | } |
| 214 | #endif /* _WIN32 */ |
| 215 | return rc; |
| 216 | } |
| 217 | |
| 218 | /* |
| 219 | ** Delete a file. |
| 220 | */ |
| 221 | void file_delete(const char *zFilename){ |
| 222 | char *z = fossil_utf8_to_mbcs(zFilename); |
| 223 | unlink(z); |
| 224 | fossil_mbcs_free(z); |
| 225 | } |
| 226 | |
| 227 | /* |
| 228 | ** Create the directory named in the argument, if it does not already |
| 229 | ** exist. If forceFlag is 1, delete any prior non-directory object |
| 230 | ** with the same name. |
| @@ -212,15 +233,19 @@ | |
| 233 | */ |
| 234 | int file_mkdir(const char *zName, int forceFlag){ |
| 235 | int rc = file_isdir(zName); |
| 236 | if( rc==2 ){ |
| 237 | if( !forceFlag ) return 1; |
| 238 | file_delete(zName); |
| 239 | } |
| 240 | if( rc!=1 ){ |
| 241 | #if defined(_WIN32) |
| 242 | int rc; |
| 243 | char *zMbcs = fossil_utf8_to_mbcs(zName); |
| 244 | rc = mkdir(zMbcs); |
| 245 | fossil_mbcs_free(zMbcs); |
| 246 | return rc; |
| 247 | #else |
| 248 | return mkdir(zName, 0755); |
| 249 | #endif |
| 250 | } |
| 251 | return 0; |
| @@ -350,16 +375,47 @@ | |
| 375 | void cmd_test_simplify_name(void){ |
| 376 | int i; |
| 377 | char *z; |
| 378 | for(i=2; i<g.argc; i++){ |
| 379 | z = mprintf("%s", g.argv[i]); |
| 380 | fossil_print("[%s] -> ", z); |
| 381 | file_simplify_name(z, -1); |
| 382 | fossil_print("[%s]\n", z); |
| 383 | fossil_free(z); |
| 384 | } |
| 385 | } |
| 386 | |
| 387 | /* |
| 388 | ** Get the current working directory. |
| 389 | ** |
| 390 | ** On windows, the name is converted from MBCS to UTF8 and all '\\' |
| 391 | ** characters are converted to '/'. No conversions are needed on |
| 392 | ** unix. |
| 393 | */ |
| 394 | void file_getcwd(char *zBuf, int nBuf){ |
| 395 | #ifdef _WIN32 |
| 396 | char *zPwdUtf8; |
| 397 | int nPwd; |
| 398 | int i; |
| 399 | char zPwd[2000]; |
| 400 | if( getcwd(zPwd, sizeof(zPwd)-1)==0 ){ |
| 401 | fossil_fatal("pwd too big: max %d\n", (int)sizeof(zPwd)-1); |
| 402 | } |
| 403 | zPwdUtf8 = fossil_mbcs_to_utf8(zPwd); |
| 404 | nPwd = strlen(zPwdUtf8); |
| 405 | if( nPwd > nBuf-1 ){ |
| 406 | fossil_fatal("pwd too big: max %d\n", nBuf-1); |
| 407 | } |
| 408 | for(i=0; zPwdUtf8[i]; i++) if( zPwdUtf8[i]=='\\' ) zPwdUtf8[i] = '/'; |
| 409 | memcpy(zBuf, zPwdUtf8, nPwd+1); |
| 410 | fossil_mbcs_free(zPwdUtf8); |
| 411 | #else |
| 412 | if( getcwd(zBuf, nBuf-1)==0 ){ |
| 413 | fossil_fatal("pwd too big: max %d\n", nBuf-1); |
| 414 | } |
| 415 | #endif |
| 416 | } |
| 417 | |
| 418 | /* |
| 419 | ** Compute a canonical pathname for a file or directory. |
| 420 | ** Make the name absolute if it is relative. |
| 421 | ** Remove redundant / characters |
| @@ -376,14 +432,11 @@ | |
| 432 | ){ |
| 433 | blob_set(pOut, zOrigName); |
| 434 | blob_materialize(pOut); |
| 435 | }else{ |
| 436 | char zPwd[2000]; |
| 437 | file_getcwd(zPwd, sizeof(zPwd)-strlen(zOrigName)); |
| 438 | blob_zero(pOut); |
| 439 | blob_appendf(pOut, "%//%/", zPwd, zOrigName); |
| 440 | } |
| 441 | blob_resize(pOut, file_simplify_name(blob_buffer(pOut), blob_size(pOut))); |
| 442 | } |
| @@ -401,19 +454,19 @@ | |
| 454 | blob_zero(&x); |
| 455 | for(i=2; i<g.argc; i++){ |
| 456 | char zBuf[100]; |
| 457 | const char *zName = g.argv[i]; |
| 458 | file_canonical_name(zName, &x); |
| 459 | fossil_print("[%s] -> [%s]\n", zName, blob_buffer(&x)); |
| 460 | blob_reset(&x); |
| 461 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_size(zName)); |
| 462 | fossil_print(" file_size = %s\n", zBuf); |
| 463 | sqlite3_snprintf(sizeof(zBuf), zBuf, "%lld", file_mtime(zName)); |
| 464 | fossil_print(" file_mtime = %s\n", zBuf); |
| 465 | fossil_print(" file_isfile = %d\n", file_isfile(zName)); |
| 466 | fossil_print(" file_isexe = %d\n", file_isexe(zName)); |
| 467 | fossil_print(" file_isdir = %d\n", file_isdir(zName)); |
| 468 | } |
| 469 | } |
| 470 | |
| 471 | /* |
| 472 | ** Return TRUE if the given filename is canonical. |
| @@ -452,14 +505,11 @@ | |
| 505 | zPath = blob_buffer(pOut); |
| 506 | if( zPath[0]=='/' ){ |
| 507 | int i, j; |
| 508 | Blob tmp; |
| 509 | char zPwd[2000]; |
| 510 | file_getcwd(zPwd, sizeof(zPwd)-20); |
| 511 | for(i=1; zPath[i] && zPwd[i]==zPath[i]; i++){} |
| 512 | if( zPath[i]==0 ){ |
| 513 | blob_reset(pOut); |
| 514 | if( zPwd[i]==0 ){ |
| 515 | blob_append(pOut, ".", 1); |
| @@ -502,11 +552,11 @@ | |
| 552 | int i; |
| 553 | Blob x; |
| 554 | blob_zero(&x); |
| 555 | for(i=2; i<g.argc; i++){ |
| 556 | file_relative_name(g.argv[i], &x); |
| 557 | fossil_print("%s\n", blob_buffer(&x)); |
| 558 | blob_reset(&x); |
| 559 | } |
| 560 | } |
| 561 | |
| 562 | /* |
| @@ -557,11 +607,11 @@ | |
| 607 | int i; |
| 608 | Blob x; |
| 609 | blob_zero(&x); |
| 610 | for(i=2; i<g.argc; i++){ |
| 611 | if( file_tree_name(g.argv[i], &x, 1) ){ |
| 612 | fossil_print("%s\n", blob_buffer(&x)); |
| 613 | blob_reset(&x); |
| 614 | } |
| 615 | } |
| 616 | } |
| 617 | |
| @@ -620,17 +670,14 @@ | |
| 670 | static const unsigned char zChars[] = |
| 671 | "abcdefghijklmnopqrstuvwxyz" |
| 672 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| 673 | "0123456789"; |
| 674 | unsigned int i, j; |
| 675 | const char *zDir = "."; |
| 676 | |
| 677 | for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){ |
| 678 | if( !file_isdir(azDirs[i]) ) continue; |
| 679 | zDir = azDirs[i]; |
| 680 | break; |
| 681 | } |
| 682 | |
| 683 | /* Check that the output buffer is large enough for the temporary file |
| @@ -646,11 +693,11 @@ | |
| 693 | sqlite3_randomness(15, &zBuf[j]); |
| 694 | for(i=0; i<15; i++, j++){ |
| 695 | zBuf[j] = (char)zChars[ ((unsigned char)zBuf[j])%(sizeof(zChars)-1) ]; |
| 696 | } |
| 697 | zBuf[j] = 0; |
| 698 | }while( file_size(zBuf)<0 ); |
| 699 | } |
| 700 | |
| 701 | |
| 702 | /* |
| 703 | ** Return true if a file named zName exists and has identical content |
| @@ -668,5 +715,106 @@ | |
| 715 | blob_read_from_file(&onDisk, zName); |
| 716 | rc = blob_compare(&onDisk, pContent); |
| 717 | blob_reset(&onDisk); |
| 718 | return rc==0; |
| 719 | } |
| 720 | |
| 721 | |
| 722 | /************************************************************************** |
| 723 | ** The following routines translate between MBCS and UTF8 on windows. |
| 724 | ** Since everything is always UTF8 on unix, these routines are no-ops |
| 725 | ** there. |
| 726 | */ |
| 727 | #ifdef _WIN32 |
| 728 | # include <windows.h> |
| 729 | #endif |
| 730 | |
| 731 | /* |
| 732 | ** Translate MBCS to UTF8. Return a pointer to the translated text. |
| 733 | ** Call fossil_mbcs_free() to deallocate any memory used to store the |
| 734 | ** returned pointer when done. |
| 735 | */ |
| 736 | char *fossil_mbcs_to_utf8(const char *zMbcs){ |
| 737 | #ifdef _WIN32 |
| 738 | extern char *sqlite3_win32_mbcs_to_utf8(const char*); |
| 739 | return sqlite3_win32_mbcs_to_utf8(zMbcs); |
| 740 | #else |
| 741 | return (char*)zMbcs; /* No-op on unix */ |
| 742 | #endif |
| 743 | } |
| 744 | |
| 745 | /* |
| 746 | ** Translate UTF8 to MBCS for use in system calls. Return a pointer to the |
| 747 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| 748 | ** used to store the returned pointer when done. |
| 749 | */ |
| 750 | char *fossil_utf8_to_mbcs(const char *zUtf8){ |
| 751 | #ifdef _WIN32 |
| 752 | extern char *sqlite3_win32_utf8_to_mbcs(const char*); |
| 753 | return sqlite3_win32_utf8_to_mbcs(zUtf8); |
| 754 | #else |
| 755 | return (char*)zUtf8; /* No-op on unix */ |
| 756 | #endif |
| 757 | } |
| 758 | |
| 759 | /* |
| 760 | ** Translate UTF8 to MBCS for display on the console. Return a pointer to the |
| 761 | ** translated text.. Call fossil_mbcs_free() to deallocate any memory |
| 762 | ** used to store the returned pointer when done. |
| 763 | */ |
| 764 | char *fossil_utf8_to_console(const char *zUtf8){ |
| 765 | #ifdef _WIN32 |
| 766 | int nChar, nByte; |
| 767 | WCHAR *zUnicode; /* Unicode version of zUtf8 */ |
| 768 | char *zConsole; /* Console version of zUtf8 */ |
| 769 | int codepage; /* Console code page */ |
| 770 | |
| 771 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, NULL, 0); |
| 772 | zUnicode = malloc( nChar*sizeof(zUnicode[0]) ); |
| 773 | if( zUnicode==0 ){ |
| 774 | return 0; |
| 775 | } |
| 776 | nChar = MultiByteToWideChar(CP_UTF8, 0, zUtf8, -1, zUnicode, nChar); |
| 777 | if( nChar==0 ){ |
| 778 | free(zUnicode); |
| 779 | return 0; |
| 780 | } |
| 781 | codepage = GetConsoleCP(); |
| 782 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, 0, 0, 0, 0); |
| 783 | zConsole = malloc( nByte ); |
| 784 | if( zConsole==0 ){ |
| 785 | free(zUnicode); |
| 786 | return 0; |
| 787 | } |
| 788 | nByte = WideCharToMultiByte(codepage, 0, zUnicode, -1, zConsole, nByte, 0, 0); |
| 789 | free(zUnicode); |
| 790 | if( nByte == 0 ){ |
| 791 | free(zConsole); |
| 792 | zConsole = 0; |
| 793 | } |
| 794 | return zConsole; |
| 795 | #else |
| 796 | return (char*)zUtf8; /* No-op on unix */ |
| 797 | #endif |
| 798 | } |
| 799 | |
| 800 | /* |
| 801 | ** Translate MBCS to UTF8. Return a pointer. Call fossil_mbcs_free() |
| 802 | ** to deallocate any memory used to store the returned pointer when done. |
| 803 | */ |
| 804 | void fossil_mbcs_free(char *zOld){ |
| 805 | #ifdef _WIN32 |
| 806 | free(zOld); |
| 807 | #else |
| 808 | /* No-op on unix */ |
| 809 | #endif |
| 810 | } |
| 811 | |
| 812 | /* |
| 813 | ** Like fopen() but always takes a UTF8 argument. |
| 814 | */ |
| 815 | FILE *fossil_fopen(const char *zName, const char *zMode){ |
| 816 | char *zMbcs = fossil_utf8_to_mbcs(zName); |
| 817 | FILE *f = fopen(zMbcs, zMode); |
| 818 | fossil_mbcs_free(zMbcs); |
| 819 | return f; |
| 820 | } |
| 821 |
+34
-11
| --- src/finfo.c | ||
| +++ src/finfo.c | ||
| @@ -89,11 +89,11 @@ | ||
| 89 | 89 | blob_reset(&uuid); |
| 90 | 90 | }else{ |
| 91 | 91 | blob_appendf(&line, "unknown 0000000000"); |
| 92 | 92 | } |
| 93 | 93 | db_finalize(&q); |
| 94 | - printf("%s\n", blob_str(&line)); | |
| 94 | + fossil_print("%s\n", blob_str(&line)); | |
| 95 | 95 | blob_reset(&fname); |
| 96 | 96 | blob_reset(&line); |
| 97 | 97 | }else if( find_option("print","p",0) ){ |
| 98 | 98 | Blob record; |
| 99 | 99 | Blob fname; |
| @@ -152,21 +152,21 @@ | ||
| 152 | 152 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 153 | 153 | zFilename, iLimit, iOffset |
| 154 | 154 | ); |
| 155 | 155 | blob_zero(&line); |
| 156 | 156 | if( iBrief ){ |
| 157 | - printf("History of %s\n", blob_str(&fname)); | |
| 157 | + fossil_print("History of %s\n", blob_str(&fname)); | |
| 158 | 158 | } |
| 159 | 159 | while( db_step(&q)==SQLITE_ROW ){ |
| 160 | 160 | const char *zFileUuid = db_column_text(&q, 0); |
| 161 | 161 | const char *zCiUuid = db_column_text(&q,1); |
| 162 | 162 | const char *zDate = db_column_text(&q, 2); |
| 163 | 163 | const char *zCom = db_column_text(&q, 3); |
| 164 | 164 | const char *zUser = db_column_text(&q, 4); |
| 165 | 165 | char *zOut; |
| 166 | 166 | if( iBrief ){ |
| 167 | - printf("%s ", zDate); | |
| 167 | + fossil_print("%s ", zDate); | |
| 168 | 168 | zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", |
| 169 | 169 | zCiUuid, zCom, zUser, zFileUuid); |
| 170 | 170 | comment_print(zOut, 11, 79); |
| 171 | 171 | sqlite3_free(zOut); |
| 172 | 172 | }else{ |
| @@ -186,27 +186,38 @@ | ||
| 186 | 186 | |
| 187 | 187 | /* |
| 188 | 188 | ** WEBPAGE: finfo |
| 189 | 189 | ** URL: /finfo?name=FILENAME |
| 190 | 190 | ** |
| 191 | -** Show the complete change history for a single file. | |
| 191 | +** Show the change history for a single file. | |
| 192 | +** | |
| 193 | +** Additional query parameters: | |
| 194 | +** | |
| 195 | +** a=DATE Only show changes after DATE | |
| 196 | +** b=DATE Only show changes before DATE | |
| 197 | +** n=NUM Show the first NUM changes only | |
| 192 | 198 | */ |
| 193 | 199 | void finfo_page(void){ |
| 194 | 200 | Stmt q; |
| 195 | 201 | const char *zFilename; |
| 196 | 202 | char zPrevDate[20]; |
| 203 | + const char *zA; | |
| 204 | + const char *zB; | |
| 205 | + int n; | |
| 197 | 206 | Blob title; |
| 207 | + Blob sql; | |
| 198 | 208 | GraphContext *pGraph; |
| 199 | 209 | |
| 200 | 210 | login_check_credentials(); |
| 201 | 211 | if( !g.okRead ){ login_needed(); return; } |
| 202 | 212 | style_header("File History"); |
| 203 | 213 | login_anonymous_available(); |
| 204 | 214 | |
| 205 | 215 | zPrevDate[0] = 0; |
| 206 | 216 | zFilename = PD("name",""); |
| 207 | - db_prepare(&q, | |
| 217 | + blob_zero(&sql); | |
| 218 | + blob_appendf(&sql, | |
| 208 | 219 | "SELECT" |
| 209 | 220 | " datetime(event.mtime,'localtime')," /* Date of change */ |
| 210 | 221 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 211 | 222 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 212 | 223 | " mlink.pid," /* Parent rid */ |
| @@ -217,15 +228,26 @@ | ||
| 217 | 228 | " event.bgcolor," /* Background color */ |
| 218 | 229 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 219 | 230 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 220 | 231 | " FROM mlink, event" |
| 221 | 232 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 222 | - " AND event.objid=mlink.mid" | |
| 223 | - " ORDER BY event.mtime DESC /*sort*/", | |
| 233 | + " AND event.objid=mlink.mid", | |
| 224 | 234 | TAG_BRANCH, |
| 225 | 235 | zFilename |
| 226 | 236 | ); |
| 237 | + if( (zA = P("a"))!=0 ){ | |
| 238 | + blob_appendf(&sql, " AND event.mtime>=julianday('%q')", zA); | |
| 239 | + } | |
| 240 | + if( (zB = P("b"))!=0 ){ | |
| 241 | + blob_appendf(&sql, " AND event.mtime<=julianday('%q')", zB); | |
| 242 | + } | |
| 243 | + blob_appendf(&sql," ORDER BY event.mtime DESC /*sort*/"); | |
| 244 | + if( (n = atoi(PD("n","0")))>0 ){ | |
| 245 | + blob_appendf(&sql, " LIMIT %d", n); | |
| 246 | + } | |
| 247 | + db_prepare(&q, blob_str(&sql)); | |
| 248 | + blob_reset(&sql); | |
| 227 | 249 | blob_zero(&title); |
| 228 | 250 | blob_appendf(&title, "History of "); |
| 229 | 251 | hyperlinked_path(zFilename, &title, 0); |
| 230 | 252 | @ <h2>%b(&title)</h2> |
| 231 | 253 | blob_reset(&title); |
| @@ -246,11 +268,11 @@ | ||
| 246 | 268 | int gidx; |
| 247 | 269 | char zTime[10]; |
| 248 | 270 | char zShort[20]; |
| 249 | 271 | char zShortCkin[20]; |
| 250 | 272 | if( zBr==0 ) zBr = "trunk"; |
| 251 | - gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 1); | |
| 273 | + gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 0); | |
| 252 | 274 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 253 | 275 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 254 | 276 | @ <tr><td> |
| 255 | 277 | @ <div class="divider">%s(zPrevDate)</div> |
| 256 | 278 | @ </td></tr> |
| @@ -291,18 +313,19 @@ | ||
| 291 | 313 | } |
| 292 | 314 | @ </td></tr> |
| 293 | 315 | } |
| 294 | 316 | db_finalize(&q); |
| 295 | 317 | if( pGraph ){ |
| 296 | - graph_finish(pGraph, 1); | |
| 318 | + graph_finish(pGraph, 0); | |
| 297 | 319 | if( pGraph->nErr ){ |
| 298 | 320 | graph_free(pGraph); |
| 299 | 321 | pGraph = 0; |
| 300 | 322 | }else{ |
| 301 | - @ <tr><td></td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div> | |
| 323 | + @ <tr><td></td><td> | |
| 324 | + @ <div id="grbtm" style="width:%d(pGraph->mxRail*20+30)px;"></div> | |
| 302 | 325 | @ </td></tr> |
| 303 | 326 | } |
| 304 | 327 | } |
| 305 | 328 | @ </table> |
| 306 | - timeline_output_graph_javascript(pGraph, 1); | |
| 329 | + timeline_output_graph_javascript(pGraph, 0); | |
| 307 | 330 | style_footer(); |
| 308 | 331 | } |
| 309 | 332 | |
| 310 | 333 | ADDED src/glob.c |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -89,11 +89,11 @@ | |
| 89 | blob_reset(&uuid); |
| 90 | }else{ |
| 91 | blob_appendf(&line, "unknown 0000000000"); |
| 92 | } |
| 93 | db_finalize(&q); |
| 94 | printf("%s\n", blob_str(&line)); |
| 95 | blob_reset(&fname); |
| 96 | blob_reset(&line); |
| 97 | }else if( find_option("print","p",0) ){ |
| 98 | Blob record; |
| 99 | Blob fname; |
| @@ -152,21 +152,21 @@ | |
| 152 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 153 | zFilename, iLimit, iOffset |
| 154 | ); |
| 155 | blob_zero(&line); |
| 156 | if( iBrief ){ |
| 157 | printf("History of %s\n", blob_str(&fname)); |
| 158 | } |
| 159 | while( db_step(&q)==SQLITE_ROW ){ |
| 160 | const char *zFileUuid = db_column_text(&q, 0); |
| 161 | const char *zCiUuid = db_column_text(&q,1); |
| 162 | const char *zDate = db_column_text(&q, 2); |
| 163 | const char *zCom = db_column_text(&q, 3); |
| 164 | const char *zUser = db_column_text(&q, 4); |
| 165 | char *zOut; |
| 166 | if( iBrief ){ |
| 167 | printf("%s ", zDate); |
| 168 | zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", |
| 169 | zCiUuid, zCom, zUser, zFileUuid); |
| 170 | comment_print(zOut, 11, 79); |
| 171 | sqlite3_free(zOut); |
| 172 | }else{ |
| @@ -186,27 +186,38 @@ | |
| 186 | |
| 187 | /* |
| 188 | ** WEBPAGE: finfo |
| 189 | ** URL: /finfo?name=FILENAME |
| 190 | ** |
| 191 | ** Show the complete change history for a single file. |
| 192 | */ |
| 193 | void finfo_page(void){ |
| 194 | Stmt q; |
| 195 | const char *zFilename; |
| 196 | char zPrevDate[20]; |
| 197 | Blob title; |
| 198 | GraphContext *pGraph; |
| 199 | |
| 200 | login_check_credentials(); |
| 201 | if( !g.okRead ){ login_needed(); return; } |
| 202 | style_header("File History"); |
| 203 | login_anonymous_available(); |
| 204 | |
| 205 | zPrevDate[0] = 0; |
| 206 | zFilename = PD("name",""); |
| 207 | db_prepare(&q, |
| 208 | "SELECT" |
| 209 | " datetime(event.mtime,'localtime')," /* Date of change */ |
| 210 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 211 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 212 | " mlink.pid," /* Parent rid */ |
| @@ -217,15 +228,26 @@ | |
| 217 | " event.bgcolor," /* Background color */ |
| 218 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 219 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 220 | " FROM mlink, event" |
| 221 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 222 | " AND event.objid=mlink.mid" |
| 223 | " ORDER BY event.mtime DESC /*sort*/", |
| 224 | TAG_BRANCH, |
| 225 | zFilename |
| 226 | ); |
| 227 | blob_zero(&title); |
| 228 | blob_appendf(&title, "History of "); |
| 229 | hyperlinked_path(zFilename, &title, 0); |
| 230 | @ <h2>%b(&title)</h2> |
| 231 | blob_reset(&title); |
| @@ -246,11 +268,11 @@ | |
| 246 | int gidx; |
| 247 | char zTime[10]; |
| 248 | char zShort[20]; |
| 249 | char zShortCkin[20]; |
| 250 | if( zBr==0 ) zBr = "trunk"; |
| 251 | gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 1); |
| 252 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 253 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 254 | @ <tr><td> |
| 255 | @ <div class="divider">%s(zPrevDate)</div> |
| 256 | @ </td></tr> |
| @@ -291,18 +313,19 @@ | |
| 291 | } |
| 292 | @ </td></tr> |
| 293 | } |
| 294 | db_finalize(&q); |
| 295 | if( pGraph ){ |
| 296 | graph_finish(pGraph, 1); |
| 297 | if( pGraph->nErr ){ |
| 298 | graph_free(pGraph); |
| 299 | pGraph = 0; |
| 300 | }else{ |
| 301 | @ <tr><td></td><td><div style="width:%d(pGraph->mxRail*20+30)px;"></div> |
| 302 | @ </td></tr> |
| 303 | } |
| 304 | } |
| 305 | @ </table> |
| 306 | timeline_output_graph_javascript(pGraph, 1); |
| 307 | style_footer(); |
| 308 | } |
| 309 | |
| 310 | DDED src/glob.c |
| --- src/finfo.c | |
| +++ src/finfo.c | |
| @@ -89,11 +89,11 @@ | |
| 89 | blob_reset(&uuid); |
| 90 | }else{ |
| 91 | blob_appendf(&line, "unknown 0000000000"); |
| 92 | } |
| 93 | db_finalize(&q); |
| 94 | fossil_print("%s\n", blob_str(&line)); |
| 95 | blob_reset(&fname); |
| 96 | blob_reset(&line); |
| 97 | }else if( find_option("print","p",0) ){ |
| 98 | Blob record; |
| 99 | Blob fname; |
| @@ -152,21 +152,21 @@ | |
| 152 | " ORDER BY event.mtime DESC LIMIT %d OFFSET %d", |
| 153 | zFilename, iLimit, iOffset |
| 154 | ); |
| 155 | blob_zero(&line); |
| 156 | if( iBrief ){ |
| 157 | fossil_print("History of %s\n", blob_str(&fname)); |
| 158 | } |
| 159 | while( db_step(&q)==SQLITE_ROW ){ |
| 160 | const char *zFileUuid = db_column_text(&q, 0); |
| 161 | const char *zCiUuid = db_column_text(&q,1); |
| 162 | const char *zDate = db_column_text(&q, 2); |
| 163 | const char *zCom = db_column_text(&q, 3); |
| 164 | const char *zUser = db_column_text(&q, 4); |
| 165 | char *zOut; |
| 166 | if( iBrief ){ |
| 167 | fossil_print("%s ", zDate); |
| 168 | zOut = sqlite3_mprintf("[%.10s] %s (user: %s, artifact: [%.10s])", |
| 169 | zCiUuid, zCom, zUser, zFileUuid); |
| 170 | comment_print(zOut, 11, 79); |
| 171 | sqlite3_free(zOut); |
| 172 | }else{ |
| @@ -186,27 +186,38 @@ | |
| 186 | |
| 187 | /* |
| 188 | ** WEBPAGE: finfo |
| 189 | ** URL: /finfo?name=FILENAME |
| 190 | ** |
| 191 | ** Show the change history for a single file. |
| 192 | ** |
| 193 | ** Additional query parameters: |
| 194 | ** |
| 195 | ** a=DATE Only show changes after DATE |
| 196 | ** b=DATE Only show changes before DATE |
| 197 | ** n=NUM Show the first NUM changes only |
| 198 | */ |
| 199 | void finfo_page(void){ |
| 200 | Stmt q; |
| 201 | const char *zFilename; |
| 202 | char zPrevDate[20]; |
| 203 | const char *zA; |
| 204 | const char *zB; |
| 205 | int n; |
| 206 | Blob title; |
| 207 | Blob sql; |
| 208 | GraphContext *pGraph; |
| 209 | |
| 210 | login_check_credentials(); |
| 211 | if( !g.okRead ){ login_needed(); return; } |
| 212 | style_header("File History"); |
| 213 | login_anonymous_available(); |
| 214 | |
| 215 | zPrevDate[0] = 0; |
| 216 | zFilename = PD("name",""); |
| 217 | blob_zero(&sql); |
| 218 | blob_appendf(&sql, |
| 219 | "SELECT" |
| 220 | " datetime(event.mtime,'localtime')," /* Date of change */ |
| 221 | " coalesce(event.ecomment, event.comment)," /* Check-in comment */ |
| 222 | " coalesce(event.euser, event.user)," /* User who made chng */ |
| 223 | " mlink.pid," /* Parent rid */ |
| @@ -217,15 +228,26 @@ | |
| 228 | " event.bgcolor," /* Background color */ |
| 229 | " (SELECT value FROM tagxref WHERE tagid=%d AND tagtype>0" |
| 230 | " AND tagxref.rid=mlink.mid)" /* Tags */ |
| 231 | " FROM mlink, event" |
| 232 | " WHERE mlink.fnid=(SELECT fnid FROM filename WHERE name=%Q)" |
| 233 | " AND event.objid=mlink.mid", |
| 234 | TAG_BRANCH, |
| 235 | zFilename |
| 236 | ); |
| 237 | if( (zA = P("a"))!=0 ){ |
| 238 | blob_appendf(&sql, " AND event.mtime>=julianday('%q')", zA); |
| 239 | } |
| 240 | if( (zB = P("b"))!=0 ){ |
| 241 | blob_appendf(&sql, " AND event.mtime<=julianday('%q')", zB); |
| 242 | } |
| 243 | blob_appendf(&sql," ORDER BY event.mtime DESC /*sort*/"); |
| 244 | if( (n = atoi(PD("n","0")))>0 ){ |
| 245 | blob_appendf(&sql, " LIMIT %d", n); |
| 246 | } |
| 247 | db_prepare(&q, blob_str(&sql)); |
| 248 | blob_reset(&sql); |
| 249 | blob_zero(&title); |
| 250 | blob_appendf(&title, "History of "); |
| 251 | hyperlinked_path(zFilename, &title, 0); |
| 252 | @ <h2>%b(&title)</h2> |
| 253 | blob_reset(&title); |
| @@ -246,11 +268,11 @@ | |
| 268 | int gidx; |
| 269 | char zTime[10]; |
| 270 | char zShort[20]; |
| 271 | char zShortCkin[20]; |
| 272 | if( zBr==0 ) zBr = "trunk"; |
| 273 | gidx = graph_add_row(pGraph, frid, fpid>0 ? 1 : 0, &fpid, zBr, zBgClr, 0); |
| 274 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 275 | sqlite3_snprintf(sizeof(zPrevDate), zPrevDate, "%.10s", zDate); |
| 276 | @ <tr><td> |
| 277 | @ <div class="divider">%s(zPrevDate)</div> |
| 278 | @ </td></tr> |
| @@ -291,18 +313,19 @@ | |
| 313 | } |
| 314 | @ </td></tr> |
| 315 | } |
| 316 | db_finalize(&q); |
| 317 | if( pGraph ){ |
| 318 | graph_finish(pGraph, 0); |
| 319 | if( pGraph->nErr ){ |
| 320 | graph_free(pGraph); |
| 321 | pGraph = 0; |
| 322 | }else{ |
| 323 | @ <tr><td></td><td> |
| 324 | @ <div id="grbtm" style="width:%d(pGraph->mxRail*20+30)px;"></div> |
| 325 | @ </td></tr> |
| 326 | } |
| 327 | } |
| 328 | @ </table> |
| 329 | timeline_output_graph_javascript(pGraph, 0); |
| 330 | style_footer(); |
| 331 | } |
| 332 | |
| 333 | DDED src/glob.c |
+88
| --- a/src/glob.c | ||
| +++ b/src/glob.c | ||
| @@ -0,0 +1,88 @@ | ||
| 1 | +/* | |
| 2 | +** Copyright (c) 2011 D. Richard Hipp | |
| 3 | +** | |
| 4 | +** This program is free software; you can redistribute it and/or | |
| 5 | +** modify it under the terms of the Simplified BSD License (also | |
| 6 | +** known as the "2-Clause License" or "FreeBSD License".) | |
| 7 | + | |
| 8 | +** This program is distributed in the hope that it will be useful, | |
| 9 | +** but without any warranty; without even the implied warranty of | |
| 10 | +** merchantability or fitness for a particular purpose. | |
| 11 | +** | |
| 12 | +** Author contact information: | |
| 13 | +** [email protected] | |
| 14 | +** http://www.hwaci.com/drh/ | |
| 15 | +** | |
| 16 | +******************************************************************************* | |
| 17 | +** | |
| 18 | +** This file contains code used to pattern matching using "glob" syntax. | |
| 19 | +*/ | |
| 20 | +#include "config.h" | |
| 21 | +#include "glob.h" | |
| 22 | +#include <assert.h> | |
| 23 | + | |
| 24 | +/* | |
| 25 | +** Construct and return a string which is an SQL expression that will | |
| 26 | +** be TRUE if value zVal matches any of the GLOB expressions in the list | |
| 27 | +** zGlobList. For example: | |
| 28 | +** | |
| 29 | +** zVal: "x" | |
| 30 | +** zGlobList: "*.o,*.obj" | |
| 31 | +** | |
| 32 | +** Result: "(x GLOB '*.o'Each the GLOB list may optionally be enclosed in either '...' or | |
| 33 | +** "... | |
| 34 | +** oris allows commas ou no effoin the expression. Whitespace at the | |
| 35 | +** beginning and end of each GLOB pattern is ignored, except when enclosed | |
| 36 | +** within '...' or "..."rrently consistunquotedpr(const char *zVal, constst){ | |
| 37 | + Blob expr; | |
| 38 | + 011 D. Richard Hipp | |
| 39 | +** | |
| 40 | +** This program is free software; you can redistribute it and/or | |
| 41 | +** modify it under the terms of the Simplified BSD License (also | |
| 42 | +** known as the "2-Clause License" or "FreeBSD License".) | |
| 43 | + | |
| 44 | +** This program is distributed in the hope that it will /* | |
| 45 | +** Copyrig.*z[j-1]==' 'hard Hipp | |
| 46 | +** | |
| 47 | +** This program is free software; you can redistribute it and/or | |
| 48 | +** modify it under the terms of the Simplified BSD License (also | |
| 49 | +** known as the "2-Clause License" or "FreeBSD License".) | |
| 50 | + | |
| 51 | +** This program is distributed in the hope that it will be useful, | |
| 52 | +** but without any warranty; without even the implied warranty of | |
| 53 | +** merchantability or fitness for a particular purpose. | |
| 54 | +** | |
| 55 | +** Author contact information: | |
| 56 | +** [email protected] | |
| 57 | +** http://www.hwaci.com/drh/ | |
| 58 | +** | |
| 59 | +******************************************************************************* | |
| 60 | +** | |
| 61 | +** This file contains code used to pattern matching using "glob" syntax. | |
| 62 | +*/ | |
| 63 | +#include "config.h" | |
| 64 | +#include "glob.h" | |
| 65 | +#include <assert.h> | |
| 66 | + | |
| 67 | +/* | |
| 68 | +** Construct and return a string which is an SQL expression that will | |
| 69 | +** be TRUE if value zVal matches any of the GLOB expressions in the list | |
| 70 | +** zGlobList. For example: | |
| 71 | +** | |
| 72 | +** zVal: "x" | |
| 73 | +** zGlobList: "*.o,*.obj" | |
| 74 | +** | |
| 75 | +** Result: "(x GLOB '*.o'Each the GLOB list may optionally be enclosed in either '...' or | |
| 76 | +** "... | |
| 77 | +** oris allows commas ou no effoin the expression. Whitespace at the | |
| 78 | +** beginning and end of each GLOB pattern is ignored, except when enclosed | |
| 79 | +** within '...' or "..."rrently consistunquotedpr(const char *zVal, constst){ | |
| 80 | + Blob expr; | |
| 81 | + 011 D. Richard Hipp | |
| 82 | +** | |
| 83 | +** This program is free software; you can redistribute it and/or | |
| 84 | +** modify it under the terms of the Simplified BSD License (also | |
| 85 | +** known as the "2-Clause License" or "FreeBSD License".) | |
| 86 | + | |
| 87 | +** This program is distributed in the hope that it will /* | |
| 88 | +** Copyrig.* |
| --- a/src/glob.c | |
| +++ b/src/glob.c | |
| @@ -0,0 +1,88 @@ | |
| --- a/src/glob.c | |
| +++ b/src/glob.c | |
| @@ -0,0 +1,88 @@ | |
| 1 | /* |
| 2 | ** Copyright (c) 2011 D. Richard Hipp |
| 3 | ** |
| 4 | ** This program is free software; you can redistribute it and/or |
| 5 | ** modify it under the terms of the Simplified BSD License (also |
| 6 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 7 | |
| 8 | ** This program is distributed in the hope that it will be useful, |
| 9 | ** but without any warranty; without even the implied warranty of |
| 10 | ** merchantability or fitness for a particular purpose. |
| 11 | ** |
| 12 | ** Author contact information: |
| 13 | ** [email protected] |
| 14 | ** http://www.hwaci.com/drh/ |
| 15 | ** |
| 16 | ******************************************************************************* |
| 17 | ** |
| 18 | ** This file contains code used to pattern matching using "glob" syntax. |
| 19 | */ |
| 20 | #include "config.h" |
| 21 | #include "glob.h" |
| 22 | #include <assert.h> |
| 23 | |
| 24 | /* |
| 25 | ** Construct and return a string which is an SQL expression that will |
| 26 | ** be TRUE if value zVal matches any of the GLOB expressions in the list |
| 27 | ** zGlobList. For example: |
| 28 | ** |
| 29 | ** zVal: "x" |
| 30 | ** zGlobList: "*.o,*.obj" |
| 31 | ** |
| 32 | ** Result: "(x GLOB '*.o'Each the GLOB list may optionally be enclosed in either '...' or |
| 33 | ** "... |
| 34 | ** oris allows commas ou no effoin the expression. Whitespace at the |
| 35 | ** beginning and end of each GLOB pattern is ignored, except when enclosed |
| 36 | ** within '...' or "..."rrently consistunquotedpr(const char *zVal, constst){ |
| 37 | Blob expr; |
| 38 | 011 D. Richard Hipp |
| 39 | ** |
| 40 | ** This program is free software; you can redistribute it and/or |
| 41 | ** modify it under the terms of the Simplified BSD License (also |
| 42 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 43 | |
| 44 | ** This program is distributed in the hope that it will /* |
| 45 | ** Copyrig.*z[j-1]==' 'hard Hipp |
| 46 | ** |
| 47 | ** This program is free software; you can redistribute it and/or |
| 48 | ** modify it under the terms of the Simplified BSD License (also |
| 49 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 50 | |
| 51 | ** This program is distributed in the hope that it will be useful, |
| 52 | ** but without any warranty; without even the implied warranty of |
| 53 | ** merchantability or fitness for a particular purpose. |
| 54 | ** |
| 55 | ** Author contact information: |
| 56 | ** [email protected] |
| 57 | ** http://www.hwaci.com/drh/ |
| 58 | ** |
| 59 | ******************************************************************************* |
| 60 | ** |
| 61 | ** This file contains code used to pattern matching using "glob" syntax. |
| 62 | */ |
| 63 | #include "config.h" |
| 64 | #include "glob.h" |
| 65 | #include <assert.h> |
| 66 | |
| 67 | /* |
| 68 | ** Construct and return a string which is an SQL expression that will |
| 69 | ** be TRUE if value zVal matches any of the GLOB expressions in the list |
| 70 | ** zGlobList. For example: |
| 71 | ** |
| 72 | ** zVal: "x" |
| 73 | ** zGlobList: "*.o,*.obj" |
| 74 | ** |
| 75 | ** Result: "(x GLOB '*.o'Each the GLOB list may optionally be enclosed in either '...' or |
| 76 | ** "... |
| 77 | ** oris allows commas ou no effoin the expression. Whitespace at the |
| 78 | ** beginning and end of each GLOB pattern is ignored, except when enclosed |
| 79 | ** within '...' or "..."rrently consistunquotedpr(const char *zVal, constst){ |
| 80 | Blob expr; |
| 81 | 011 D. Richard Hipp |
| 82 | ** |
| 83 | ** This program is free software; you can redistribute it and/or |
| 84 | ** modify it under the terms of the Simplified BSD License (also |
| 85 | ** known as the "2-Clause License" or "FreeBSD License".) |
| 86 | |
| 87 | ** This program is distributed in the hope that it will /* |
| 88 | ** Copyrig.* |
+35
-15
| --- src/graph.c | ||
| +++ src/graph.c | ||
| @@ -306,20 +306,35 @@ | ||
| 306 | 306 | } |
| 307 | 307 | } |
| 308 | 308 | pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1; |
| 309 | 309 | } |
| 310 | 310 | |
| 311 | +/* | |
| 312 | +** Compute the maximum rail number. | |
| 313 | +*/ | |
| 314 | +static void find_max_rail(GraphContext *p){ | |
| 315 | + GraphRow *pRow; | |
| 316 | + p->mxRail = 0; | |
| 317 | + for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 318 | + if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; | |
| 319 | + if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4; | |
| 320 | + while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){ | |
| 321 | + p->mxRail++; | |
| 322 | + } | |
| 323 | + } | |
| 324 | +} | |
| 325 | + | |
| 311 | 326 | |
| 312 | 327 | /* |
| 313 | 328 | ** Compute the complete graph |
| 314 | 329 | */ |
| 315 | 330 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 316 | 331 | GraphRow *pRow, *pDesc, *pDup, *pLoop, *pParent; |
| 317 | 332 | int i; |
| 318 | 333 | u32 mask; |
| 319 | 334 | u32 inUse; |
| 320 | - int hasDup = 0; /* True if one or more isDup entries */ | |
| 335 | + int hasDup = 0; /* True if one or more isDup entries */ | |
| 321 | 336 | const char *zTrunk; |
| 322 | 337 | |
| 323 | 338 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 324 | 339 | p->nErr = 1; /* Assume an error until proven otherwise */ |
| 325 | 340 | |
| @@ -390,10 +405,11 @@ | ||
| 390 | 405 | ** Strive to put the "trunk" branch on far left. |
| 391 | 406 | */ |
| 392 | 407 | zTrunk = persistBranchName(p, "trunk"); |
| 393 | 408 | for(i=0; i<2; i++){ |
| 394 | 409 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 410 | + if( pRow->isDup ) continue; | |
| 395 | 411 | if( i==0 ){ |
| 396 | 412 | if( pRow->zBranch!=zTrunk ) continue; |
| 397 | 413 | }else { |
| 398 | 414 | if( pRow->iRail>=0 ) continue; |
| 399 | 415 | } |
| @@ -422,11 +438,11 @@ | ||
| 422 | 438 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 423 | 439 | int parentRid; |
| 424 | 440 | |
| 425 | 441 | if( pRow->iRail>=0 ){ |
| 426 | 442 | if( pRow->pChild==0 && !pRow->timeWarp ){ |
| 427 | - if( pRow->isLeaf || omitDescenders ){ | |
| 443 | + if( omitDescenders || count_nonbranch_children(pRow->rid)==0 ){ | |
| 428 | 444 | inUse &= ~(1<<pRow->iRail); |
| 429 | 445 | }else{ |
| 430 | 446 | pRow->aiRiser[pRow->iRail] = 0; |
| 431 | 447 | mask = 1<<pRow->iRail; |
| 432 | 448 | for(pLoop=pRow; pLoop; pLoop=pLoop->pPrev){ |
| @@ -435,14 +451,11 @@ | ||
| 435 | 451 | } |
| 436 | 452 | } |
| 437 | 453 | continue; |
| 438 | 454 | } |
| 439 | 455 | if( pRow->isDup ){ |
| 440 | - pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); | |
| 441 | - if( p->mxRail>=GR_MAX_RAIL ) return; | |
| 442 | - pDesc = pRow; | |
| 443 | - pParent = 0; | |
| 456 | + continue; | |
| 444 | 457 | }else{ |
| 445 | 458 | assert( pRow->nParent>0 ); |
| 446 | 459 | parentRid = pRow->aParent[0]; |
| 447 | 460 | pParent = hashFind(p, parentRid); |
| 448 | 461 | if( pParent==0 ){ |
| @@ -515,27 +528,34 @@ | ||
| 515 | 528 | |
| 516 | 529 | /* |
| 517 | 530 | ** Insert merge rails from primaries to duplicates. |
| 518 | 531 | */ |
| 519 | 532 | if( hasDup ){ |
| 533 | + int dupRail; | |
| 534 | + int mxRail; | |
| 535 | + find_max_rail(p); | |
| 536 | + mxRail = p->mxRail; | |
| 537 | + dupRail = mxRail+1; | |
| 538 | + if( p->mxRail>=GR_MAX_RAIL ) return; | |
| 520 | 539 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 521 | 540 | if( !pRow->isDup ) continue; |
| 541 | + pRow->iRail = dupRail; | |
| 522 | 542 | pDesc = hashFind(p, pRow->rid); |
| 523 | 543 | assert( pDesc!=0 && pDesc!=pRow ); |
| 524 | 544 | createMergeRiser(p, pDesc, pRow); |
| 545 | + if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4; | |
| 546 | + } | |
| 547 | + if( dupRail<=mxRail ){ | |
| 548 | + dupRail = mxRail+1; | |
| 549 | + for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 550 | + if( pRow->isDup ) pRow->iRail = dupRail; | |
| 551 | + } | |
| 525 | 552 | } |
| 526 | - if( p->mxRail>=GR_MAX_RAIL ) return; | |
| 553 | + if( mxRail>=GR_MAX_RAIL ) return; | |
| 527 | 554 | } |
| 528 | 555 | |
| 529 | 556 | /* |
| 530 | 557 | ** Find the maximum rail number. |
| 531 | 558 | */ |
| 532 | - p->mxRail = 0; | |
| 533 | - for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 534 | - if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; | |
| 535 | - if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4; | |
| 536 | - while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){ | |
| 537 | - p->mxRail++; | |
| 538 | - } | |
| 539 | - } | |
| 559 | + find_max_rail(p); | |
| 540 | 560 | p->nErr = 0; |
| 541 | 561 | } |
| 542 | 562 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -306,20 +306,35 @@ | |
| 306 | } |
| 307 | } |
| 308 | pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1; |
| 309 | } |
| 310 | |
| 311 | |
| 312 | /* |
| 313 | ** Compute the complete graph |
| 314 | */ |
| 315 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 316 | GraphRow *pRow, *pDesc, *pDup, *pLoop, *pParent; |
| 317 | int i; |
| 318 | u32 mask; |
| 319 | u32 inUse; |
| 320 | int hasDup = 0; /* True if one or more isDup entries */ |
| 321 | const char *zTrunk; |
| 322 | |
| 323 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 324 | p->nErr = 1; /* Assume an error until proven otherwise */ |
| 325 | |
| @@ -390,10 +405,11 @@ | |
| 390 | ** Strive to put the "trunk" branch on far left. |
| 391 | */ |
| 392 | zTrunk = persistBranchName(p, "trunk"); |
| 393 | for(i=0; i<2; i++){ |
| 394 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 395 | if( i==0 ){ |
| 396 | if( pRow->zBranch!=zTrunk ) continue; |
| 397 | }else { |
| 398 | if( pRow->iRail>=0 ) continue; |
| 399 | } |
| @@ -422,11 +438,11 @@ | |
| 422 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 423 | int parentRid; |
| 424 | |
| 425 | if( pRow->iRail>=0 ){ |
| 426 | if( pRow->pChild==0 && !pRow->timeWarp ){ |
| 427 | if( pRow->isLeaf || omitDescenders ){ |
| 428 | inUse &= ~(1<<pRow->iRail); |
| 429 | }else{ |
| 430 | pRow->aiRiser[pRow->iRail] = 0; |
| 431 | mask = 1<<pRow->iRail; |
| 432 | for(pLoop=pRow; pLoop; pLoop=pLoop->pPrev){ |
| @@ -435,14 +451,11 @@ | |
| 435 | } |
| 436 | } |
| 437 | continue; |
| 438 | } |
| 439 | if( pRow->isDup ){ |
| 440 | pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); |
| 441 | if( p->mxRail>=GR_MAX_RAIL ) return; |
| 442 | pDesc = pRow; |
| 443 | pParent = 0; |
| 444 | }else{ |
| 445 | assert( pRow->nParent>0 ); |
| 446 | parentRid = pRow->aParent[0]; |
| 447 | pParent = hashFind(p, parentRid); |
| 448 | if( pParent==0 ){ |
| @@ -515,27 +528,34 @@ | |
| 515 | |
| 516 | /* |
| 517 | ** Insert merge rails from primaries to duplicates. |
| 518 | */ |
| 519 | if( hasDup ){ |
| 520 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 521 | if( !pRow->isDup ) continue; |
| 522 | pDesc = hashFind(p, pRow->rid); |
| 523 | assert( pDesc!=0 && pDesc!=pRow ); |
| 524 | createMergeRiser(p, pDesc, pRow); |
| 525 | } |
| 526 | if( p->mxRail>=GR_MAX_RAIL ) return; |
| 527 | } |
| 528 | |
| 529 | /* |
| 530 | ** Find the maximum rail number. |
| 531 | */ |
| 532 | p->mxRail = 0; |
| 533 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 534 | if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; |
| 535 | if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4; |
| 536 | while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){ |
| 537 | p->mxRail++; |
| 538 | } |
| 539 | } |
| 540 | p->nErr = 0; |
| 541 | } |
| 542 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -306,20 +306,35 @@ | |
| 306 | } |
| 307 | } |
| 308 | pChild->mergeIn[pParent->mergeOut/4] = (pParent->mergeOut&3)+1; |
| 309 | } |
| 310 | |
| 311 | /* |
| 312 | ** Compute the maximum rail number. |
| 313 | */ |
| 314 | static void find_max_rail(GraphContext *p){ |
| 315 | GraphRow *pRow; |
| 316 | p->mxRail = 0; |
| 317 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 318 | if( pRow->iRail>p->mxRail ) p->mxRail = pRow->iRail; |
| 319 | if( pRow->mergeOut/4>p->mxRail ) p->mxRail = pRow->mergeOut/4; |
| 320 | while( p->mxRail<GR_MAX_RAIL && pRow->mergeDown>((1<<(p->mxRail+1))-1) ){ |
| 321 | p->mxRail++; |
| 322 | } |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | |
| 327 | /* |
| 328 | ** Compute the complete graph |
| 329 | */ |
| 330 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 331 | GraphRow *pRow, *pDesc, *pDup, *pLoop, *pParent; |
| 332 | int i; |
| 333 | u32 mask; |
| 334 | u32 inUse; |
| 335 | int hasDup = 0; /* True if one or more isDup entries */ |
| 336 | const char *zTrunk; |
| 337 | |
| 338 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 339 | p->nErr = 1; /* Assume an error until proven otherwise */ |
| 340 | |
| @@ -390,10 +405,11 @@ | |
| 405 | ** Strive to put the "trunk" branch on far left. |
| 406 | */ |
| 407 | zTrunk = persistBranchName(p, "trunk"); |
| 408 | for(i=0; i<2; i++){ |
| 409 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 410 | if( pRow->isDup ) continue; |
| 411 | if( i==0 ){ |
| 412 | if( pRow->zBranch!=zTrunk ) continue; |
| 413 | }else { |
| 414 | if( pRow->iRail>=0 ) continue; |
| 415 | } |
| @@ -422,11 +438,11 @@ | |
| 438 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 439 | int parentRid; |
| 440 | |
| 441 | if( pRow->iRail>=0 ){ |
| 442 | if( pRow->pChild==0 && !pRow->timeWarp ){ |
| 443 | if( omitDescenders || count_nonbranch_children(pRow->rid)==0 ){ |
| 444 | inUse &= ~(1<<pRow->iRail); |
| 445 | }else{ |
| 446 | pRow->aiRiser[pRow->iRail] = 0; |
| 447 | mask = 1<<pRow->iRail; |
| 448 | for(pLoop=pRow; pLoop; pLoop=pLoop->pPrev){ |
| @@ -435,14 +451,11 @@ | |
| 451 | } |
| 452 | } |
| 453 | continue; |
| 454 | } |
| 455 | if( pRow->isDup ){ |
| 456 | continue; |
| 457 | }else{ |
| 458 | assert( pRow->nParent>0 ); |
| 459 | parentRid = pRow->aParent[0]; |
| 460 | pParent = hashFind(p, parentRid); |
| 461 | if( pParent==0 ){ |
| @@ -515,27 +528,34 @@ | |
| 528 | |
| 529 | /* |
| 530 | ** Insert merge rails from primaries to duplicates. |
| 531 | */ |
| 532 | if( hasDup ){ |
| 533 | int dupRail; |
| 534 | int mxRail; |
| 535 | find_max_rail(p); |
| 536 | mxRail = p->mxRail; |
| 537 | dupRail = mxRail+1; |
| 538 | if( p->mxRail>=GR_MAX_RAIL ) return; |
| 539 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 540 | if( !pRow->isDup ) continue; |
| 541 | pRow->iRail = dupRail; |
| 542 | pDesc = hashFind(p, pRow->rid); |
| 543 | assert( pDesc!=0 && pDesc!=pRow ); |
| 544 | createMergeRiser(p, pDesc, pRow); |
| 545 | if( pDesc->mergeOut/4>mxRail ) mxRail = pDesc->mergeOut/4; |
| 546 | } |
| 547 | if( dupRail<=mxRail ){ |
| 548 | dupRail = mxRail+1; |
| 549 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 550 | if( pRow->isDup ) pRow->iRail = dupRail; |
| 551 | } |
| 552 | } |
| 553 | if( mxRail>=GR_MAX_RAIL ) return; |
| 554 | } |
| 555 | |
| 556 | /* |
| 557 | ** Find the maximum rail number. |
| 558 | */ |
| 559 | find_max_rail(p); |
| 560 | p->nErr = 0; |
| 561 | } |
| 562 |
+15
-13
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -62,26 +62,21 @@ | ||
| 62 | 62 | /* Password failure while doing a sync from the command-line interface */ |
| 63 | 63 | url_prompt_for_password(); |
| 64 | 64 | zPw = g.urlPasswd; |
| 65 | 65 | if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0); |
| 66 | 66 | } |
| 67 | + | |
| 68 | + /* If the first character of the password is "#", then that character is | |
| 69 | + ** not really part of the password - it is an indicator that we should | |
| 70 | + ** use Basic Authentication. So skip that character. | |
| 71 | + */ | |
| 72 | + if( zPw && zPw[0]=='#' ) zPw++; | |
| 67 | 73 | |
| 68 | 74 | /* The login card wants the SHA1 hash of the password, so convert the |
| 69 | 75 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 70 | - ** | |
| 71 | - ** Except, if the password begins with "*" then use the characters | |
| 72 | - ** after the "*" as a cleartext password. Put an "*" at the beginning | |
| 73 | - ** of the password to trick a newer client to use the cleartext password | |
| 74 | - ** protocol required by legacy servers. | |
| 75 | 76 | */ |
| 76 | - if( zPw && zPw[0] ){ | |
| 77 | - if( zPw[0]=='*' ){ | |
| 78 | - zPw++; | |
| 79 | - }else{ | |
| 80 | - zPw = sha1_shared_secret(zPw, zLogin, 0); | |
| 81 | - } | |
| 82 | - } | |
| 77 | + if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0); | |
| 83 | 78 | |
| 84 | 79 | blob_append(&pw, zPw, -1); |
| 85 | 80 | sha1sum_blob(&pw, &sig); |
| 86 | 81 | blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig); |
| 87 | 82 | blob_reset(&pw); |
| @@ -105,11 +100,18 @@ | ||
| 105 | 100 | }else{ |
| 106 | 101 | zSep = "/"; |
| 107 | 102 | } |
| 108 | 103 | blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep); |
| 109 | 104 | if( g.urlProxyAuth ){ |
| 110 | - blob_appendf(pHdr, "Proxy-Authorization: %s\n", g.urlProxyAuth); | |
| 105 | + blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth); | |
| 106 | + } | |
| 107 | + if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){ | |
| 108 | + char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]); | |
| 109 | + char *zEncoded = encode64(zCredentials, -1); | |
| 110 | + blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded); | |
| 111 | + fossil_free(zEncoded); | |
| 112 | + fossil_free(zCredentials); | |
| 111 | 113 | } |
| 112 | 114 | blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname); |
| 113 | 115 | blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n"); |
| 114 | 116 | if( g.fHttpTrace ){ |
| 115 | 117 | blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 116 | 118 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -62,26 +62,21 @@ | |
| 62 | /* Password failure while doing a sync from the command-line interface */ |
| 63 | url_prompt_for_password(); |
| 64 | zPw = g.urlPasswd; |
| 65 | if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0); |
| 66 | } |
| 67 | |
| 68 | /* The login card wants the SHA1 hash of the password, so convert the |
| 69 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 70 | ** |
| 71 | ** Except, if the password begins with "*" then use the characters |
| 72 | ** after the "*" as a cleartext password. Put an "*" at the beginning |
| 73 | ** of the password to trick a newer client to use the cleartext password |
| 74 | ** protocol required by legacy servers. |
| 75 | */ |
| 76 | if( zPw && zPw[0] ){ |
| 77 | if( zPw[0]=='*' ){ |
| 78 | zPw++; |
| 79 | }else{ |
| 80 | zPw = sha1_shared_secret(zPw, zLogin, 0); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | blob_append(&pw, zPw, -1); |
| 85 | sha1sum_blob(&pw, &sig); |
| 86 | blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig); |
| 87 | blob_reset(&pw); |
| @@ -105,11 +100,18 @@ | |
| 105 | }else{ |
| 106 | zSep = "/"; |
| 107 | } |
| 108 | blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep); |
| 109 | if( g.urlProxyAuth ){ |
| 110 | blob_appendf(pHdr, "Proxy-Authorization: %s\n", g.urlProxyAuth); |
| 111 | } |
| 112 | blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname); |
| 113 | blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n"); |
| 114 | if( g.fHttpTrace ){ |
| 115 | blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 116 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -62,26 +62,21 @@ | |
| 62 | /* Password failure while doing a sync from the command-line interface */ |
| 63 | url_prompt_for_password(); |
| 64 | zPw = g.urlPasswd; |
| 65 | if( !g.dontKeepUrl ) db_set("last-sync-pw", obscure(zPw), 0); |
| 66 | } |
| 67 | |
| 68 | /* If the first character of the password is "#", then that character is |
| 69 | ** not really part of the password - it is an indicator that we should |
| 70 | ** use Basic Authentication. So skip that character. |
| 71 | */ |
| 72 | if( zPw && zPw[0]=='#' ) zPw++; |
| 73 | |
| 74 | /* The login card wants the SHA1 hash of the password, so convert the |
| 75 | ** password to its SHA1 hash it it isn't already a SHA1 hash. |
| 76 | */ |
| 77 | if( zPw && zPw[0] ) zPw = sha1_shared_secret(zPw, zLogin, 0); |
| 78 | |
| 79 | blob_append(&pw, zPw, -1); |
| 80 | sha1sum_blob(&pw, &sig); |
| 81 | blob_appendf(pLogin, "login %F %b %b\n", zLogin, &nonce, &sig); |
| 82 | blob_reset(&pw); |
| @@ -105,11 +100,18 @@ | |
| 100 | }else{ |
| 101 | zSep = "/"; |
| 102 | } |
| 103 | blob_appendf(pHdr, "POST %s%sxfer/xfer HTTP/1.0\r\n", g.urlPath, zSep); |
| 104 | if( g.urlProxyAuth ){ |
| 105 | blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.urlProxyAuth); |
| 106 | } |
| 107 | if( g.urlPasswd && g.urlUser && g.urlPasswd[0]=='#' ){ |
| 108 | char *zCredentials = mprintf("%s:%s", g.urlUser, &g.urlPasswd[1]); |
| 109 | char *zEncoded = encode64(zCredentials, -1); |
| 110 | blob_appendf(pHdr, "Authorization: Basic %s\r\n", zEncoded); |
| 111 | fossil_free(zEncoded); |
| 112 | fossil_free(zCredentials); |
| 113 | } |
| 114 | blob_appendf(pHdr, "Host: %s\r\n", g.urlHostname); |
| 115 | blob_appendf(pHdr, "User-Agent: Fossil/" MANIFEST_VERSION "\r\n"); |
| 116 | if( g.fHttpTrace ){ |
| 117 | blob_appendf(pHdr, "Content-Type: application/x-fossil-debug\r\n"); |
| 118 |
+9
| --- src/http_ssl.c | ||
| +++ src/http_ssl.c | ||
| @@ -182,15 +182,24 @@ | ||
| 182 | 182 | if( SSL_get_verify_result(ssl) != X509_V_OK ){ |
| 183 | 183 | char *desc, *prompt; |
| 184 | 184 | char *warning = ""; |
| 185 | 185 | Blob ans; |
| 186 | 186 | BIO *mem; |
| 187 | + unsigned char md[32]; | |
| 188 | + unsigned int mdLength = 31; | |
| 187 | 189 | |
| 188 | 190 | mem = BIO_new(BIO_s_mem()); |
| 189 | 191 | X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE); |
| 190 | 192 | BIO_puts(mem, "\n\nIssued By:\n\n"); |
| 191 | 193 | X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE); |
| 194 | + BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n "); | |
| 195 | + if(X509_digest(cert, EVP_sha1(), md, &mdLength)){ | |
| 196 | + int j; | |
| 197 | + for( j = 0; j < mdLength; ++j ) { | |
| 198 | + BIO_printf(mem, " %02x", md[j]); | |
| 199 | + } | |
| 200 | + } | |
| 192 | 201 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 193 | 202 | BIO_get_mem_data(mem, &desc); |
| 194 | 203 | |
| 195 | 204 | if( hasSavedCertificate ){ |
| 196 | 205 | warning = "WARNING: Certificate doesn't match the " |
| 197 | 206 |
| --- src/http_ssl.c | |
| +++ src/http_ssl.c | |
| @@ -182,15 +182,24 @@ | |
| 182 | if( SSL_get_verify_result(ssl) != X509_V_OK ){ |
| 183 | char *desc, *prompt; |
| 184 | char *warning = ""; |
| 185 | Blob ans; |
| 186 | BIO *mem; |
| 187 | |
| 188 | mem = BIO_new(BIO_s_mem()); |
| 189 | X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE); |
| 190 | BIO_puts(mem, "\n\nIssued By:\n\n"); |
| 191 | X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE); |
| 192 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 193 | BIO_get_mem_data(mem, &desc); |
| 194 | |
| 195 | if( hasSavedCertificate ){ |
| 196 | warning = "WARNING: Certificate doesn't match the " |
| 197 |
| --- src/http_ssl.c | |
| +++ src/http_ssl.c | |
| @@ -182,15 +182,24 @@ | |
| 182 | if( SSL_get_verify_result(ssl) != X509_V_OK ){ |
| 183 | char *desc, *prompt; |
| 184 | char *warning = ""; |
| 185 | Blob ans; |
| 186 | BIO *mem; |
| 187 | unsigned char md[32]; |
| 188 | unsigned int mdLength = 31; |
| 189 | |
| 190 | mem = BIO_new(BIO_s_mem()); |
| 191 | X509_NAME_print_ex(mem, X509_get_subject_name(cert), 2, XN_FLAG_MULTILINE); |
| 192 | BIO_puts(mem, "\n\nIssued By:\n\n"); |
| 193 | X509_NAME_print_ex(mem, X509_get_issuer_name(cert), 2, XN_FLAG_MULTILINE); |
| 194 | BIO_puts(mem, "\n\nSHA1 Fingerprint:\n\n "); |
| 195 | if(X509_digest(cert, EVP_sha1(), md, &mdLength)){ |
| 196 | int j; |
| 197 | for( j = 0; j < mdLength; ++j ) { |
| 198 | BIO_printf(mem, " %02x", md[j]); |
| 199 | } |
| 200 | } |
| 201 | BIO_write(mem, "", 1); // null-terminate mem buffer |
| 202 | BIO_get_mem_data(mem, &desc); |
| 203 | |
| 204 | if( hasSavedCertificate ){ |
| 205 | warning = "WARNING: Certificate doesn't match the " |
| 206 |
+6
-5
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -120,11 +120,11 @@ | ||
| 120 | 120 | blob_appendf(&zCmd, " -P %d", g.urlPort); |
| 121 | 121 | #else |
| 122 | 122 | blob_appendf(&zCmd, " -p %d", g.urlPort); |
| 123 | 123 | #endif |
| 124 | 124 | } |
| 125 | - printf("%s", blob_str(&zCmd)); /* Show the base of the SSH command */ | |
| 125 | + fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */ | |
| 126 | 126 | if( g.urlUser && g.urlUser[0] ){ |
| 127 | 127 | zHost = mprintf("%s@%s", g.urlUser, g.urlName); |
| 128 | 128 | #ifdef __MINGW32__ |
| 129 | 129 | /* Only win32 (and specifically PLINK.EXE) support the -pw option */ |
| 130 | 130 | if( g.urlPasswd && g.urlPasswd[0] ){ |
| @@ -139,19 +139,19 @@ | ||
| 139 | 139 | blob_init(&pw, g.urlPasswd, -1); |
| 140 | 140 | } |
| 141 | 141 | blob_append(&zCmd, " -pw ", -1); |
| 142 | 142 | shell_escape(&zCmd, blob_str(&pw)); |
| 143 | 143 | blob_reset(&pw); |
| 144 | - printf(" -pw ********"); /* Do not show the password text */ | |
| 144 | + fossil_print(" -pw ********"); /* Do not show the password text */ | |
| 145 | 145 | } |
| 146 | 146 | #endif |
| 147 | 147 | }else{ |
| 148 | 148 | zHost = mprintf("%s", g.urlName); |
| 149 | 149 | } |
| 150 | 150 | blob_append(&zCmd, " ", 1); |
| 151 | 151 | shell_escape(&zCmd, zHost); |
| 152 | - printf(" %s\n", zHost); /* Show the conclusion of the SSH command */ | |
| 152 | + fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */ | |
| 153 | 153 | free(zHost); |
| 154 | 154 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 155 | 155 | if( sshPid==0 ){ |
| 156 | 156 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 157 | 157 | } |
| @@ -246,12 +246,12 @@ | ||
| 246 | 246 | }else if( g.urlIsFile ){ |
| 247 | 247 | if( transport.pFile ){ |
| 248 | 248 | fclose(transport.pFile); |
| 249 | 249 | transport.pFile = 0; |
| 250 | 250 | } |
| 251 | - unlink(transport.zInFile); | |
| 252 | - unlink(transport.zOutFile); | |
| 251 | + file_delete(transport.zInFile); | |
| 252 | + file_delete(transport.zOutFile); | |
| 253 | 253 | free(transport.zInFile); |
| 254 | 254 | free(transport.zOutFile); |
| 255 | 255 | }else{ |
| 256 | 256 | socket_close(); |
| 257 | 257 | } |
| @@ -432,10 +432,11 @@ | ||
| 432 | 432 | transport.pBuf = pNew; |
| 433 | 433 | } |
| 434 | 434 | if( N>0 ){ |
| 435 | 435 | i = transport_fetch(&transport.pBuf[transport.nUsed], N); |
| 436 | 436 | if( i>0 ){ |
| 437 | + transport.nRcvd += i; | |
| 437 | 438 | transport.nUsed += i; |
| 438 | 439 | } |
| 439 | 440 | } |
| 440 | 441 | } |
| 441 | 442 | |
| 442 | 443 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -120,11 +120,11 @@ | |
| 120 | blob_appendf(&zCmd, " -P %d", g.urlPort); |
| 121 | #else |
| 122 | blob_appendf(&zCmd, " -p %d", g.urlPort); |
| 123 | #endif |
| 124 | } |
| 125 | printf("%s", blob_str(&zCmd)); /* Show the base of the SSH command */ |
| 126 | if( g.urlUser && g.urlUser[0] ){ |
| 127 | zHost = mprintf("%s@%s", g.urlUser, g.urlName); |
| 128 | #ifdef __MINGW32__ |
| 129 | /* Only win32 (and specifically PLINK.EXE) support the -pw option */ |
| 130 | if( g.urlPasswd && g.urlPasswd[0] ){ |
| @@ -139,19 +139,19 @@ | |
| 139 | blob_init(&pw, g.urlPasswd, -1); |
| 140 | } |
| 141 | blob_append(&zCmd, " -pw ", -1); |
| 142 | shell_escape(&zCmd, blob_str(&pw)); |
| 143 | blob_reset(&pw); |
| 144 | printf(" -pw ********"); /* Do not show the password text */ |
| 145 | } |
| 146 | #endif |
| 147 | }else{ |
| 148 | zHost = mprintf("%s", g.urlName); |
| 149 | } |
| 150 | blob_append(&zCmd, " ", 1); |
| 151 | shell_escape(&zCmd, zHost); |
| 152 | printf(" %s\n", zHost); /* Show the conclusion of the SSH command */ |
| 153 | free(zHost); |
| 154 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 155 | if( sshPid==0 ){ |
| 156 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 157 | } |
| @@ -246,12 +246,12 @@ | |
| 246 | }else if( g.urlIsFile ){ |
| 247 | if( transport.pFile ){ |
| 248 | fclose(transport.pFile); |
| 249 | transport.pFile = 0; |
| 250 | } |
| 251 | unlink(transport.zInFile); |
| 252 | unlink(transport.zOutFile); |
| 253 | free(transport.zInFile); |
| 254 | free(transport.zOutFile); |
| 255 | }else{ |
| 256 | socket_close(); |
| 257 | } |
| @@ -432,10 +432,11 @@ | |
| 432 | transport.pBuf = pNew; |
| 433 | } |
| 434 | if( N>0 ){ |
| 435 | i = transport_fetch(&transport.pBuf[transport.nUsed], N); |
| 436 | if( i>0 ){ |
| 437 | transport.nUsed += i; |
| 438 | } |
| 439 | } |
| 440 | } |
| 441 | |
| 442 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -120,11 +120,11 @@ | |
| 120 | blob_appendf(&zCmd, " -P %d", g.urlPort); |
| 121 | #else |
| 122 | blob_appendf(&zCmd, " -p %d", g.urlPort); |
| 123 | #endif |
| 124 | } |
| 125 | fossil_print("%s", blob_str(&zCmd)); /* Show the base of the SSH command */ |
| 126 | if( g.urlUser && g.urlUser[0] ){ |
| 127 | zHost = mprintf("%s@%s", g.urlUser, g.urlName); |
| 128 | #ifdef __MINGW32__ |
| 129 | /* Only win32 (and specifically PLINK.EXE) support the -pw option */ |
| 130 | if( g.urlPasswd && g.urlPasswd[0] ){ |
| @@ -139,19 +139,19 @@ | |
| 139 | blob_init(&pw, g.urlPasswd, -1); |
| 140 | } |
| 141 | blob_append(&zCmd, " -pw ", -1); |
| 142 | shell_escape(&zCmd, blob_str(&pw)); |
| 143 | blob_reset(&pw); |
| 144 | fossil_print(" -pw ********"); /* Do not show the password text */ |
| 145 | } |
| 146 | #endif |
| 147 | }else{ |
| 148 | zHost = mprintf("%s", g.urlName); |
| 149 | } |
| 150 | blob_append(&zCmd, " ", 1); |
| 151 | shell_escape(&zCmd, zHost); |
| 152 | fossil_print(" %s\n", zHost); /* Show the conclusion of the SSH command */ |
| 153 | free(zHost); |
| 154 | popen2(blob_str(&zCmd), &sshIn, &sshOut, &sshPid); |
| 155 | if( sshPid==0 ){ |
| 156 | fossil_fatal("cannot start ssh tunnel using [%b]", &zCmd); |
| 157 | } |
| @@ -246,12 +246,12 @@ | |
| 246 | }else if( g.urlIsFile ){ |
| 247 | if( transport.pFile ){ |
| 248 | fclose(transport.pFile); |
| 249 | transport.pFile = 0; |
| 250 | } |
| 251 | file_delete(transport.zInFile); |
| 252 | file_delete(transport.zOutFile); |
| 253 | free(transport.zInFile); |
| 254 | free(transport.zOutFile); |
| 255 | }else{ |
| 256 | socket_close(); |
| 257 | } |
| @@ -432,10 +432,11 @@ | |
| 432 | transport.pBuf = pNew; |
| 433 | } |
| 434 | if( N>0 ){ |
| 435 | i = transport_fetch(&transport.pBuf[transport.nUsed], N); |
| 436 | if( i>0 ){ |
| 437 | transport.nRcvd += i; |
| 438 | transport.nUsed += i; |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | |
| 443 |
+8
-8
| --- src/import.c | ||
| +++ src/import.c | ||
| @@ -497,11 +497,11 @@ | ||
| 497 | 497 | gg.xFinish(); |
| 498 | 498 | }else |
| 499 | 499 | if( memcmp(zLine, "progress ", 9)==0 ){ |
| 500 | 500 | gg.xFinish(); |
| 501 | 501 | trim_newline(&zLine[9]); |
| 502 | - printf("%s\n", &zLine[9]); | |
| 502 | + fossil_print("%s\n", &zLine[9]); | |
| 503 | 503 | fflush(stdout); |
| 504 | 504 | }else |
| 505 | 505 | if( memcmp(zLine, "data ", 5)==0 ){ |
| 506 | 506 | fossil_free(gg.aData); gg.aData = 0; |
| 507 | 507 | gg.nData = atoi(&zLine[5]); |
| @@ -697,11 +697,11 @@ | ||
| 697 | 697 | }else{ |
| 698 | 698 | pIn = stdin; |
| 699 | 699 | fossil_binary_mode(pIn); |
| 700 | 700 | } |
| 701 | 701 | if( !incrFlag ){ |
| 702 | - if( forceFlag ) unlink(g.argv[2]); | |
| 702 | + if( forceFlag ) file_delete(g.argv[2]); | |
| 703 | 703 | db_create_repository(g.argv[2]); |
| 704 | 704 | } |
| 705 | 705 | db_open_repository(g.argv[2]); |
| 706 | 706 | db_open_config(0); |
| 707 | 707 | |
| @@ -742,19 +742,19 @@ | ||
| 742 | 742 | import_reset(0); |
| 743 | 743 | } |
| 744 | 744 | db_finalize(&q); |
| 745 | 745 | db_end_transaction(0); |
| 746 | 746 | db_begin_transaction(); |
| 747 | - printf("Rebuilding repository meta-data...\n"); | |
| 747 | + fossil_print("Rebuilding repository meta-data...\n"); | |
| 748 | 748 | rebuild_db(0, 1, !incrFlag); |
| 749 | 749 | verify_cancel(); |
| 750 | 750 | db_end_transaction(0); |
| 751 | - printf("Vacuuming..."); fflush(stdout); | |
| 751 | + fossil_print("Vacuuming..."); fflush(stdout); | |
| 752 | 752 | db_multi_exec("VACUUM"); |
| 753 | - printf(" ok\n"); | |
| 753 | + fossil_print(" ok\n"); | |
| 754 | 754 | if( !incrFlag ){ |
| 755 | - printf("project-id: %s\n", db_get("project-code", 0)); | |
| 756 | - printf("server-id: %s\n", db_get("server-code", 0)); | |
| 755 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 756 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 757 | 757 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 758 | - printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 758 | + fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); | |
| 759 | 759 | } |
| 760 | 760 | } |
| 761 | 761 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -497,11 +497,11 @@ | |
| 497 | gg.xFinish(); |
| 498 | }else |
| 499 | if( memcmp(zLine, "progress ", 9)==0 ){ |
| 500 | gg.xFinish(); |
| 501 | trim_newline(&zLine[9]); |
| 502 | printf("%s\n", &zLine[9]); |
| 503 | fflush(stdout); |
| 504 | }else |
| 505 | if( memcmp(zLine, "data ", 5)==0 ){ |
| 506 | fossil_free(gg.aData); gg.aData = 0; |
| 507 | gg.nData = atoi(&zLine[5]); |
| @@ -697,11 +697,11 @@ | |
| 697 | }else{ |
| 698 | pIn = stdin; |
| 699 | fossil_binary_mode(pIn); |
| 700 | } |
| 701 | if( !incrFlag ){ |
| 702 | if( forceFlag ) unlink(g.argv[2]); |
| 703 | db_create_repository(g.argv[2]); |
| 704 | } |
| 705 | db_open_repository(g.argv[2]); |
| 706 | db_open_config(0); |
| 707 | |
| @@ -742,19 +742,19 @@ | |
| 742 | import_reset(0); |
| 743 | } |
| 744 | db_finalize(&q); |
| 745 | db_end_transaction(0); |
| 746 | db_begin_transaction(); |
| 747 | printf("Rebuilding repository meta-data...\n"); |
| 748 | rebuild_db(0, 1, !incrFlag); |
| 749 | verify_cancel(); |
| 750 | db_end_transaction(0); |
| 751 | printf("Vacuuming..."); fflush(stdout); |
| 752 | db_multi_exec("VACUUM"); |
| 753 | printf(" ok\n"); |
| 754 | if( !incrFlag ){ |
| 755 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 756 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 757 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 758 | printf("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 759 | } |
| 760 | } |
| 761 |
| --- src/import.c | |
| +++ src/import.c | |
| @@ -497,11 +497,11 @@ | |
| 497 | gg.xFinish(); |
| 498 | }else |
| 499 | if( memcmp(zLine, "progress ", 9)==0 ){ |
| 500 | gg.xFinish(); |
| 501 | trim_newline(&zLine[9]); |
| 502 | fossil_print("%s\n", &zLine[9]); |
| 503 | fflush(stdout); |
| 504 | }else |
| 505 | if( memcmp(zLine, "data ", 5)==0 ){ |
| 506 | fossil_free(gg.aData); gg.aData = 0; |
| 507 | gg.nData = atoi(&zLine[5]); |
| @@ -697,11 +697,11 @@ | |
| 697 | }else{ |
| 698 | pIn = stdin; |
| 699 | fossil_binary_mode(pIn); |
| 700 | } |
| 701 | if( !incrFlag ){ |
| 702 | if( forceFlag ) file_delete(g.argv[2]); |
| 703 | db_create_repository(g.argv[2]); |
| 704 | } |
| 705 | db_open_repository(g.argv[2]); |
| 706 | db_open_config(0); |
| 707 | |
| @@ -742,19 +742,19 @@ | |
| 742 | import_reset(0); |
| 743 | } |
| 744 | db_finalize(&q); |
| 745 | db_end_transaction(0); |
| 746 | db_begin_transaction(); |
| 747 | fossil_print("Rebuilding repository meta-data...\n"); |
| 748 | rebuild_db(0, 1, !incrFlag); |
| 749 | verify_cancel(); |
| 750 | db_end_transaction(0); |
| 751 | fossil_print("Vacuuming..."); fflush(stdout); |
| 752 | db_multi_exec("VACUUM"); |
| 753 | fossil_print(" ok\n"); |
| 754 | if( !incrFlag ){ |
| 755 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 756 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 757 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 758 | fossil_print("admin-user: %s (password is \"%s\")\n", g.zLogin, zPassword); |
| 759 | } |
| 760 | } |
| 761 |
+35
-26
| --- src/info.c | ||
| +++ src/info.c | ||
| @@ -67,11 +67,11 @@ | ||
| 67 | 67 | zDate = db_text(0, |
| 68 | 68 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 69 | 69 | rid |
| 70 | 70 | ); |
| 71 | 71 | /* 01234567890123 */ |
| 72 | - printf("%-13s %s %s\n", zUuidName, zUuid, zDate ? zDate : ""); | |
| 72 | + fossil_print("%-13s %s %s\n", zUuidName, zUuid, zDate ? zDate : ""); | |
| 73 | 73 | free(zUuid); |
| 74 | 74 | free(zDate); |
| 75 | 75 | } |
| 76 | 76 | if( zUuid && showComment ){ |
| 77 | 77 | zComment = db_text(0, |
| @@ -88,11 +88,11 @@ | ||
| 88 | 88 | const char *zUuid = db_column_text(&q, 0); |
| 89 | 89 | zDate = db_text("", |
| 90 | 90 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 91 | 91 | db_column_int(&q, 1) |
| 92 | 92 | ); |
| 93 | - printf("parent: %s %s\n", zUuid, zDate); | |
| 93 | + fossil_print("parent: %s %s\n", zUuid, zDate); | |
| 94 | 94 | free(zDate); |
| 95 | 95 | } |
| 96 | 96 | db_finalize(&q); |
| 97 | 97 | db_prepare(&q, "SELECT uuid, cid FROM plink JOIN blob ON cid=rid " |
| 98 | 98 | " WHERE pid=%d", rid); |
| @@ -100,22 +100,22 @@ | ||
| 100 | 100 | const char *zUuid = db_column_text(&q, 0); |
| 101 | 101 | zDate = db_text("", |
| 102 | 102 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 103 | 103 | db_column_int(&q, 1) |
| 104 | 104 | ); |
| 105 | - printf("child: %s %s\n", zUuid, zDate); | |
| 105 | + fossil_print("child: %s %s\n", zUuid, zDate); | |
| 106 | 106 | free(zDate); |
| 107 | 107 | } |
| 108 | 108 | db_finalize(&q); |
| 109 | 109 | } |
| 110 | 110 | zTags = info_tags_of_checkin(rid, 0); |
| 111 | 111 | if( zTags && zTags[0] ){ |
| 112 | - printf("tags: %s\n", zTags); | |
| 112 | + fossil_print("tags: %s\n", zTags); | |
| 113 | 113 | } |
| 114 | 114 | free(zTags); |
| 115 | 115 | if( zComment ){ |
| 116 | - printf("comment: "); | |
| 116 | + fossil_print("comment: "); | |
| 117 | 117 | comment_print(zComment, 14, 79); |
| 118 | 118 | free(zComment); |
| 119 | 119 | } |
| 120 | 120 | } |
| 121 | 121 | |
| @@ -141,33 +141,33 @@ | ||
| 141 | 141 | } |
| 142 | 142 | if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){ |
| 143 | 143 | db_open_config(0); |
| 144 | 144 | db_record_repository_filename(g.argv[2]); |
| 145 | 145 | db_open_repository(g.argv[2]); |
| 146 | - printf("project-name: %s\n", db_get("project-name", "<unnamed>")); | |
| 147 | - printf("project-code: %s\n", db_get("project-code", "<none>")); | |
| 148 | - printf("server-code: %s\n", db_get("server-code", "<none>")); | |
| 146 | + fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); | |
| 147 | + fossil_print("project-code: %s\n", db_get("project-code", "<none>")); | |
| 148 | + fossil_print("server-code: %s\n", db_get("server-code", "<none>")); | |
| 149 | 149 | return; |
| 150 | 150 | } |
| 151 | 151 | db_must_be_within_tree(); |
| 152 | 152 | if( g.argc==2 ){ |
| 153 | 153 | int vid; |
| 154 | 154 | /* 012345678901234 */ |
| 155 | 155 | db_record_repository_filename(0); |
| 156 | - printf("project-name: %s\n", db_get("project-name", "<unnamed>")); | |
| 157 | - printf("repository: %s\n", db_lget("repository", "")); | |
| 158 | - printf("local-root: %s\n", g.zLocalRoot); | |
| 156 | + fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); | |
| 157 | + fossil_print("repository: %s\n", db_lget("repository", "")); | |
| 158 | + fossil_print("local-root: %s\n", g.zLocalRoot); | |
| 159 | 159 | #if defined(_WIN32) |
| 160 | 160 | if( g.zHome ){ |
| 161 | - printf("user-home: %s\n", g.zHome); | |
| 161 | + fossil_print("user-home: %s\n", g.zHome); | |
| 162 | 162 | } |
| 163 | 163 | #endif |
| 164 | - printf("project-code: %s\n", db_get("project-code", "")); | |
| 165 | - printf("server-code: %s\n", db_get("server-code", "")); | |
| 164 | + fossil_print("project-code: %s\n", db_get("project-code", "")); | |
| 165 | + fossil_print("server-code: %s\n", db_get("server-code", "")); | |
| 166 | 166 | vid = db_lget_int("checkout", 0); |
| 167 | 167 | if( vid==0 ){ |
| 168 | - printf("checkout: nil\n"); | |
| 168 | + fossil_print("checkout: nil\n"); | |
| 169 | 169 | }else{ |
| 170 | 170 | show_common_info(vid, "checkout:", 1, 1); |
| 171 | 171 | } |
| 172 | 172 | }else{ |
| 173 | 173 | int rid; |
| @@ -368,11 +368,11 @@ | ||
| 368 | 368 | zParent = db_text(0, |
| 369 | 369 | "SELECT uuid FROM plink, blob" |
| 370 | 370 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 371 | 371 | rid |
| 372 | 372 | ); |
| 373 | - isLeaf = !db_exists("SELECT 1 FROM plink WHERE pid=%d", rid); | |
| 373 | + isLeaf = is_a_leaf(rid); | |
| 374 | 374 | db_prepare(&q, |
| 375 | 375 | "SELECT uuid, datetime(mtime, 'localtime'), user, comment," |
| 376 | 376 | " datetime(omtime, 'localtime')" |
| 377 | 377 | " FROM blob, event" |
| 378 | 378 | " WHERE blob.rid=%d" |
| @@ -800,10 +800,14 @@ | ||
| 800 | 800 | @ part of check-in |
| 801 | 801 | hyperlink_to_uuid(zVers); |
| 802 | 802 | @ - %w(zCom) by |
| 803 | 803 | hyperlink_to_user(zUser,zDate," on"); |
| 804 | 804 | hyperlink_to_date(zDate,"."); |
| 805 | + if( g.okHistory ){ | |
| 806 | + @ <a href="%s(g.zTop)/annotate?checkin=%S(zVers)&filename=%T(zName)"> | |
| 807 | + @ [annotate]</a> | |
| 808 | + } | |
| 805 | 809 | cnt++; |
| 806 | 810 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 807 | 811 | blob_append(pDownloadName, zName, -1); |
| 808 | 812 | } |
| 809 | 813 | } |
| @@ -945,16 +949,20 @@ | ||
| 945 | 949 | */ |
| 946 | 950 | void diff_page(void){ |
| 947 | 951 | int v1, v2; |
| 948 | 952 | int isPatch; |
| 949 | 953 | Blob c1, c2, diff, *pOut; |
| 954 | + char *zV1; | |
| 955 | + char *zV2; | |
| 950 | 956 | |
| 951 | 957 | login_check_credentials(); |
| 952 | 958 | if( !g.okRead ){ login_needed(); return; } |
| 953 | 959 | v1 = name_to_rid_www("v1"); |
| 954 | 960 | v2 = name_to_rid_www("v2"); |
| 955 | 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | + zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); | |
| 963 | + zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); | |
| 956 | 964 | isPatch = P("patch")!=0; |
| 957 | 965 | if( isPatch ){ |
| 958 | 966 | pOut = cgi_output_blob(); |
| 959 | 967 | cgi_set_content_type("text/plain"); |
| 960 | 968 | }else{ |
| @@ -968,15 +976,16 @@ | ||
| 968 | 976 | blob_reset(&c2); |
| 969 | 977 | if( !isPatch ){ |
| 970 | 978 | style_header("Diff"); |
| 971 | 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 972 | 980 | g.zTop, P("v1"), P("v2")); |
| 973 | - @ <h2>Differences From:</h2> | |
| 981 | + @ <h2>Differences From | |
| 982 | + @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> | |
| 974 | 983 | @ <blockquote><p> |
| 975 | 984 | object_description(v1, 1, 0); |
| 976 | 985 | @ </p></blockquote> |
| 977 | - @ <h2>To:</h2> | |
| 986 | + @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> | |
| 978 | 987 | @ <blockquote><p> |
| 979 | 988 | object_description(v2, 1, 0); |
| 980 | 989 | @ </p></blockquote> |
| 981 | 990 | @ <hr /> |
| 982 | 991 | @ <blockquote><pre> |
| @@ -1579,29 +1588,29 @@ | ||
| 1579 | 1588 | } |
| 1580 | 1589 | zNewComment = PD("c",zComment); |
| 1581 | 1590 | zUser = db_text(0, "SELECT coalesce(euser,user)" |
| 1582 | 1591 | " FROM event WHERE objid=%d", rid); |
| 1583 | 1592 | if( zUser==0 ) fossil_redirect_home(); |
| 1584 | - zNewUser = PD("u",zUser); | |
| 1593 | + zNewUser = PDT("u",zUser); | |
| 1585 | 1594 | zDate = db_text(0, "SELECT datetime(mtime)" |
| 1586 | 1595 | " FROM event WHERE objid=%d", rid); |
| 1587 | 1596 | if( zDate==0 ) fossil_redirect_home(); |
| 1588 | - zNewDate = PD("dt",zDate); | |
| 1597 | + zNewDate = PDT("dt",zDate); | |
| 1589 | 1598 | zColor = db_text("", "SELECT bgcolor" |
| 1590 | 1599 | " FROM event WHERE objid=%d", rid); |
| 1591 | - zNewColor = PD("clr",zColor); | |
| 1600 | + zNewColor = PDT("clr",zColor); | |
| 1592 | 1601 | if( fossil_strcmp(zNewColor,"##")==0 ){ |
| 1593 | - zNewColor = P("clrcust"); | |
| 1602 | + zNewColor = PT("clrcust"); | |
| 1594 | 1603 | } |
| 1595 | 1604 | fPropagateColor = db_int(0, "SELECT tagtype FROM tagxref" |
| 1596 | 1605 | " WHERE rid=%d AND tagid=%d", |
| 1597 | 1606 | rid, TAG_BGCOLOR)==2; |
| 1598 | 1607 | fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor; |
| 1599 | 1608 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1600 | - zNewTag = PD("tagname",""); | |
| 1609 | + zNewTag = PDT("tagname",""); | |
| 1601 | 1610 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 1602 | - zNewBranch = PD("brname",""); | |
| 1611 | + zNewBranch = PDT("brname",""); | |
| 1603 | 1612 | zCloseFlag = P("close") ? " checked" : ""; |
| 1604 | 1613 | if( P("apply") ){ |
| 1605 | 1614 | Blob ctrl; |
| 1606 | 1615 | char *zNow; |
| 1607 | 1616 | int nChng = 0; |
| @@ -1651,14 +1660,14 @@ | ||
| 1651 | 1660 | } |
| 1652 | 1661 | db_finalize(&q); |
| 1653 | 1662 | if( zCloseFlag[0] ){ |
| 1654 | 1663 | db_multi_exec("REPLACE INTO newtags VALUES('closed','+',NULL)"); |
| 1655 | 1664 | } |
| 1656 | - if( zNewTagFlag[0] ){ | |
| 1665 | + if( zNewTagFlag[0] && zNewTag[0] ){ | |
| 1657 | 1666 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag); |
| 1658 | 1667 | } |
| 1659 | - if( zNewBrFlag[0] ){ | |
| 1668 | + if( zNewBrFlag[0] && zNewBranch[0] ){ | |
| 1660 | 1669 | db_multi_exec( |
| 1661 | 1670 | "REPLACE INTO newtags " |
| 1662 | 1671 | " SELECT tagname, '-', NULL FROM tagxref, tag" |
| 1663 | 1672 | " WHERE tagxref.rid=%d AND tagtype==2" |
| 1664 | 1673 | " AND tagname GLOB 'sym-*'" |
| 1665 | 1674 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -67,11 +67,11 @@ | |
| 67 | zDate = db_text(0, |
| 68 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 69 | rid |
| 70 | ); |
| 71 | /* 01234567890123 */ |
| 72 | printf("%-13s %s %s\n", zUuidName, zUuid, zDate ? zDate : ""); |
| 73 | free(zUuid); |
| 74 | free(zDate); |
| 75 | } |
| 76 | if( zUuid && showComment ){ |
| 77 | zComment = db_text(0, |
| @@ -88,11 +88,11 @@ | |
| 88 | const char *zUuid = db_column_text(&q, 0); |
| 89 | zDate = db_text("", |
| 90 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 91 | db_column_int(&q, 1) |
| 92 | ); |
| 93 | printf("parent: %s %s\n", zUuid, zDate); |
| 94 | free(zDate); |
| 95 | } |
| 96 | db_finalize(&q); |
| 97 | db_prepare(&q, "SELECT uuid, cid FROM plink JOIN blob ON cid=rid " |
| 98 | " WHERE pid=%d", rid); |
| @@ -100,22 +100,22 @@ | |
| 100 | const char *zUuid = db_column_text(&q, 0); |
| 101 | zDate = db_text("", |
| 102 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 103 | db_column_int(&q, 1) |
| 104 | ); |
| 105 | printf("child: %s %s\n", zUuid, zDate); |
| 106 | free(zDate); |
| 107 | } |
| 108 | db_finalize(&q); |
| 109 | } |
| 110 | zTags = info_tags_of_checkin(rid, 0); |
| 111 | if( zTags && zTags[0] ){ |
| 112 | printf("tags: %s\n", zTags); |
| 113 | } |
| 114 | free(zTags); |
| 115 | if( zComment ){ |
| 116 | printf("comment: "); |
| 117 | comment_print(zComment, 14, 79); |
| 118 | free(zComment); |
| 119 | } |
| 120 | } |
| 121 | |
| @@ -141,33 +141,33 @@ | |
| 141 | } |
| 142 | if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){ |
| 143 | db_open_config(0); |
| 144 | db_record_repository_filename(g.argv[2]); |
| 145 | db_open_repository(g.argv[2]); |
| 146 | printf("project-name: %s\n", db_get("project-name", "<unnamed>")); |
| 147 | printf("project-code: %s\n", db_get("project-code", "<none>")); |
| 148 | printf("server-code: %s\n", db_get("server-code", "<none>")); |
| 149 | return; |
| 150 | } |
| 151 | db_must_be_within_tree(); |
| 152 | if( g.argc==2 ){ |
| 153 | int vid; |
| 154 | /* 012345678901234 */ |
| 155 | db_record_repository_filename(0); |
| 156 | printf("project-name: %s\n", db_get("project-name", "<unnamed>")); |
| 157 | printf("repository: %s\n", db_lget("repository", "")); |
| 158 | printf("local-root: %s\n", g.zLocalRoot); |
| 159 | #if defined(_WIN32) |
| 160 | if( g.zHome ){ |
| 161 | printf("user-home: %s\n", g.zHome); |
| 162 | } |
| 163 | #endif |
| 164 | printf("project-code: %s\n", db_get("project-code", "")); |
| 165 | printf("server-code: %s\n", db_get("server-code", "")); |
| 166 | vid = db_lget_int("checkout", 0); |
| 167 | if( vid==0 ){ |
| 168 | printf("checkout: nil\n"); |
| 169 | }else{ |
| 170 | show_common_info(vid, "checkout:", 1, 1); |
| 171 | } |
| 172 | }else{ |
| 173 | int rid; |
| @@ -368,11 +368,11 @@ | |
| 368 | zParent = db_text(0, |
| 369 | "SELECT uuid FROM plink, blob" |
| 370 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 371 | rid |
| 372 | ); |
| 373 | isLeaf = !db_exists("SELECT 1 FROM plink WHERE pid=%d", rid); |
| 374 | db_prepare(&q, |
| 375 | "SELECT uuid, datetime(mtime, 'localtime'), user, comment," |
| 376 | " datetime(omtime, 'localtime')" |
| 377 | " FROM blob, event" |
| 378 | " WHERE blob.rid=%d" |
| @@ -800,10 +800,14 @@ | |
| 800 | @ part of check-in |
| 801 | hyperlink_to_uuid(zVers); |
| 802 | @ - %w(zCom) by |
| 803 | hyperlink_to_user(zUser,zDate," on"); |
| 804 | hyperlink_to_date(zDate,"."); |
| 805 | cnt++; |
| 806 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 807 | blob_append(pDownloadName, zName, -1); |
| 808 | } |
| 809 | } |
| @@ -945,16 +949,20 @@ | |
| 945 | */ |
| 946 | void diff_page(void){ |
| 947 | int v1, v2; |
| 948 | int isPatch; |
| 949 | Blob c1, c2, diff, *pOut; |
| 950 | |
| 951 | login_check_credentials(); |
| 952 | if( !g.okRead ){ login_needed(); return; } |
| 953 | v1 = name_to_rid_www("v1"); |
| 954 | v2 = name_to_rid_www("v2"); |
| 955 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 956 | isPatch = P("patch")!=0; |
| 957 | if( isPatch ){ |
| 958 | pOut = cgi_output_blob(); |
| 959 | cgi_set_content_type("text/plain"); |
| 960 | }else{ |
| @@ -968,15 +976,16 @@ | |
| 968 | blob_reset(&c2); |
| 969 | if( !isPatch ){ |
| 970 | style_header("Diff"); |
| 971 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 972 | g.zTop, P("v1"), P("v2")); |
| 973 | @ <h2>Differences From:</h2> |
| 974 | @ <blockquote><p> |
| 975 | object_description(v1, 1, 0); |
| 976 | @ </p></blockquote> |
| 977 | @ <h2>To:</h2> |
| 978 | @ <blockquote><p> |
| 979 | object_description(v2, 1, 0); |
| 980 | @ </p></blockquote> |
| 981 | @ <hr /> |
| 982 | @ <blockquote><pre> |
| @@ -1579,29 +1588,29 @@ | |
| 1579 | } |
| 1580 | zNewComment = PD("c",zComment); |
| 1581 | zUser = db_text(0, "SELECT coalesce(euser,user)" |
| 1582 | " FROM event WHERE objid=%d", rid); |
| 1583 | if( zUser==0 ) fossil_redirect_home(); |
| 1584 | zNewUser = PD("u",zUser); |
| 1585 | zDate = db_text(0, "SELECT datetime(mtime)" |
| 1586 | " FROM event WHERE objid=%d", rid); |
| 1587 | if( zDate==0 ) fossil_redirect_home(); |
| 1588 | zNewDate = PD("dt",zDate); |
| 1589 | zColor = db_text("", "SELECT bgcolor" |
| 1590 | " FROM event WHERE objid=%d", rid); |
| 1591 | zNewColor = PD("clr",zColor); |
| 1592 | if( fossil_strcmp(zNewColor,"##")==0 ){ |
| 1593 | zNewColor = P("clrcust"); |
| 1594 | } |
| 1595 | fPropagateColor = db_int(0, "SELECT tagtype FROM tagxref" |
| 1596 | " WHERE rid=%d AND tagid=%d", |
| 1597 | rid, TAG_BGCOLOR)==2; |
| 1598 | fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor; |
| 1599 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1600 | zNewTag = PD("tagname",""); |
| 1601 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 1602 | zNewBranch = PD("brname",""); |
| 1603 | zCloseFlag = P("close") ? " checked" : ""; |
| 1604 | if( P("apply") ){ |
| 1605 | Blob ctrl; |
| 1606 | char *zNow; |
| 1607 | int nChng = 0; |
| @@ -1651,14 +1660,14 @@ | |
| 1651 | } |
| 1652 | db_finalize(&q); |
| 1653 | if( zCloseFlag[0] ){ |
| 1654 | db_multi_exec("REPLACE INTO newtags VALUES('closed','+',NULL)"); |
| 1655 | } |
| 1656 | if( zNewTagFlag[0] ){ |
| 1657 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag); |
| 1658 | } |
| 1659 | if( zNewBrFlag[0] ){ |
| 1660 | db_multi_exec( |
| 1661 | "REPLACE INTO newtags " |
| 1662 | " SELECT tagname, '-', NULL FROM tagxref, tag" |
| 1663 | " WHERE tagxref.rid=%d AND tagtype==2" |
| 1664 | " AND tagname GLOB 'sym-*'" |
| 1665 |
| --- src/info.c | |
| +++ src/info.c | |
| @@ -67,11 +67,11 @@ | |
| 67 | zDate = db_text(0, |
| 68 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 69 | rid |
| 70 | ); |
| 71 | /* 01234567890123 */ |
| 72 | fossil_print("%-13s %s %s\n", zUuidName, zUuid, zDate ? zDate : ""); |
| 73 | free(zUuid); |
| 74 | free(zDate); |
| 75 | } |
| 76 | if( zUuid && showComment ){ |
| 77 | zComment = db_text(0, |
| @@ -88,11 +88,11 @@ | |
| 88 | const char *zUuid = db_column_text(&q, 0); |
| 89 | zDate = db_text("", |
| 90 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 91 | db_column_int(&q, 1) |
| 92 | ); |
| 93 | fossil_print("parent: %s %s\n", zUuid, zDate); |
| 94 | free(zDate); |
| 95 | } |
| 96 | db_finalize(&q); |
| 97 | db_prepare(&q, "SELECT uuid, cid FROM plink JOIN blob ON cid=rid " |
| 98 | " WHERE pid=%d", rid); |
| @@ -100,22 +100,22 @@ | |
| 100 | const char *zUuid = db_column_text(&q, 0); |
| 101 | zDate = db_text("", |
| 102 | "SELECT datetime(mtime) || ' UTC' FROM event WHERE objid=%d", |
| 103 | db_column_int(&q, 1) |
| 104 | ); |
| 105 | fossil_print("child: %s %s\n", zUuid, zDate); |
| 106 | free(zDate); |
| 107 | } |
| 108 | db_finalize(&q); |
| 109 | } |
| 110 | zTags = info_tags_of_checkin(rid, 0); |
| 111 | if( zTags && zTags[0] ){ |
| 112 | fossil_print("tags: %s\n", zTags); |
| 113 | } |
| 114 | free(zTags); |
| 115 | if( zComment ){ |
| 116 | fossil_print("comment: "); |
| 117 | comment_print(zComment, 14, 79); |
| 118 | free(zComment); |
| 119 | } |
| 120 | } |
| 121 | |
| @@ -141,33 +141,33 @@ | |
| 141 | } |
| 142 | if( g.argc==3 && (fsize = file_size(g.argv[2]))>0 && (fsize&0x1ff)==0 ){ |
| 143 | db_open_config(0); |
| 144 | db_record_repository_filename(g.argv[2]); |
| 145 | db_open_repository(g.argv[2]); |
| 146 | fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); |
| 147 | fossil_print("project-code: %s\n", db_get("project-code", "<none>")); |
| 148 | fossil_print("server-code: %s\n", db_get("server-code", "<none>")); |
| 149 | return; |
| 150 | } |
| 151 | db_must_be_within_tree(); |
| 152 | if( g.argc==2 ){ |
| 153 | int vid; |
| 154 | /* 012345678901234 */ |
| 155 | db_record_repository_filename(0); |
| 156 | fossil_print("project-name: %s\n", db_get("project-name", "<unnamed>")); |
| 157 | fossil_print("repository: %s\n", db_lget("repository", "")); |
| 158 | fossil_print("local-root: %s\n", g.zLocalRoot); |
| 159 | #if defined(_WIN32) |
| 160 | if( g.zHome ){ |
| 161 | fossil_print("user-home: %s\n", g.zHome); |
| 162 | } |
| 163 | #endif |
| 164 | fossil_print("project-code: %s\n", db_get("project-code", "")); |
| 165 | fossil_print("server-code: %s\n", db_get("server-code", "")); |
| 166 | vid = db_lget_int("checkout", 0); |
| 167 | if( vid==0 ){ |
| 168 | fossil_print("checkout: nil\n"); |
| 169 | }else{ |
| 170 | show_common_info(vid, "checkout:", 1, 1); |
| 171 | } |
| 172 | }else{ |
| 173 | int rid; |
| @@ -368,11 +368,11 @@ | |
| 368 | zParent = db_text(0, |
| 369 | "SELECT uuid FROM plink, blob" |
| 370 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 371 | rid |
| 372 | ); |
| 373 | isLeaf = is_a_leaf(rid); |
| 374 | db_prepare(&q, |
| 375 | "SELECT uuid, datetime(mtime, 'localtime'), user, comment," |
| 376 | " datetime(omtime, 'localtime')" |
| 377 | " FROM blob, event" |
| 378 | " WHERE blob.rid=%d" |
| @@ -800,10 +800,14 @@ | |
| 800 | @ part of check-in |
| 801 | hyperlink_to_uuid(zVers); |
| 802 | @ - %w(zCom) by |
| 803 | hyperlink_to_user(zUser,zDate," on"); |
| 804 | hyperlink_to_date(zDate,"."); |
| 805 | if( g.okHistory ){ |
| 806 | @ <a href="%s(g.zTop)/annotate?checkin=%S(zVers)&filename=%T(zName)"> |
| 807 | @ [annotate]</a> |
| 808 | } |
| 809 | cnt++; |
| 810 | if( pDownloadName && blob_size(pDownloadName)==0 ){ |
| 811 | blob_append(pDownloadName, zName, -1); |
| 812 | } |
| 813 | } |
| @@ -945,16 +949,20 @@ | |
| 949 | */ |
| 950 | void diff_page(void){ |
| 951 | int v1, v2; |
| 952 | int isPatch; |
| 953 | Blob c1, c2, diff, *pOut; |
| 954 | char *zV1; |
| 955 | char *zV2; |
| 956 | |
| 957 | login_check_credentials(); |
| 958 | if( !g.okRead ){ login_needed(); return; } |
| 959 | v1 = name_to_rid_www("v1"); |
| 960 | v2 = name_to_rid_www("v2"); |
| 961 | if( v1==0 || v2==0 ) fossil_redirect_home(); |
| 962 | zV1 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v1); |
| 963 | zV2 = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", v2); |
| 964 | isPatch = P("patch")!=0; |
| 965 | if( isPatch ){ |
| 966 | pOut = cgi_output_blob(); |
| 967 | cgi_set_content_type("text/plain"); |
| 968 | }else{ |
| @@ -968,15 +976,16 @@ | |
| 976 | blob_reset(&c2); |
| 977 | if( !isPatch ){ |
| 978 | style_header("Diff"); |
| 979 | style_submenu_element("Patch", "Patch", "%s/fdiff?v1=%T&v2=%T&patch", |
| 980 | g.zTop, P("v1"), P("v2")); |
| 981 | @ <h2>Differences From |
| 982 | @ Artifact <a href="%s(g.zTop)/artifact/%S(zV1)">[%S(zV1)]</a>:</h2> |
| 983 | @ <blockquote><p> |
| 984 | object_description(v1, 1, 0); |
| 985 | @ </p></blockquote> |
| 986 | @ <h2>To Artifact <a href="%s(g.zTop)/artifact/%S(zV2)">[%S(zV2)]</a>:</h2> |
| 987 | @ <blockquote><p> |
| 988 | object_description(v2, 1, 0); |
| 989 | @ </p></blockquote> |
| 990 | @ <hr /> |
| 991 | @ <blockquote><pre> |
| @@ -1579,29 +1588,29 @@ | |
| 1588 | } |
| 1589 | zNewComment = PD("c",zComment); |
| 1590 | zUser = db_text(0, "SELECT coalesce(euser,user)" |
| 1591 | " FROM event WHERE objid=%d", rid); |
| 1592 | if( zUser==0 ) fossil_redirect_home(); |
| 1593 | zNewUser = PDT("u",zUser); |
| 1594 | zDate = db_text(0, "SELECT datetime(mtime)" |
| 1595 | " FROM event WHERE objid=%d", rid); |
| 1596 | if( zDate==0 ) fossil_redirect_home(); |
| 1597 | zNewDate = PDT("dt",zDate); |
| 1598 | zColor = db_text("", "SELECT bgcolor" |
| 1599 | " FROM event WHERE objid=%d", rid); |
| 1600 | zNewColor = PDT("clr",zColor); |
| 1601 | if( fossil_strcmp(zNewColor,"##")==0 ){ |
| 1602 | zNewColor = PT("clrcust"); |
| 1603 | } |
| 1604 | fPropagateColor = db_int(0, "SELECT tagtype FROM tagxref" |
| 1605 | " WHERE rid=%d AND tagid=%d", |
| 1606 | rid, TAG_BGCOLOR)==2; |
| 1607 | fNewPropagateColor = P("clr")!=0 ? P("pclr")!=0 : fPropagateColor; |
| 1608 | zNewTagFlag = P("newtag") ? " checked" : ""; |
| 1609 | zNewTag = PDT("tagname",""); |
| 1610 | zNewBrFlag = P("newbr") ? " checked" : ""; |
| 1611 | zNewBranch = PDT("brname",""); |
| 1612 | zCloseFlag = P("close") ? " checked" : ""; |
| 1613 | if( P("apply") ){ |
| 1614 | Blob ctrl; |
| 1615 | char *zNow; |
| 1616 | int nChng = 0; |
| @@ -1651,14 +1660,14 @@ | |
| 1660 | } |
| 1661 | db_finalize(&q); |
| 1662 | if( zCloseFlag[0] ){ |
| 1663 | db_multi_exec("REPLACE INTO newtags VALUES('closed','+',NULL)"); |
| 1664 | } |
| 1665 | if( zNewTagFlag[0] && zNewTag[0] ){ |
| 1666 | db_multi_exec("REPLACE INTO newtags VALUES('sym-%q','+',NULL)", zNewTag); |
| 1667 | } |
| 1668 | if( zNewBrFlag[0] && zNewBranch[0] ){ |
| 1669 | db_multi_exec( |
| 1670 | "REPLACE INTO newtags " |
| 1671 | " SELECT tagname, '-', NULL FROM tagxref, tag" |
| 1672 | " WHERE tagxref.rid=%d AND tagtype==2" |
| 1673 | " AND tagname GLOB 'sym-*'" |
| 1674 |
+51
-3
| --- src/leaf.c | ||
| +++ src/leaf.c | ||
| @@ -23,10 +23,59 @@ | ||
| 23 | 23 | */ |
| 24 | 24 | #include "config.h" |
| 25 | 25 | #include "leaf.h" |
| 26 | 26 | #include <assert.h> |
| 27 | 27 | |
| 28 | + | |
| 29 | +/* | |
| 30 | +** Return true if the check-in with RID=rid is a leaf. | |
| 31 | +** | |
| 32 | +** A leaf has no children in the same branch. | |
| 33 | +*/ | |
| 34 | +int is_a_leaf(int rid){ | |
| 35 | + int rc; | |
| 36 | + static const char zSql[] = | |
| 37 | + @ SELECT 1 FROM plink | |
| 38 | + @ WHERE pid=%d | |
| 39 | + @ AND coalesce((SELECT value FROM tagxref | |
| 40 | + @ WHERE tagid=%d AND rid=plink.pid), 'trunk') | |
| 41 | + @ =coalesce((SELECT value FROM tagxref | |
| 42 | + @ WHERE tagid=%d AND rid=plink.cid), 'trunk') | |
| 43 | + ; | |
| 44 | + rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); | |
| 45 | + return rc==0; | |
| 46 | +} | |
| 47 | + | |
| 48 | +/* | |
| 49 | +** Count the number of primary non-branch children for the given check-in. | |
| 50 | +** | |
| 51 | +** A primary child is one where the parent is the primary parent, not | |
| 52 | +** a merge parent. A "leaf" is a node that has zero children of any | |
| 53 | +** kind. This routine counts only primary children. | |
| 54 | +** | |
| 55 | +** A non-branch child is one which is on the same branch as the parent. | |
| 56 | +*/ | |
| 57 | +int count_nonbranch_children(int pid){ | |
| 58 | + int nNonBranch = 0; | |
| 59 | + static Stmt q; | |
| 60 | + static const char zSql[] = | |
| 61 | + @ SELECT count(*) FROM plink | |
| 62 | + @ WHERE pid=:pid AND isprim | |
| 63 | + @ AND coalesce((SELECT value FROM tagxref | |
| 64 | + @ WHERE tagid=%d AND rid=plink.pid), 'trunk') | |
| 65 | + @ =coalesce((SELECT value FROM tagxref | |
| 66 | + @ WHERE tagid=%d AND rid=plink.cid), 'trunk') | |
| 67 | + ; | |
| 68 | + db_static_prepare(&q, zSql, TAG_BRANCH, TAG_BRANCH); | |
| 69 | + db_bind_int(&q, ":pid", pid); | |
| 70 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 71 | + nNonBranch = db_column_int(&q, 0); | |
| 72 | + } | |
| 73 | + db_reset(&q); | |
| 74 | + return nNonBranch; | |
| 75 | +} | |
| 76 | + | |
| 28 | 77 | |
| 29 | 78 | /* |
| 30 | 79 | ** Recompute the entire LEAF table. |
| 31 | 80 | ** |
| 32 | 81 | ** This can be expensive (5 seconds or so) for a really large repository. |
| @@ -40,12 +89,11 @@ | ||
| 40 | 89 | " EXCEPT" |
| 41 | 90 | " SELECT pid FROM plink" |
| 42 | 91 | " WHERE coalesce((SELECT value FROM tagxref" |
| 43 | 92 | " WHERE tagid=%d AND rid=plink.pid),'trunk')" |
| 44 | 93 | " == coalesce((SELECT value FROM tagxref" |
| 45 | - " WHERE tagid=%d AND rid=plink.cid),'trunk')" | |
| 46 | - " AND isprim", | |
| 94 | + " WHERE tagid=%d AND rid=plink.cid),'trunk')", | |
| 47 | 95 | TAG_BRANCH, TAG_BRANCH |
| 48 | 96 | ); |
| 49 | 97 | } |
| 50 | 98 | |
| 51 | 99 | /* |
| @@ -63,11 +111,11 @@ | ||
| 63 | 111 | static Stmt removeLeaf; |
| 64 | 112 | int rc; |
| 65 | 113 | |
| 66 | 114 | db_static_prepare(&checkIfLeaf, |
| 67 | 115 | "SELECT 1 FROM plink" |
| 68 | - " WHERE pid=:rid AND isprim" | |
| 116 | + " WHERE pid=:rid" | |
| 69 | 117 | " AND coalesce((SELECT value FROM tagxref" |
| 70 | 118 | " WHERE tagid=%d AND rid=:rid),'trunk')" |
| 71 | 119 | " == coalesce((SELECT value FROM tagxref" |
| 72 | 120 | " WHERE tagid=%d AND rid=plink.cid),'trunk');", |
| 73 | 121 | TAG_BRANCH, TAG_BRANCH |
| 74 | 122 |
| --- src/leaf.c | |
| +++ src/leaf.c | |
| @@ -23,10 +23,59 @@ | |
| 23 | */ |
| 24 | #include "config.h" |
| 25 | #include "leaf.h" |
| 26 | #include <assert.h> |
| 27 | |
| 28 | |
| 29 | /* |
| 30 | ** Recompute the entire LEAF table. |
| 31 | ** |
| 32 | ** This can be expensive (5 seconds or so) for a really large repository. |
| @@ -40,12 +89,11 @@ | |
| 40 | " EXCEPT" |
| 41 | " SELECT pid FROM plink" |
| 42 | " WHERE coalesce((SELECT value FROM tagxref" |
| 43 | " WHERE tagid=%d AND rid=plink.pid),'trunk')" |
| 44 | " == coalesce((SELECT value FROM tagxref" |
| 45 | " WHERE tagid=%d AND rid=plink.cid),'trunk')" |
| 46 | " AND isprim", |
| 47 | TAG_BRANCH, TAG_BRANCH |
| 48 | ); |
| 49 | } |
| 50 | |
| 51 | /* |
| @@ -63,11 +111,11 @@ | |
| 63 | static Stmt removeLeaf; |
| 64 | int rc; |
| 65 | |
| 66 | db_static_prepare(&checkIfLeaf, |
| 67 | "SELECT 1 FROM plink" |
| 68 | " WHERE pid=:rid AND isprim" |
| 69 | " AND coalesce((SELECT value FROM tagxref" |
| 70 | " WHERE tagid=%d AND rid=:rid),'trunk')" |
| 71 | " == coalesce((SELECT value FROM tagxref" |
| 72 | " WHERE tagid=%d AND rid=plink.cid),'trunk');", |
| 73 | TAG_BRANCH, TAG_BRANCH |
| 74 |
| --- src/leaf.c | |
| +++ src/leaf.c | |
| @@ -23,10 +23,59 @@ | |
| 23 | */ |
| 24 | #include "config.h" |
| 25 | #include "leaf.h" |
| 26 | #include <assert.h> |
| 27 | |
| 28 | |
| 29 | /* |
| 30 | ** Return true if the check-in with RID=rid is a leaf. |
| 31 | ** |
| 32 | ** A leaf has no children in the same branch. |
| 33 | */ |
| 34 | int is_a_leaf(int rid){ |
| 35 | int rc; |
| 36 | static const char zSql[] = |
| 37 | @ SELECT 1 FROM plink |
| 38 | @ WHERE pid=%d |
| 39 | @ AND coalesce((SELECT value FROM tagxref |
| 40 | @ WHERE tagid=%d AND rid=plink.pid), 'trunk') |
| 41 | @ =coalesce((SELECT value FROM tagxref |
| 42 | @ WHERE tagid=%d AND rid=plink.cid), 'trunk') |
| 43 | ; |
| 44 | rc = db_int(0, zSql, rid, TAG_BRANCH, TAG_BRANCH); |
| 45 | return rc==0; |
| 46 | } |
| 47 | |
| 48 | /* |
| 49 | ** Count the number of primary non-branch children for the given check-in. |
| 50 | ** |
| 51 | ** A primary child is one where the parent is the primary parent, not |
| 52 | ** a merge parent. A "leaf" is a node that has zero children of any |
| 53 | ** kind. This routine counts only primary children. |
| 54 | ** |
| 55 | ** A non-branch child is one which is on the same branch as the parent. |
| 56 | */ |
| 57 | int count_nonbranch_children(int pid){ |
| 58 | int nNonBranch = 0; |
| 59 | static Stmt q; |
| 60 | static const char zSql[] = |
| 61 | @ SELECT count(*) FROM plink |
| 62 | @ WHERE pid=:pid AND isprim |
| 63 | @ AND coalesce((SELECT value FROM tagxref |
| 64 | @ WHERE tagid=%d AND rid=plink.pid), 'trunk') |
| 65 | @ =coalesce((SELECT value FROM tagxref |
| 66 | @ WHERE tagid=%d AND rid=plink.cid), 'trunk') |
| 67 | ; |
| 68 | db_static_prepare(&q, zSql, TAG_BRANCH, TAG_BRANCH); |
| 69 | db_bind_int(&q, ":pid", pid); |
| 70 | if( db_step(&q)==SQLITE_ROW ){ |
| 71 | nNonBranch = db_column_int(&q, 0); |
| 72 | } |
| 73 | db_reset(&q); |
| 74 | return nNonBranch; |
| 75 | } |
| 76 | |
| 77 | |
| 78 | /* |
| 79 | ** Recompute the entire LEAF table. |
| 80 | ** |
| 81 | ** This can be expensive (5 seconds or so) for a really large repository. |
| @@ -40,12 +89,11 @@ | |
| 89 | " EXCEPT" |
| 90 | " SELECT pid FROM plink" |
| 91 | " WHERE coalesce((SELECT value FROM tagxref" |
| 92 | " WHERE tagid=%d AND rid=plink.pid),'trunk')" |
| 93 | " == coalesce((SELECT value FROM tagxref" |
| 94 | " WHERE tagid=%d AND rid=plink.cid),'trunk')", |
| 95 | TAG_BRANCH, TAG_BRANCH |
| 96 | ); |
| 97 | } |
| 98 | |
| 99 | /* |
| @@ -63,11 +111,11 @@ | |
| 111 | static Stmt removeLeaf; |
| 112 | int rc; |
| 113 | |
| 114 | db_static_prepare(&checkIfLeaf, |
| 115 | "SELECT 1 FROM plink" |
| 116 | " WHERE pid=:rid" |
| 117 | " AND coalesce((SELECT value FROM tagxref" |
| 118 | " WHERE tagid=%d AND rid=:rid),'trunk')" |
| 119 | " == coalesce((SELECT value FROM tagxref" |
| 120 | " WHERE tagid=%d AND rid=plink.cid),'trunk');", |
| 121 | TAG_BRANCH, TAG_BRANCH |
| 122 |
+26
-16
| --- src/login.c | ||
| +++ src/login.c | ||
| @@ -546,11 +546,12 @@ | ||
| 546 | 546 | ** |
| 547 | 547 | */ |
| 548 | 548 | void login_check_credentials(void){ |
| 549 | 549 | int uid = 0; /* User id */ |
| 550 | 550 | const char *zCookie; /* Text of the login cookie */ |
| 551 | - char *zRemoteAddr; /* IP address of the requestor */ | |
| 551 | + const char *zIpAddr; /* Raw IP address of the requestor */ | |
| 552 | + char *zRemoteAddr; /* Abbreviated IP address of the requestor */ | |
| 552 | 553 | const char *zCap = 0; /* Capability string */ |
| 553 | 554 | |
| 554 | 555 | /* Only run this check once. */ |
| 555 | 556 | if( g.userUid!=0 ) return; |
| 556 | 557 | |
| @@ -559,12 +560,12 @@ | ||
| 559 | 560 | ** then there is no need to check user credentials. |
| 560 | 561 | ** |
| 561 | 562 | ** This feature allows the "fossil ui" command to give the user |
| 562 | 563 | ** full access rights without having to log in. |
| 563 | 564 | */ |
| 564 | - zRemoteAddr = ipPrefix(PD("REMOTE_ADDR","nil")); | |
| 565 | - if( strcmp(zRemoteAddr, "127.0.0.1")==0 | |
| 565 | + zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil")); | |
| 566 | + if( strcmp(zIpAddr, "127.0.0.1")==0 | |
| 566 | 567 | && g.useLocalauth |
| 567 | 568 | && db_get_int("localauth",0)==0 |
| 568 | 569 | && P("HTTPS")==0 |
| 569 | 570 | ){ |
| 570 | 571 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| @@ -622,10 +623,11 @@ | ||
| 622 | 623 | ** are part of a login-group. |
| 623 | 624 | */ |
| 624 | 625 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 625 | 626 | if( uid==0 && login_transfer_credentials(zUser,zArg,zHash,zRemoteAddr) ){ |
| 626 | 627 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 628 | + if( uid ) record_login_attempt(zUser, zIpAddr, 1); | |
| 627 | 629 | } |
| 628 | 630 | } |
| 629 | 631 | sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash); |
| 630 | 632 | } |
| 631 | 633 | |
| @@ -678,11 +680,11 @@ | ||
| 678 | 680 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 679 | 681 | g.zLogin = 0; |
| 680 | 682 | } |
| 681 | 683 | |
| 682 | 684 | /* Set the capabilities */ |
| 683 | - login_set_capabilities(zCap); | |
| 685 | + login_set_capabilities(zCap, 0); | |
| 684 | 686 | login_set_anon_nobody_capabilities(); |
| 685 | 687 | } |
| 686 | 688 | |
| 687 | 689 | /* |
| 688 | 690 | ** Memory of settings |
| @@ -696,26 +698,32 @@ | ||
| 696 | 698 | void login_set_anon_nobody_capabilities(void){ |
| 697 | 699 | if( g.zLogin && login_anon_once ){ |
| 698 | 700 | const char *zCap; |
| 699 | 701 | /* All logged-in users inherit privileges from "nobody" */ |
| 700 | 702 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 701 | - login_set_capabilities(zCap); | |
| 703 | + login_set_capabilities(zCap, 0); | |
| 702 | 704 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 703 | 705 | /* All logged-in users inherit privileges from "anonymous" */ |
| 704 | 706 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 705 | - login_set_capabilities(zCap); | |
| 707 | + login_set_capabilities(zCap, 0); | |
| 706 | 708 | } |
| 707 | 709 | login_anon_once = 0; |
| 708 | 710 | } |
| 709 | 711 | } |
| 710 | 712 | |
| 713 | +/* | |
| 714 | +** Flags passed into the 2nd argument of login_set_capabilities(). | |
| 715 | +*/ | |
| 716 | +#if INTERFACE | |
| 717 | +#define LOGIN_IGNORE_U 0x01 /* Ignore "u" */ | |
| 718 | +#define LOGIN_IGNORE_V 0x01 /* Ignore "v" */ | |
| 719 | +#endif | |
| 720 | + | |
| 711 | 721 | /* |
| 712 | 722 | ** Set the global capability flags based on a capability string. |
| 713 | 723 | */ |
| 714 | -void login_set_capabilities(const char *zCap){ | |
| 715 | - static char *zDev = 0; | |
| 716 | - static char *zUser = 0; | |
| 724 | +void login_set_capabilities(const char *zCap, unsigned flags){ | |
| 717 | 725 | int i; |
| 718 | 726 | for(i=0; zCap[i]; i++){ |
| 719 | 727 | switch( zCap[i] ){ |
| 720 | 728 | case 's': g.okSetup = 1; /* Fall thru into Admin */ |
| 721 | 729 | case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip = |
| @@ -749,23 +757,25 @@ | ||
| 749 | 757 | case 'x': g.okPrivate = 1; break; |
| 750 | 758 | |
| 751 | 759 | /* The "u" privileges is a little different. It recursively |
| 752 | 760 | ** inherits all privileges of the user named "reader" */ |
| 753 | 761 | case 'u': { |
| 754 | - if( zUser==0 ){ | |
| 762 | + if( (flags & LOGIN_IGNORE_U)==0 ){ | |
| 763 | + const char *zUser; | |
| 755 | 764 | zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); |
| 756 | - login_set_capabilities(zUser); | |
| 765 | + login_set_capabilities(zUser, flags | LOGIN_IGNORE_U); | |
| 757 | 766 | } |
| 758 | 767 | break; |
| 759 | 768 | } |
| 760 | 769 | |
| 761 | 770 | /* The "v" privileges is a little different. It recursively |
| 762 | 771 | ** inherits all privileges of the user named "developer" */ |
| 763 | 772 | case 'v': { |
| 764 | - if( zDev==0 ){ | |
| 773 | + if( (flags & LOGIN_IGNORE_V)==0 ){ | |
| 774 | + const char *zDev; | |
| 765 | 775 | zDev = db_text("", "SELECT cap FROM user WHERE login='developer'"); |
| 766 | - login_set_capabilities(zDev); | |
| 776 | + login_set_capabilities(zDev, flags | LOGIN_IGNORE_V); | |
| 767 | 777 | } |
| 768 | 778 | break; |
| 769 | 779 | } |
| 770 | 780 | } |
| 771 | 781 | } |
| @@ -857,11 +867,11 @@ | ||
| 857 | 867 | } |
| 858 | 868 | if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; |
| 859 | 869 | g.zLogin = fossil_strdup(zUser); |
| 860 | 870 | |
| 861 | 871 | /* Set the capabilities */ |
| 862 | - login_set_capabilities(zCap); | |
| 872 | + login_set_capabilities(zCap, 0); | |
| 863 | 873 | login_anon_once = 1; |
| 864 | 874 | login_set_anon_nobody_capabilities(); |
| 865 | 875 | } |
| 866 | 876 | |
| 867 | 877 | /* |
| @@ -1255,12 +1265,12 @@ | ||
| 1255 | 1265 | db_multi_exec("DETACH other"); |
| 1256 | 1266 | |
| 1257 | 1267 | /* Propagate the changes to all other members of the login-group */ |
| 1258 | 1268 | zSql = mprintf( |
| 1259 | 1269 | "BEGIN;" |
| 1260 | - "REPLACE INTO config(name, value) VALUES('peer-name-%q', %Q);" | |
| 1261 | - "REPLACE INTO config(name, value) VALUES('peer-repo-%q', %Q);" | |
| 1270 | + "REPLACE INTO config(name,value,mtime) VALUES('peer-name-%q',%Q,now());" | |
| 1271 | + "REPLACE INTO config(name,value,mtime) VALUES('peer-repo-%q',%Q,now());" | |
| 1262 | 1272 | "COMMIT;", |
| 1263 | 1273 | zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo |
| 1264 | 1274 | ); |
| 1265 | 1275 | login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); |
| 1266 | 1276 | fossil_free(zSql); |
| 1267 | 1277 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -546,11 +546,12 @@ | |
| 546 | ** |
| 547 | */ |
| 548 | void login_check_credentials(void){ |
| 549 | int uid = 0; /* User id */ |
| 550 | const char *zCookie; /* Text of the login cookie */ |
| 551 | char *zRemoteAddr; /* IP address of the requestor */ |
| 552 | const char *zCap = 0; /* Capability string */ |
| 553 | |
| 554 | /* Only run this check once. */ |
| 555 | if( g.userUid!=0 ) return; |
| 556 | |
| @@ -559,12 +560,12 @@ | |
| 559 | ** then there is no need to check user credentials. |
| 560 | ** |
| 561 | ** This feature allows the "fossil ui" command to give the user |
| 562 | ** full access rights without having to log in. |
| 563 | */ |
| 564 | zRemoteAddr = ipPrefix(PD("REMOTE_ADDR","nil")); |
| 565 | if( strcmp(zRemoteAddr, "127.0.0.1")==0 |
| 566 | && g.useLocalauth |
| 567 | && db_get_int("localauth",0)==0 |
| 568 | && P("HTTPS")==0 |
| 569 | ){ |
| 570 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| @@ -622,10 +623,11 @@ | |
| 622 | ** are part of a login-group. |
| 623 | */ |
| 624 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 625 | if( uid==0 && login_transfer_credentials(zUser,zArg,zHash,zRemoteAddr) ){ |
| 626 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 627 | } |
| 628 | } |
| 629 | sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash); |
| 630 | } |
| 631 | |
| @@ -678,11 +680,11 @@ | |
| 678 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 679 | g.zLogin = 0; |
| 680 | } |
| 681 | |
| 682 | /* Set the capabilities */ |
| 683 | login_set_capabilities(zCap); |
| 684 | login_set_anon_nobody_capabilities(); |
| 685 | } |
| 686 | |
| 687 | /* |
| 688 | ** Memory of settings |
| @@ -696,26 +698,32 @@ | |
| 696 | void login_set_anon_nobody_capabilities(void){ |
| 697 | if( g.zLogin && login_anon_once ){ |
| 698 | const char *zCap; |
| 699 | /* All logged-in users inherit privileges from "nobody" */ |
| 700 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 701 | login_set_capabilities(zCap); |
| 702 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 703 | /* All logged-in users inherit privileges from "anonymous" */ |
| 704 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 705 | login_set_capabilities(zCap); |
| 706 | } |
| 707 | login_anon_once = 0; |
| 708 | } |
| 709 | } |
| 710 | |
| 711 | /* |
| 712 | ** Set the global capability flags based on a capability string. |
| 713 | */ |
| 714 | void login_set_capabilities(const char *zCap){ |
| 715 | static char *zDev = 0; |
| 716 | static char *zUser = 0; |
| 717 | int i; |
| 718 | for(i=0; zCap[i]; i++){ |
| 719 | switch( zCap[i] ){ |
| 720 | case 's': g.okSetup = 1; /* Fall thru into Admin */ |
| 721 | case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip = |
| @@ -749,23 +757,25 @@ | |
| 749 | case 'x': g.okPrivate = 1; break; |
| 750 | |
| 751 | /* The "u" privileges is a little different. It recursively |
| 752 | ** inherits all privileges of the user named "reader" */ |
| 753 | case 'u': { |
| 754 | if( zUser==0 ){ |
| 755 | zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); |
| 756 | login_set_capabilities(zUser); |
| 757 | } |
| 758 | break; |
| 759 | } |
| 760 | |
| 761 | /* The "v" privileges is a little different. It recursively |
| 762 | ** inherits all privileges of the user named "developer" */ |
| 763 | case 'v': { |
| 764 | if( zDev==0 ){ |
| 765 | zDev = db_text("", "SELECT cap FROM user WHERE login='developer'"); |
| 766 | login_set_capabilities(zDev); |
| 767 | } |
| 768 | break; |
| 769 | } |
| 770 | } |
| 771 | } |
| @@ -857,11 +867,11 @@ | |
| 857 | } |
| 858 | if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; |
| 859 | g.zLogin = fossil_strdup(zUser); |
| 860 | |
| 861 | /* Set the capabilities */ |
| 862 | login_set_capabilities(zCap); |
| 863 | login_anon_once = 1; |
| 864 | login_set_anon_nobody_capabilities(); |
| 865 | } |
| 866 | |
| 867 | /* |
| @@ -1255,12 +1265,12 @@ | |
| 1255 | db_multi_exec("DETACH other"); |
| 1256 | |
| 1257 | /* Propagate the changes to all other members of the login-group */ |
| 1258 | zSql = mprintf( |
| 1259 | "BEGIN;" |
| 1260 | "REPLACE INTO config(name, value) VALUES('peer-name-%q', %Q);" |
| 1261 | "REPLACE INTO config(name, value) VALUES('peer-repo-%q', %Q);" |
| 1262 | "COMMIT;", |
| 1263 | zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo |
| 1264 | ); |
| 1265 | login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); |
| 1266 | fossil_free(zSql); |
| 1267 |
| --- src/login.c | |
| +++ src/login.c | |
| @@ -546,11 +546,12 @@ | |
| 546 | ** |
| 547 | */ |
| 548 | void login_check_credentials(void){ |
| 549 | int uid = 0; /* User id */ |
| 550 | const char *zCookie; /* Text of the login cookie */ |
| 551 | const char *zIpAddr; /* Raw IP address of the requestor */ |
| 552 | char *zRemoteAddr; /* Abbreviated IP address of the requestor */ |
| 553 | const char *zCap = 0; /* Capability string */ |
| 554 | |
| 555 | /* Only run this check once. */ |
| 556 | if( g.userUid!=0 ) return; |
| 557 | |
| @@ -559,12 +560,12 @@ | |
| 560 | ** then there is no need to check user credentials. |
| 561 | ** |
| 562 | ** This feature allows the "fossil ui" command to give the user |
| 563 | ** full access rights without having to log in. |
| 564 | */ |
| 565 | zRemoteAddr = ipPrefix(zIpAddr = PD("REMOTE_ADDR","nil")); |
| 566 | if( strcmp(zIpAddr, "127.0.0.1")==0 |
| 567 | && g.useLocalauth |
| 568 | && db_get_int("localauth",0)==0 |
| 569 | && P("HTTPS")==0 |
| 570 | ){ |
| 571 | uid = db_int(0, "SELECT uid FROM user WHERE cap LIKE '%%s%%'"); |
| @@ -622,10 +623,11 @@ | |
| 623 | ** are part of a login-group. |
| 624 | */ |
| 625 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 626 | if( uid==0 && login_transfer_credentials(zUser,zArg,zHash,zRemoteAddr) ){ |
| 627 | uid = login_find_user(zUser, zHash, zRemoteAddr); |
| 628 | if( uid ) record_login_attempt(zUser, zIpAddr, 1); |
| 629 | } |
| 630 | } |
| 631 | sqlite3_snprintf(sizeof(g.zCsrfToken), g.zCsrfToken, "%.10s", zHash); |
| 632 | } |
| 633 | |
| @@ -678,11 +680,11 @@ | |
| 680 | if( fossil_strcmp(g.zLogin,"nobody")==0 ){ |
| 681 | g.zLogin = 0; |
| 682 | } |
| 683 | |
| 684 | /* Set the capabilities */ |
| 685 | login_set_capabilities(zCap, 0); |
| 686 | login_set_anon_nobody_capabilities(); |
| 687 | } |
| 688 | |
| 689 | /* |
| 690 | ** Memory of settings |
| @@ -696,26 +698,32 @@ | |
| 698 | void login_set_anon_nobody_capabilities(void){ |
| 699 | if( g.zLogin && login_anon_once ){ |
| 700 | const char *zCap; |
| 701 | /* All logged-in users inherit privileges from "nobody" */ |
| 702 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'nobody'"); |
| 703 | login_set_capabilities(zCap, 0); |
| 704 | if( fossil_strcmp(g.zLogin, "nobody")!=0 ){ |
| 705 | /* All logged-in users inherit privileges from "anonymous" */ |
| 706 | zCap = db_text("", "SELECT cap FROM user WHERE login = 'anonymous'"); |
| 707 | login_set_capabilities(zCap, 0); |
| 708 | } |
| 709 | login_anon_once = 0; |
| 710 | } |
| 711 | } |
| 712 | |
| 713 | /* |
| 714 | ** Flags passed into the 2nd argument of login_set_capabilities(). |
| 715 | */ |
| 716 | #if INTERFACE |
| 717 | #define LOGIN_IGNORE_U 0x01 /* Ignore "u" */ |
| 718 | #define LOGIN_IGNORE_V 0x01 /* Ignore "v" */ |
| 719 | #endif |
| 720 | |
| 721 | /* |
| 722 | ** Set the global capability flags based on a capability string. |
| 723 | */ |
| 724 | void login_set_capabilities(const char *zCap, unsigned flags){ |
| 725 | int i; |
| 726 | for(i=0; zCap[i]; i++){ |
| 727 | switch( zCap[i] ){ |
| 728 | case 's': g.okSetup = 1; /* Fall thru into Admin */ |
| 729 | case 'a': g.okAdmin = g.okRdTkt = g.okWrTkt = g.okZip = |
| @@ -749,23 +757,25 @@ | |
| 757 | case 'x': g.okPrivate = 1; break; |
| 758 | |
| 759 | /* The "u" privileges is a little different. It recursively |
| 760 | ** inherits all privileges of the user named "reader" */ |
| 761 | case 'u': { |
| 762 | if( (flags & LOGIN_IGNORE_U)==0 ){ |
| 763 | const char *zUser; |
| 764 | zUser = db_text("", "SELECT cap FROM user WHERE login='reader'"); |
| 765 | login_set_capabilities(zUser, flags | LOGIN_IGNORE_U); |
| 766 | } |
| 767 | break; |
| 768 | } |
| 769 | |
| 770 | /* The "v" privileges is a little different. It recursively |
| 771 | ** inherits all privileges of the user named "developer" */ |
| 772 | case 'v': { |
| 773 | if( (flags & LOGIN_IGNORE_V)==0 ){ |
| 774 | const char *zDev; |
| 775 | zDev = db_text("", "SELECT cap FROM user WHERE login='developer'"); |
| 776 | login_set_capabilities(zDev, flags | LOGIN_IGNORE_V); |
| 777 | } |
| 778 | break; |
| 779 | } |
| 780 | } |
| 781 | } |
| @@ -857,11 +867,11 @@ | |
| 867 | } |
| 868 | if( fossil_strcmp(zUser,"nobody")==0 ) zUser = 0; |
| 869 | g.zLogin = fossil_strdup(zUser); |
| 870 | |
| 871 | /* Set the capabilities */ |
| 872 | login_set_capabilities(zCap, 0); |
| 873 | login_anon_once = 1; |
| 874 | login_set_anon_nobody_capabilities(); |
| 875 | } |
| 876 | |
| 877 | /* |
| @@ -1255,12 +1265,12 @@ | |
| 1265 | db_multi_exec("DETACH other"); |
| 1266 | |
| 1267 | /* Propagate the changes to all other members of the login-group */ |
| 1268 | zSql = mprintf( |
| 1269 | "BEGIN;" |
| 1270 | "REPLACE INTO config(name,value,mtime) VALUES('peer-name-%q',%Q,now());" |
| 1271 | "REPLACE INTO config(name,value,mtime) VALUES('peer-repo-%q',%Q,now());" |
| 1272 | "COMMIT;", |
| 1273 | zSelfProjCode, zSelfLabel, zSelfProjCode, zSelfRepo |
| 1274 | ); |
| 1275 | login_group_sql(zSql, "<li> ", "</li>", pzErrMsg); |
| 1276 | fossil_free(zSql); |
| 1277 |
+42
-35
| --- src/main.c | ||
| +++ src/main.c | ||
| @@ -227,23 +227,24 @@ | ||
| 227 | 227 | */ |
| 228 | 228 | int main(int argc, char **argv){ |
| 229 | 229 | const char *zCmdName = "unknown"; |
| 230 | 230 | int idx; |
| 231 | 231 | int rc; |
| 232 | + int i; | |
| 232 | 233 | |
| 233 | 234 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 234 | 235 | g.now = time(0); |
| 235 | 236 | g.argc = argc; |
| 236 | 237 | g.argv = argv; |
| 238 | + for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]); | |
| 237 | 239 | if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){ |
| 238 | 240 | zCmdName = "cgi"; |
| 239 | 241 | }else if( argc<2 ){ |
| 240 | - fprintf(stderr, "Usage: %s COMMAND ...\n" | |
| 241 | - "\"%s help\" for a list of available commands\n" | |
| 242 | - "\"%s help COMMAND\" for specific details\n", | |
| 243 | - argv[0], argv[0], argv[0]); | |
| 244 | - fossil_exit(1); | |
| 242 | + fossil_fatal("Usage: %s COMMAND ...\n" | |
| 243 | + "\"%s help\" for a list of available commands\n" | |
| 244 | + "\"%s help COMMAND\" for specific details\n", | |
| 245 | + argv[0], argv[0], argv[0]); | |
| 245 | 246 | }else{ |
| 246 | 247 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 247 | 248 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 248 | 249 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 249 | 250 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| @@ -264,14 +265,13 @@ | ||
| 264 | 265 | } |
| 265 | 266 | zCmdName = g.argv[1]; |
| 266 | 267 | } |
| 267 | 268 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 268 | 269 | if( rc==1 ){ |
| 269 | - fprintf(stderr,"%s: unknown command: %s\n" | |
| 270 | - "%s: use \"help\" for more information\n", | |
| 270 | + fossil_fatal("%s: unknown command: %s\n" | |
| 271 | + "%s: use \"help\" for more information\n", | |
| 271 | 272 | argv[0], zCmdName, argv[0]); |
| 272 | - fossil_exit(1); | |
| 273 | 273 | }else if( rc==2 ){ |
| 274 | 274 | int i, n; |
| 275 | 275 | Blob couldbe; |
| 276 | 276 | blob_zero(&couldbe); |
| 277 | 277 | n = strlen(zCmdName); |
| @@ -278,15 +278,14 @@ | ||
| 278 | 278 | for(i=0; i<count(aCommand); i++){ |
| 279 | 279 | if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){ |
| 280 | 280 | blob_appendf(&couldbe, " %s", aCommand[i].zName); |
| 281 | 281 | } |
| 282 | 282 | } |
| 283 | - fprintf(stderr,"%s: ambiguous command prefix: %s\n" | |
| 284 | - "%s: could be any of:%s\n" | |
| 285 | - "%s: use \"help\" for more information\n", | |
| 286 | - argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]); | |
| 287 | - fossil_exit(1); | |
| 283 | + fossil_fatal("%s: ambiguous command prefix: %s\n" | |
| 284 | + "%s: could be any of:%s\n" | |
| 285 | + "%s: use \"help\" for more information\n", | |
| 286 | + argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]); | |
| 288 | 287 | } |
| 289 | 288 | aCommand[idx].xFunc(); |
| 290 | 289 | fossil_exit(0); |
| 291 | 290 | /*NOT_REACHED*/ |
| 292 | 291 | return 0; |
| @@ -333,11 +332,12 @@ | ||
| 333 | 332 | if( g.cgiOutput && once ){ |
| 334 | 333 | once = 0; |
| 335 | 334 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 336 | 335 | cgi_reply(); |
| 337 | 336 | }else{ |
| 338 | - fprintf(stderr, "%s: %s\n", fossil_nameofexe(), z); | |
| 337 | + char *zOut = mprintf("%s: %s\n", fossil_nameofexe(), z); | |
| 338 | + fossil_puts(zOut, 1); | |
| 339 | 339 | } |
| 340 | 340 | db_force_rollback(); |
| 341 | 341 | fossil_exit(1); |
| 342 | 342 | } |
| 343 | 343 | void fossil_fatal(const char *zFormat, ...){ |
| @@ -350,11 +350,12 @@ | ||
| 350 | 350 | if( g.cgiOutput ){ |
| 351 | 351 | g.cgiOutput = 0; |
| 352 | 352 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 353 | 353 | cgi_reply(); |
| 354 | 354 | }else{ |
| 355 | - fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); | |
| 355 | + char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); | |
| 356 | + fossil_puts(zOut, 1); | |
| 356 | 357 | } |
| 357 | 358 | db_force_rollback(); |
| 358 | 359 | fossil_exit(1); |
| 359 | 360 | } |
| 360 | 361 | |
| @@ -378,11 +379,12 @@ | ||
| 378 | 379 | if( g.cgiOutput ){ |
| 379 | 380 | g.cgiOutput = 0; |
| 380 | 381 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 381 | 382 | cgi_reply(); |
| 382 | 383 | }else{ |
| 383 | - fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); | |
| 384 | + char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); | |
| 385 | + fossil_puts(zOut, 1); | |
| 384 | 386 | } |
| 385 | 387 | db_force_rollback(); |
| 386 | 388 | fossil_exit(1); |
| 387 | 389 | } |
| 388 | 390 | |
| @@ -395,19 +397,21 @@ | ||
| 395 | 397 | z = vmprintf(zFormat, ap); |
| 396 | 398 | va_end(ap); |
| 397 | 399 | if( g.cgiOutput ){ |
| 398 | 400 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 399 | 401 | }else{ |
| 400 | - fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); | |
| 402 | + char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); | |
| 403 | + fossil_puts(zOut, 1); | |
| 404 | + free(zOut); | |
| 401 | 405 | } |
| 402 | 406 | } |
| 403 | 407 | |
| 404 | 408 | /* |
| 405 | 409 | ** Malloc and free routines that cannot fail |
| 406 | 410 | */ |
| 407 | 411 | void *fossil_malloc(size_t n){ |
| 408 | - void *p = malloc(n); | |
| 412 | + void *p = malloc(n==0 ? 1 : n); | |
| 409 | 413 | if( p==0 ) fossil_panic("out of memory"); |
| 410 | 414 | return p; |
| 411 | 415 | } |
| 412 | 416 | void fossil_free(void *p){ |
| 413 | 417 | free(p); |
| @@ -426,11 +430,13 @@ | ||
| 426 | 430 | #if defined(_WIN32) |
| 427 | 431 | /* On windows, we have to put double-quotes around the entire command. |
| 428 | 432 | ** Who knows why - this is just the way windows works. |
| 429 | 433 | */ |
| 430 | 434 | char *zNewCmd = mprintf("\"%s\"", zOrigCmd); |
| 431 | - rc = system(zNewCmd); | |
| 435 | + char *zMbcs = fossil_utf8_to_mbcs(zNewCmd); | |
| 436 | + rc = system(zMbcs); | |
| 437 | + fossil_mbcs_free(zMbcs); | |
| 432 | 438 | free(zNewCmd); |
| 433 | 439 | #else |
| 434 | 440 | /* On unix, evaluate the command directly. |
| 435 | 441 | */ |
| 436 | 442 | rc = system(zOrigCmd); |
| @@ -507,12 +513,11 @@ | ||
| 507 | 513 | |
| 508 | 514 | /* |
| 509 | 515 | ** Print a usage comment and quit |
| 510 | 516 | */ |
| 511 | 517 | void usage(const char *zFormat){ |
| 512 | - fprintf(stderr, "Usage: %s %s %s\n", fossil_nameofexe(), g.argv[1], zFormat); | |
| 513 | - fossil_exit(1); | |
| 518 | + fossil_fatal("Usage: %s %s %s\n", fossil_nameofexe(), g.argv[1], zFormat); | |
| 514 | 519 | } |
| 515 | 520 | |
| 516 | 521 | /* |
| 517 | 522 | ** Remove n elements from g.argv beginning with the i-th element. |
| 518 | 523 | */ |
| @@ -601,14 +606,14 @@ | ||
| 601 | 606 | if( nCol==0 ) nCol = 1; |
| 602 | 607 | nRow = (nWord + nCol - 1)/nCol; |
| 603 | 608 | for(i=0; i<nRow; i++){ |
| 604 | 609 | const char *zSpacer = ""; |
| 605 | 610 | for(j=i; j<nWord; j+=nRow){ |
| 606 | - printf("%s%-*s", zSpacer, mxLen, azWord[j]); | |
| 611 | + fossil_print("%s%-*s", zSpacer, mxLen, azWord[j]); | |
| 607 | 612 | zSpacer = " "; |
| 608 | 613 | } |
| 609 | - printf("\n"); | |
| 614 | + fossil_print("\n"); | |
| 610 | 615 | } |
| 611 | 616 | } |
| 612 | 617 | |
| 613 | 618 | /* |
| 614 | 619 | ** List of commands starting with zPrefix, or all commands if zPrefix is NULL. |
| @@ -650,11 +655,12 @@ | ||
| 650 | 655 | ** Usage: %fossil version |
| 651 | 656 | ** |
| 652 | 657 | ** Print the source code version number for the fossil executable. |
| 653 | 658 | */ |
| 654 | 659 | void version_cmd(void){ |
| 655 | - printf("This is fossil version " MANIFEST_VERSION " " MANIFEST_DATE " UTC\n"); | |
| 660 | + fossil_print("This is fossil version " | |
| 661 | + MANIFEST_VERSION " " MANIFEST_DATE " UTC\n"); | |
| 656 | 662 | } |
| 657 | 663 | |
| 658 | 664 | |
| 659 | 665 | /* |
| 660 | 666 | ** COMMAND: help |
| @@ -665,12 +671,12 @@ | ||
| 665 | 671 | */ |
| 666 | 672 | void help_cmd(void){ |
| 667 | 673 | int rc, idx; |
| 668 | 674 | const char *z; |
| 669 | 675 | if( g.argc<3 ){ |
| 670 | - printf("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", | |
| 671 | - fossil_nameofexe()); | |
| 676 | + fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", | |
| 677 | + fossil_nameofexe()); | |
| 672 | 678 | cmd_cmd_list(0); |
| 673 | 679 | version_cmd(); |
| 674 | 680 | return; |
| 675 | 681 | } |
| 676 | 682 | rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); |
| @@ -689,11 +695,11 @@ | ||
| 689 | 695 | fossil_fatal("no help available for the %s command", |
| 690 | 696 | aCommand[idx].zName); |
| 691 | 697 | } |
| 692 | 698 | while( *z ){ |
| 693 | 699 | if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ |
| 694 | - printf("%s", fossil_nameofexe()); | |
| 700 | + fossil_print("%s", fossil_nameofexe()); | |
| 695 | 701 | z += 7; |
| 696 | 702 | }else{ |
| 697 | 703 | putchar(*z); |
| 698 | 704 | z++; |
| 699 | 705 | } |
| @@ -806,11 +812,11 @@ | ||
| 806 | 812 | zHost = PD("HTTP_HOST",""); |
| 807 | 813 | zMode = PD("HTTPS","off"); |
| 808 | 814 | zCur = PD("SCRIPT_NAME","/"); |
| 809 | 815 | i = strlen(zCur); |
| 810 | 816 | while( i>0 && zCur[i-1]=='/' ) i--; |
| 811 | - if( strcmp(zMode,"on")==0 ){ | |
| 817 | + if( fossil_stricmp(zMode,"on")==0 ){ | |
| 812 | 818 | g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur); |
| 813 | 819 | g.zTop = &g.zBaseURL[8+strlen(zHost)]; |
| 814 | 820 | }else{ |
| 815 | 821 | g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); |
| 816 | 822 | g.zTop = &g.zBaseURL[7+strlen(zHost)]; |
| @@ -901,19 +907,19 @@ | ||
| 901 | 907 | const char *zOldScript = PD("SCRIPT_NAME", ""); |
| 902 | 908 | char *zNewScript; |
| 903 | 909 | int j, k; |
| 904 | 910 | i64 szFile; |
| 905 | 911 | |
| 906 | - i = 1; | |
| 912 | + i = zPathInfo[0]!=0; | |
| 907 | 913 | while( 1 ){ |
| 908 | 914 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 909 | 915 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 910 | 916 | |
| 911 | 917 | /* To avoid mischief, make sure the repository basename contains no |
| 912 | 918 | ** characters other than alphanumerics, "-", "/", and "_". |
| 913 | 919 | */ |
| 914 | - for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){ | |
| 920 | + for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ | |
| 915 | 921 | if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){ |
| 916 | 922 | zRepo[j] = '_'; |
| 917 | 923 | } |
| 918 | 924 | } |
| 919 | 925 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| @@ -1001,10 +1007,11 @@ | ||
| 1001 | 1007 | zAltRepo[jj] = 0; |
| 1002 | 1008 | zAltRepo += jj+1; |
| 1003 | 1009 | }else{ |
| 1004 | 1010 | zUser = "nobody"; |
| 1005 | 1011 | } |
| 1012 | + if( g.zLogin==0 ) zUser = "nobody"; | |
| 1006 | 1013 | if( zAltRepo[0]!='/' ){ |
| 1007 | 1014 | zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); |
| 1008 | 1015 | file_simplify_name(zAltRepo, -1); |
| 1009 | 1016 | } |
| 1010 | 1017 | db_close(1); |
| @@ -1280,12 +1287,12 @@ | ||
| 1280 | 1287 | if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ |
| 1281 | 1288 | fossil_fatal("no repository specified"); |
| 1282 | 1289 | } |
| 1283 | 1290 | g.fullHttpReply = 1; |
| 1284 | 1291 | if( g.argc==6 ){ |
| 1285 | - g.httpIn = fopen(g.argv[3], "rb"); | |
| 1286 | - g.httpOut = fopen(g.argv[4], "wb"); | |
| 1292 | + g.httpIn = fossil_fopen(g.argv[3], "rb"); | |
| 1293 | + g.httpOut = fossil_fopen(g.argv[4], "wb"); | |
| 1287 | 1294 | zIpAddr = g.argv[5]; |
| 1288 | 1295 | }else{ |
| 1289 | 1296 | g.httpIn = stdin; |
| 1290 | 1297 | g.httpOut = stdout; |
| 1291 | 1298 | zIpAddr = 0; |
| @@ -1301,11 +1308,11 @@ | ||
| 1301 | 1308 | ** |
| 1302 | 1309 | ** COMMAND: test-http |
| 1303 | 1310 | ** Works like the http command but gives setup permission to all users. |
| 1304 | 1311 | */ |
| 1305 | 1312 | void cmd_test_http(void){ |
| 1306 | - login_set_capabilities("s"); | |
| 1313 | + login_set_capabilities("s", 0); | |
| 1307 | 1314 | g.httpIn = stdin; |
| 1308 | 1315 | g.httpOut = stdout; |
| 1309 | 1316 | find_server_repository(0); |
| 1310 | 1317 | g.cgiOutput = 1; |
| 1311 | 1318 | g.fullHttpReply = 1; |
| @@ -1326,11 +1333,11 @@ | ||
| 1326 | 1333 | int bExists; |
| 1327 | 1334 | while( zPath && zPath[0] ){ |
| 1328 | 1335 | while( zPath[0]==':' ) zPath++; |
| 1329 | 1336 | for(i=0; zPath[i] && zPath[i]!=':'; i++){} |
| 1330 | 1337 | zFull = mprintf("%.*s/%s", i, zPath, zBinary); |
| 1331 | - bExists = access(zFull, X_OK); | |
| 1338 | + bExists = file_access(zFull, X_OK); | |
| 1332 | 1339 | free(zFull); |
| 1333 | 1340 | if( bExists==0 ) return 1; |
| 1334 | 1341 | zPath += i; |
| 1335 | 1342 | } |
| 1336 | 1343 | return 0; |
| @@ -1454,8 +1461,8 @@ | ||
| 1454 | 1461 | ** wildcard expansion behavior of the host shell can be investigated. |
| 1455 | 1462 | */ |
| 1456 | 1463 | void test_echo_cmd(void){ |
| 1457 | 1464 | int i; |
| 1458 | 1465 | for(i=0; i<g.argc; i++){ |
| 1459 | - printf("argv[%d] = [%s]\n", i, g.argv[i]); | |
| 1466 | + fossil_print("argv[%d] = [%s]\n", i, g.argv[i]); | |
| 1460 | 1467 | } |
| 1461 | 1468 | } |
| 1462 | 1469 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -227,23 +227,24 @@ | |
| 227 | */ |
| 228 | int main(int argc, char **argv){ |
| 229 | const char *zCmdName = "unknown"; |
| 230 | int idx; |
| 231 | int rc; |
| 232 | |
| 233 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 234 | g.now = time(0); |
| 235 | g.argc = argc; |
| 236 | g.argv = argv; |
| 237 | if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){ |
| 238 | zCmdName = "cgi"; |
| 239 | }else if( argc<2 ){ |
| 240 | fprintf(stderr, "Usage: %s COMMAND ...\n" |
| 241 | "\"%s help\" for a list of available commands\n" |
| 242 | "\"%s help COMMAND\" for specific details\n", |
| 243 | argv[0], argv[0], argv[0]); |
| 244 | fossil_exit(1); |
| 245 | }else{ |
| 246 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 247 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 248 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 249 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| @@ -264,14 +265,13 @@ | |
| 264 | } |
| 265 | zCmdName = g.argv[1]; |
| 266 | } |
| 267 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 268 | if( rc==1 ){ |
| 269 | fprintf(stderr,"%s: unknown command: %s\n" |
| 270 | "%s: use \"help\" for more information\n", |
| 271 | argv[0], zCmdName, argv[0]); |
| 272 | fossil_exit(1); |
| 273 | }else if( rc==2 ){ |
| 274 | int i, n; |
| 275 | Blob couldbe; |
| 276 | blob_zero(&couldbe); |
| 277 | n = strlen(zCmdName); |
| @@ -278,15 +278,14 @@ | |
| 278 | for(i=0; i<count(aCommand); i++){ |
| 279 | if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){ |
| 280 | blob_appendf(&couldbe, " %s", aCommand[i].zName); |
| 281 | } |
| 282 | } |
| 283 | fprintf(stderr,"%s: ambiguous command prefix: %s\n" |
| 284 | "%s: could be any of:%s\n" |
| 285 | "%s: use \"help\" for more information\n", |
| 286 | argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]); |
| 287 | fossil_exit(1); |
| 288 | } |
| 289 | aCommand[idx].xFunc(); |
| 290 | fossil_exit(0); |
| 291 | /*NOT_REACHED*/ |
| 292 | return 0; |
| @@ -333,11 +332,12 @@ | |
| 333 | if( g.cgiOutput && once ){ |
| 334 | once = 0; |
| 335 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 336 | cgi_reply(); |
| 337 | }else{ |
| 338 | fprintf(stderr, "%s: %s\n", fossil_nameofexe(), z); |
| 339 | } |
| 340 | db_force_rollback(); |
| 341 | fossil_exit(1); |
| 342 | } |
| 343 | void fossil_fatal(const char *zFormat, ...){ |
| @@ -350,11 +350,12 @@ | |
| 350 | if( g.cgiOutput ){ |
| 351 | g.cgiOutput = 0; |
| 352 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 353 | cgi_reply(); |
| 354 | }else{ |
| 355 | fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); |
| 356 | } |
| 357 | db_force_rollback(); |
| 358 | fossil_exit(1); |
| 359 | } |
| 360 | |
| @@ -378,11 +379,12 @@ | |
| 378 | if( g.cgiOutput ){ |
| 379 | g.cgiOutput = 0; |
| 380 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 381 | cgi_reply(); |
| 382 | }else{ |
| 383 | fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); |
| 384 | } |
| 385 | db_force_rollback(); |
| 386 | fossil_exit(1); |
| 387 | } |
| 388 | |
| @@ -395,19 +397,21 @@ | |
| 395 | z = vmprintf(zFormat, ap); |
| 396 | va_end(ap); |
| 397 | if( g.cgiOutput ){ |
| 398 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 399 | }else{ |
| 400 | fprintf(stderr, "\r%s: %s\n", fossil_nameofexe(), z); |
| 401 | } |
| 402 | } |
| 403 | |
| 404 | /* |
| 405 | ** Malloc and free routines that cannot fail |
| 406 | */ |
| 407 | void *fossil_malloc(size_t n){ |
| 408 | void *p = malloc(n); |
| 409 | if( p==0 ) fossil_panic("out of memory"); |
| 410 | return p; |
| 411 | } |
| 412 | void fossil_free(void *p){ |
| 413 | free(p); |
| @@ -426,11 +430,13 @@ | |
| 426 | #if defined(_WIN32) |
| 427 | /* On windows, we have to put double-quotes around the entire command. |
| 428 | ** Who knows why - this is just the way windows works. |
| 429 | */ |
| 430 | char *zNewCmd = mprintf("\"%s\"", zOrigCmd); |
| 431 | rc = system(zNewCmd); |
| 432 | free(zNewCmd); |
| 433 | #else |
| 434 | /* On unix, evaluate the command directly. |
| 435 | */ |
| 436 | rc = system(zOrigCmd); |
| @@ -507,12 +513,11 @@ | |
| 507 | |
| 508 | /* |
| 509 | ** Print a usage comment and quit |
| 510 | */ |
| 511 | void usage(const char *zFormat){ |
| 512 | fprintf(stderr, "Usage: %s %s %s\n", fossil_nameofexe(), g.argv[1], zFormat); |
| 513 | fossil_exit(1); |
| 514 | } |
| 515 | |
| 516 | /* |
| 517 | ** Remove n elements from g.argv beginning with the i-th element. |
| 518 | */ |
| @@ -601,14 +606,14 @@ | |
| 601 | if( nCol==0 ) nCol = 1; |
| 602 | nRow = (nWord + nCol - 1)/nCol; |
| 603 | for(i=0; i<nRow; i++){ |
| 604 | const char *zSpacer = ""; |
| 605 | for(j=i; j<nWord; j+=nRow){ |
| 606 | printf("%s%-*s", zSpacer, mxLen, azWord[j]); |
| 607 | zSpacer = " "; |
| 608 | } |
| 609 | printf("\n"); |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | /* |
| 614 | ** List of commands starting with zPrefix, or all commands if zPrefix is NULL. |
| @@ -650,11 +655,12 @@ | |
| 650 | ** Usage: %fossil version |
| 651 | ** |
| 652 | ** Print the source code version number for the fossil executable. |
| 653 | */ |
| 654 | void version_cmd(void){ |
| 655 | printf("This is fossil version " MANIFEST_VERSION " " MANIFEST_DATE " UTC\n"); |
| 656 | } |
| 657 | |
| 658 | |
| 659 | /* |
| 660 | ** COMMAND: help |
| @@ -665,12 +671,12 @@ | |
| 665 | */ |
| 666 | void help_cmd(void){ |
| 667 | int rc, idx; |
| 668 | const char *z; |
| 669 | if( g.argc<3 ){ |
| 670 | printf("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", |
| 671 | fossil_nameofexe()); |
| 672 | cmd_cmd_list(0); |
| 673 | version_cmd(); |
| 674 | return; |
| 675 | } |
| 676 | rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); |
| @@ -689,11 +695,11 @@ | |
| 689 | fossil_fatal("no help available for the %s command", |
| 690 | aCommand[idx].zName); |
| 691 | } |
| 692 | while( *z ){ |
| 693 | if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ |
| 694 | printf("%s", fossil_nameofexe()); |
| 695 | z += 7; |
| 696 | }else{ |
| 697 | putchar(*z); |
| 698 | z++; |
| 699 | } |
| @@ -806,11 +812,11 @@ | |
| 806 | zHost = PD("HTTP_HOST",""); |
| 807 | zMode = PD("HTTPS","off"); |
| 808 | zCur = PD("SCRIPT_NAME","/"); |
| 809 | i = strlen(zCur); |
| 810 | while( i>0 && zCur[i-1]=='/' ) i--; |
| 811 | if( strcmp(zMode,"on")==0 ){ |
| 812 | g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur); |
| 813 | g.zTop = &g.zBaseURL[8+strlen(zHost)]; |
| 814 | }else{ |
| 815 | g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); |
| 816 | g.zTop = &g.zBaseURL[7+strlen(zHost)]; |
| @@ -901,19 +907,19 @@ | |
| 901 | const char *zOldScript = PD("SCRIPT_NAME", ""); |
| 902 | char *zNewScript; |
| 903 | int j, k; |
| 904 | i64 szFile; |
| 905 | |
| 906 | i = 1; |
| 907 | while( 1 ){ |
| 908 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 909 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 910 | |
| 911 | /* To avoid mischief, make sure the repository basename contains no |
| 912 | ** characters other than alphanumerics, "-", "/", and "_". |
| 913 | */ |
| 914 | for(j=strlen(g.zRepositoryName)+1, k=0; k<i-1; j++, k++){ |
| 915 | if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){ |
| 916 | zRepo[j] = '_'; |
| 917 | } |
| 918 | } |
| 919 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| @@ -1001,10 +1007,11 @@ | |
| 1001 | zAltRepo[jj] = 0; |
| 1002 | zAltRepo += jj+1; |
| 1003 | }else{ |
| 1004 | zUser = "nobody"; |
| 1005 | } |
| 1006 | if( zAltRepo[0]!='/' ){ |
| 1007 | zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); |
| 1008 | file_simplify_name(zAltRepo, -1); |
| 1009 | } |
| 1010 | db_close(1); |
| @@ -1280,12 +1287,12 @@ | |
| 1280 | if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ |
| 1281 | fossil_fatal("no repository specified"); |
| 1282 | } |
| 1283 | g.fullHttpReply = 1; |
| 1284 | if( g.argc==6 ){ |
| 1285 | g.httpIn = fopen(g.argv[3], "rb"); |
| 1286 | g.httpOut = fopen(g.argv[4], "wb"); |
| 1287 | zIpAddr = g.argv[5]; |
| 1288 | }else{ |
| 1289 | g.httpIn = stdin; |
| 1290 | g.httpOut = stdout; |
| 1291 | zIpAddr = 0; |
| @@ -1301,11 +1308,11 @@ | |
| 1301 | ** |
| 1302 | ** COMMAND: test-http |
| 1303 | ** Works like the http command but gives setup permission to all users. |
| 1304 | */ |
| 1305 | void cmd_test_http(void){ |
| 1306 | login_set_capabilities("s"); |
| 1307 | g.httpIn = stdin; |
| 1308 | g.httpOut = stdout; |
| 1309 | find_server_repository(0); |
| 1310 | g.cgiOutput = 1; |
| 1311 | g.fullHttpReply = 1; |
| @@ -1326,11 +1333,11 @@ | |
| 1326 | int bExists; |
| 1327 | while( zPath && zPath[0] ){ |
| 1328 | while( zPath[0]==':' ) zPath++; |
| 1329 | for(i=0; zPath[i] && zPath[i]!=':'; i++){} |
| 1330 | zFull = mprintf("%.*s/%s", i, zPath, zBinary); |
| 1331 | bExists = access(zFull, X_OK); |
| 1332 | free(zFull); |
| 1333 | if( bExists==0 ) return 1; |
| 1334 | zPath += i; |
| 1335 | } |
| 1336 | return 0; |
| @@ -1454,8 +1461,8 @@ | |
| 1454 | ** wildcard expansion behavior of the host shell can be investigated. |
| 1455 | */ |
| 1456 | void test_echo_cmd(void){ |
| 1457 | int i; |
| 1458 | for(i=0; i<g.argc; i++){ |
| 1459 | printf("argv[%d] = [%s]\n", i, g.argv[i]); |
| 1460 | } |
| 1461 | } |
| 1462 |
| --- src/main.c | |
| +++ src/main.c | |
| @@ -227,23 +227,24 @@ | |
| 227 | */ |
| 228 | int main(int argc, char **argv){ |
| 229 | const char *zCmdName = "unknown"; |
| 230 | int idx; |
| 231 | int rc; |
| 232 | int i; |
| 233 | |
| 234 | sqlite3_config(SQLITE_CONFIG_LOG, fossil_sqlite_log, 0); |
| 235 | g.now = time(0); |
| 236 | g.argc = argc; |
| 237 | g.argv = argv; |
| 238 | for(i=0; i<argc; i++) g.argv[i] = fossil_mbcs_to_utf8(argv[i]); |
| 239 | if( getenv("GATEWAY_INTERFACE")!=0 && !find_option("nocgi", 0, 0)){ |
| 240 | zCmdName = "cgi"; |
| 241 | }else if( argc<2 ){ |
| 242 | fossil_fatal("Usage: %s COMMAND ...\n" |
| 243 | "\"%s help\" for a list of available commands\n" |
| 244 | "\"%s help COMMAND\" for specific details\n", |
| 245 | argv[0], argv[0], argv[0]); |
| 246 | }else{ |
| 247 | g.fQuiet = find_option("quiet", 0, 0)!=0; |
| 248 | g.fSqlTrace = find_option("sqltrace", 0, 0)!=0; |
| 249 | g.fSqlStats = find_option("sqlstats", 0, 0)!=0; |
| 250 | if( g.fSqlTrace ) g.fSqlStats = 1; |
| @@ -264,14 +265,13 @@ | |
| 265 | } |
| 266 | zCmdName = g.argv[1]; |
| 267 | } |
| 268 | rc = name_search(zCmdName, aCommand, count(aCommand), &idx); |
| 269 | if( rc==1 ){ |
| 270 | fossil_fatal("%s: unknown command: %s\n" |
| 271 | "%s: use \"help\" for more information\n", |
| 272 | argv[0], zCmdName, argv[0]); |
| 273 | }else if( rc==2 ){ |
| 274 | int i, n; |
| 275 | Blob couldbe; |
| 276 | blob_zero(&couldbe); |
| 277 | n = strlen(zCmdName); |
| @@ -278,15 +278,14 @@ | |
| 278 | for(i=0; i<count(aCommand); i++){ |
| 279 | if( memcmp(zCmdName, aCommand[i].zName, n)==0 ){ |
| 280 | blob_appendf(&couldbe, " %s", aCommand[i].zName); |
| 281 | } |
| 282 | } |
| 283 | fossil_fatal("%s: ambiguous command prefix: %s\n" |
| 284 | "%s: could be any of:%s\n" |
| 285 | "%s: use \"help\" for more information\n", |
| 286 | argv[0], zCmdName, argv[0], blob_str(&couldbe), argv[0]); |
| 287 | } |
| 288 | aCommand[idx].xFunc(); |
| 289 | fossil_exit(0); |
| 290 | /*NOT_REACHED*/ |
| 291 | return 0; |
| @@ -333,11 +332,12 @@ | |
| 332 | if( g.cgiOutput && once ){ |
| 333 | once = 0; |
| 334 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 335 | cgi_reply(); |
| 336 | }else{ |
| 337 | char *zOut = mprintf("%s: %s\n", fossil_nameofexe(), z); |
| 338 | fossil_puts(zOut, 1); |
| 339 | } |
| 340 | db_force_rollback(); |
| 341 | fossil_exit(1); |
| 342 | } |
| 343 | void fossil_fatal(const char *zFormat, ...){ |
| @@ -350,11 +350,12 @@ | |
| 350 | if( g.cgiOutput ){ |
| 351 | g.cgiOutput = 0; |
| 352 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 353 | cgi_reply(); |
| 354 | }else{ |
| 355 | char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); |
| 356 | fossil_puts(zOut, 1); |
| 357 | } |
| 358 | db_force_rollback(); |
| 359 | fossil_exit(1); |
| 360 | } |
| 361 | |
| @@ -378,11 +379,12 @@ | |
| 379 | if( g.cgiOutput ){ |
| 380 | g.cgiOutput = 0; |
| 381 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 382 | cgi_reply(); |
| 383 | }else{ |
| 384 | char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); |
| 385 | fossil_puts(zOut, 1); |
| 386 | } |
| 387 | db_force_rollback(); |
| 388 | fossil_exit(1); |
| 389 | } |
| 390 | |
| @@ -395,19 +397,21 @@ | |
| 397 | z = vmprintf(zFormat, ap); |
| 398 | va_end(ap); |
| 399 | if( g.cgiOutput ){ |
| 400 | cgi_printf("<p class=\"generalError\">%h</p>", z); |
| 401 | }else{ |
| 402 | char *zOut = mprintf("\r%s: %s\n", fossil_nameofexe(), z); |
| 403 | fossil_puts(zOut, 1); |
| 404 | free(zOut); |
| 405 | } |
| 406 | } |
| 407 | |
| 408 | /* |
| 409 | ** Malloc and free routines that cannot fail |
| 410 | */ |
| 411 | void *fossil_malloc(size_t n){ |
| 412 | void *p = malloc(n==0 ? 1 : n); |
| 413 | if( p==0 ) fossil_panic("out of memory"); |
| 414 | return p; |
| 415 | } |
| 416 | void fossil_free(void *p){ |
| 417 | free(p); |
| @@ -426,11 +430,13 @@ | |
| 430 | #if defined(_WIN32) |
| 431 | /* On windows, we have to put double-quotes around the entire command. |
| 432 | ** Who knows why - this is just the way windows works. |
| 433 | */ |
| 434 | char *zNewCmd = mprintf("\"%s\"", zOrigCmd); |
| 435 | char *zMbcs = fossil_utf8_to_mbcs(zNewCmd); |
| 436 | rc = system(zMbcs); |
| 437 | fossil_mbcs_free(zMbcs); |
| 438 | free(zNewCmd); |
| 439 | #else |
| 440 | /* On unix, evaluate the command directly. |
| 441 | */ |
| 442 | rc = system(zOrigCmd); |
| @@ -507,12 +513,11 @@ | |
| 513 | |
| 514 | /* |
| 515 | ** Print a usage comment and quit |
| 516 | */ |
| 517 | void usage(const char *zFormat){ |
| 518 | fossil_fatal("Usage: %s %s %s\n", fossil_nameofexe(), g.argv[1], zFormat); |
| 519 | } |
| 520 | |
| 521 | /* |
| 522 | ** Remove n elements from g.argv beginning with the i-th element. |
| 523 | */ |
| @@ -601,14 +606,14 @@ | |
| 606 | if( nCol==0 ) nCol = 1; |
| 607 | nRow = (nWord + nCol - 1)/nCol; |
| 608 | for(i=0; i<nRow; i++){ |
| 609 | const char *zSpacer = ""; |
| 610 | for(j=i; j<nWord; j+=nRow){ |
| 611 | fossil_print("%s%-*s", zSpacer, mxLen, azWord[j]); |
| 612 | zSpacer = " "; |
| 613 | } |
| 614 | fossil_print("\n"); |
| 615 | } |
| 616 | } |
| 617 | |
| 618 | /* |
| 619 | ** List of commands starting with zPrefix, or all commands if zPrefix is NULL. |
| @@ -650,11 +655,12 @@ | |
| 655 | ** Usage: %fossil version |
| 656 | ** |
| 657 | ** Print the source code version number for the fossil executable. |
| 658 | */ |
| 659 | void version_cmd(void){ |
| 660 | fossil_print("This is fossil version " |
| 661 | MANIFEST_VERSION " " MANIFEST_DATE " UTC\n"); |
| 662 | } |
| 663 | |
| 664 | |
| 665 | /* |
| 666 | ** COMMAND: help |
| @@ -665,12 +671,12 @@ | |
| 671 | */ |
| 672 | void help_cmd(void){ |
| 673 | int rc, idx; |
| 674 | const char *z; |
| 675 | if( g.argc<3 ){ |
| 676 | fossil_print("Usage: %s help COMMAND.\nAvailable COMMANDs:\n", |
| 677 | fossil_nameofexe()); |
| 678 | cmd_cmd_list(0); |
| 679 | version_cmd(); |
| 680 | return; |
| 681 | } |
| 682 | rc = name_search(g.argv[2], aCommand, count(aCommand), &idx); |
| @@ -689,11 +695,11 @@ | |
| 695 | fossil_fatal("no help available for the %s command", |
| 696 | aCommand[idx].zName); |
| 697 | } |
| 698 | while( *z ){ |
| 699 | if( *z=='%' && strncmp(z, "%fossil", 7)==0 ){ |
| 700 | fossil_print("%s", fossil_nameofexe()); |
| 701 | z += 7; |
| 702 | }else{ |
| 703 | putchar(*z); |
| 704 | z++; |
| 705 | } |
| @@ -806,11 +812,11 @@ | |
| 812 | zHost = PD("HTTP_HOST",""); |
| 813 | zMode = PD("HTTPS","off"); |
| 814 | zCur = PD("SCRIPT_NAME","/"); |
| 815 | i = strlen(zCur); |
| 816 | while( i>0 && zCur[i-1]=='/' ) i--; |
| 817 | if( fossil_stricmp(zMode,"on")==0 ){ |
| 818 | g.zBaseURL = mprintf("https://%s%.*s", zHost, i, zCur); |
| 819 | g.zTop = &g.zBaseURL[8+strlen(zHost)]; |
| 820 | }else{ |
| 821 | g.zBaseURL = mprintf("http://%s%.*s", zHost, i, zCur); |
| 822 | g.zTop = &g.zBaseURL[7+strlen(zHost)]; |
| @@ -901,19 +907,19 @@ | |
| 907 | const char *zOldScript = PD("SCRIPT_NAME", ""); |
| 908 | char *zNewScript; |
| 909 | int j, k; |
| 910 | i64 szFile; |
| 911 | |
| 912 | i = zPathInfo[0]!=0; |
| 913 | while( 1 ){ |
| 914 | while( zPathInfo[i] && zPathInfo[i]!='/' ){ i++; } |
| 915 | zRepo = zToFree = mprintf("%s%.*s.fossil",g.zRepositoryName,i,zPathInfo); |
| 916 | |
| 917 | /* To avoid mischief, make sure the repository basename contains no |
| 918 | ** characters other than alphanumerics, "-", "/", and "_". |
| 919 | */ |
| 920 | for(j=strlen(g.zRepositoryName)+1, k=0; zRepo[j] && k<i-1; j++, k++){ |
| 921 | if( !fossil_isalnum(zRepo[j]) && zRepo[j]!='-' && zRepo[j]!='/' ){ |
| 922 | zRepo[j] = '_'; |
| 923 | } |
| 924 | } |
| 925 | if( zRepo[0]=='/' && zRepo[1]=='/' ){ zRepo++; j--; } |
| @@ -1001,10 +1007,11 @@ | |
| 1007 | zAltRepo[jj] = 0; |
| 1008 | zAltRepo += jj+1; |
| 1009 | }else{ |
| 1010 | zUser = "nobody"; |
| 1011 | } |
| 1012 | if( g.zLogin==0 ) zUser = "nobody"; |
| 1013 | if( zAltRepo[0]!='/' ){ |
| 1014 | zAltRepo = mprintf("%s/../%s", g.zRepositoryName, zAltRepo); |
| 1015 | file_simplify_name(zAltRepo, -1); |
| 1016 | } |
| 1017 | db_close(1); |
| @@ -1280,12 +1287,12 @@ | |
| 1287 | if( g.argc!=2 && g.argc!=3 && g.argc!=6 ){ |
| 1288 | fossil_fatal("no repository specified"); |
| 1289 | } |
| 1290 | g.fullHttpReply = 1; |
| 1291 | if( g.argc==6 ){ |
| 1292 | g.httpIn = fossil_fopen(g.argv[3], "rb"); |
| 1293 | g.httpOut = fossil_fopen(g.argv[4], "wb"); |
| 1294 | zIpAddr = g.argv[5]; |
| 1295 | }else{ |
| 1296 | g.httpIn = stdin; |
| 1297 | g.httpOut = stdout; |
| 1298 | zIpAddr = 0; |
| @@ -1301,11 +1308,11 @@ | |
| 1308 | ** |
| 1309 | ** COMMAND: test-http |
| 1310 | ** Works like the http command but gives setup permission to all users. |
| 1311 | */ |
| 1312 | void cmd_test_http(void){ |
| 1313 | login_set_capabilities("s", 0); |
| 1314 | g.httpIn = stdin; |
| 1315 | g.httpOut = stdout; |
| 1316 | find_server_repository(0); |
| 1317 | g.cgiOutput = 1; |
| 1318 | g.fullHttpReply = 1; |
| @@ -1326,11 +1333,11 @@ | |
| 1333 | int bExists; |
| 1334 | while( zPath && zPath[0] ){ |
| 1335 | while( zPath[0]==':' ) zPath++; |
| 1336 | for(i=0; zPath[i] && zPath[i]!=':'; i++){} |
| 1337 | zFull = mprintf("%.*s/%s", i, zPath, zBinary); |
| 1338 | bExists = file_access(zFull, X_OK); |
| 1339 | free(zFull); |
| 1340 | if( bExists==0 ) return 1; |
| 1341 | zPath += i; |
| 1342 | } |
| 1343 | return 0; |
| @@ -1454,8 +1461,8 @@ | |
| 1461 | ** wildcard expansion behavior of the host shell can be investigated. |
| 1462 | */ |
| 1463 | void test_echo_cmd(void){ |
| 1464 | int i; |
| 1465 | for(i=0; i<g.argc; i++){ |
| 1466 | fossil_print("argv[%d] = [%s]\n", i, g.argv[i]); |
| 1467 | } |
| 1468 | } |
| 1469 |
+12
-2
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -38,10 +38,11 @@ | ||
| 38 | 38 | $(SRCDIR)/encode.c \ |
| 39 | 39 | $(SRCDIR)/event.c \ |
| 40 | 40 | $(SRCDIR)/export.c \ |
| 41 | 41 | $(SRCDIR)/file.c \ |
| 42 | 42 | $(SRCDIR)/finfo.c \ |
| 43 | + $(SRCDIR)/glob.c \ | |
| 43 | 44 | $(SRCDIR)/graph.c \ |
| 44 | 45 | $(SRCDIR)/gzip.c \ |
| 45 | 46 | $(SRCDIR)/http.c \ |
| 46 | 47 | $(SRCDIR)/http_socket.c \ |
| 47 | 48 | $(SRCDIR)/http_ssl.c \ |
| @@ -121,10 +122,11 @@ | ||
| 121 | 122 | $(OBJDIR)/encode_.c \ |
| 122 | 123 | $(OBJDIR)/event_.c \ |
| 123 | 124 | $(OBJDIR)/export_.c \ |
| 124 | 125 | $(OBJDIR)/file_.c \ |
| 125 | 126 | $(OBJDIR)/finfo_.c \ |
| 127 | + $(OBJDIR)/glob_.c \ | |
| 126 | 128 | $(OBJDIR)/graph_.c \ |
| 127 | 129 | $(OBJDIR)/gzip_.c \ |
| 128 | 130 | $(OBJDIR)/http_.c \ |
| 129 | 131 | $(OBJDIR)/http_socket_.c \ |
| 130 | 132 | $(OBJDIR)/http_ssl_.c \ |
| @@ -204,10 +206,11 @@ | ||
| 204 | 206 | $(OBJDIR)/encode.o \ |
| 205 | 207 | $(OBJDIR)/event.o \ |
| 206 | 208 | $(OBJDIR)/export.o \ |
| 207 | 209 | $(OBJDIR)/file.o \ |
| 208 | 210 | $(OBJDIR)/finfo.o \ |
| 211 | + $(OBJDIR)/glob.o \ | |
| 209 | 212 | $(OBJDIR)/graph.o \ |
| 210 | 213 | $(OBJDIR)/gzip.o \ |
| 211 | 214 | $(OBJDIR)/http.o \ |
| 212 | 215 | $(OBJDIR)/http_socket.o \ |
| 213 | 216 | $(OBJDIR)/http_ssl.o \ |
| @@ -307,11 +310,11 @@ | ||
| 307 | 310 | |
| 308 | 311 | |
| 309 | 312 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 310 | 313 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 311 | 314 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 312 | - $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 315 | + $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 313 | 316 | touch $(OBJDIR)/headers |
| 314 | 317 | $(OBJDIR)/headers: Makefile |
| 315 | 318 | Makefile: |
| 316 | 319 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| 317 | 320 | $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| @@ -514,10 +517,17 @@ | ||
| 514 | 517 | |
| 515 | 518 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 516 | 519 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 517 | 520 | |
| 518 | 521 | $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
| 522 | +$(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(OBJDIR)/translate | |
| 523 | + $(OBJDIR)/translate $(SRCDIR)/glob.c >$(OBJDIR)/glob_.c | |
| 524 | + | |
| 525 | +$(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h | |
| 526 | + $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c | |
| 527 | + | |
| 528 | +$(OBJDIR)/glob.h: $(OBJDIR)/headers | |
| 519 | 529 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 520 | 530 | $(OBJDIR)/translate $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 521 | 531 | |
| 522 | 532 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 523 | 533 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| @@ -882,13 +892,13 @@ | ||
| 882 | 892 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 883 | 893 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c |
| 884 | 894 | $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 885 | 895 | |
| 886 | 896 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c |
| 887 | - $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o | |
| 897 | + $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dfopen=fossil_fopen -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o | |
| 888 | 898 | |
| 889 | 899 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 890 | 900 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 891 | 901 | |
| 892 | 902 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 893 | 903 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o |
| 894 | 904 | |
| 895 | 905 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -38,10 +38,11 @@ | |
| 38 | $(SRCDIR)/encode.c \ |
| 39 | $(SRCDIR)/event.c \ |
| 40 | $(SRCDIR)/export.c \ |
| 41 | $(SRCDIR)/file.c \ |
| 42 | $(SRCDIR)/finfo.c \ |
| 43 | $(SRCDIR)/graph.c \ |
| 44 | $(SRCDIR)/gzip.c \ |
| 45 | $(SRCDIR)/http.c \ |
| 46 | $(SRCDIR)/http_socket.c \ |
| 47 | $(SRCDIR)/http_ssl.c \ |
| @@ -121,10 +122,11 @@ | |
| 121 | $(OBJDIR)/encode_.c \ |
| 122 | $(OBJDIR)/event_.c \ |
| 123 | $(OBJDIR)/export_.c \ |
| 124 | $(OBJDIR)/file_.c \ |
| 125 | $(OBJDIR)/finfo_.c \ |
| 126 | $(OBJDIR)/graph_.c \ |
| 127 | $(OBJDIR)/gzip_.c \ |
| 128 | $(OBJDIR)/http_.c \ |
| 129 | $(OBJDIR)/http_socket_.c \ |
| 130 | $(OBJDIR)/http_ssl_.c \ |
| @@ -204,10 +206,11 @@ | |
| 204 | $(OBJDIR)/encode.o \ |
| 205 | $(OBJDIR)/event.o \ |
| 206 | $(OBJDIR)/export.o \ |
| 207 | $(OBJDIR)/file.o \ |
| 208 | $(OBJDIR)/finfo.o \ |
| 209 | $(OBJDIR)/graph.o \ |
| 210 | $(OBJDIR)/gzip.o \ |
| 211 | $(OBJDIR)/http.o \ |
| 212 | $(OBJDIR)/http_socket.o \ |
| 213 | $(OBJDIR)/http_ssl.o \ |
| @@ -307,11 +310,11 @@ | |
| 307 | |
| 308 | |
| 309 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 310 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 311 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 312 | $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 313 | touch $(OBJDIR)/headers |
| 314 | $(OBJDIR)/headers: Makefile |
| 315 | Makefile: |
| 316 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| 317 | $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| @@ -514,10 +517,17 @@ | |
| 514 | |
| 515 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 516 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 517 | |
| 518 | $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
| 519 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 520 | $(OBJDIR)/translate $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 521 | |
| 522 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 523 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| @@ -882,13 +892,13 @@ | |
| 882 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 883 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c |
| 884 | $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 885 | |
| 886 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c |
| 887 | $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 888 | |
| 889 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 890 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 891 | |
| 892 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 893 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o |
| 894 | |
| 895 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -38,10 +38,11 @@ | |
| 38 | $(SRCDIR)/encode.c \ |
| 39 | $(SRCDIR)/event.c \ |
| 40 | $(SRCDIR)/export.c \ |
| 41 | $(SRCDIR)/file.c \ |
| 42 | $(SRCDIR)/finfo.c \ |
| 43 | $(SRCDIR)/glob.c \ |
| 44 | $(SRCDIR)/graph.c \ |
| 45 | $(SRCDIR)/gzip.c \ |
| 46 | $(SRCDIR)/http.c \ |
| 47 | $(SRCDIR)/http_socket.c \ |
| 48 | $(SRCDIR)/http_ssl.c \ |
| @@ -121,10 +122,11 @@ | |
| 122 | $(OBJDIR)/encode_.c \ |
| 123 | $(OBJDIR)/event_.c \ |
| 124 | $(OBJDIR)/export_.c \ |
| 125 | $(OBJDIR)/file_.c \ |
| 126 | $(OBJDIR)/finfo_.c \ |
| 127 | $(OBJDIR)/glob_.c \ |
| 128 | $(OBJDIR)/graph_.c \ |
| 129 | $(OBJDIR)/gzip_.c \ |
| 130 | $(OBJDIR)/http_.c \ |
| 131 | $(OBJDIR)/http_socket_.c \ |
| 132 | $(OBJDIR)/http_ssl_.c \ |
| @@ -204,10 +206,11 @@ | |
| 206 | $(OBJDIR)/encode.o \ |
| 207 | $(OBJDIR)/event.o \ |
| 208 | $(OBJDIR)/export.o \ |
| 209 | $(OBJDIR)/file.o \ |
| 210 | $(OBJDIR)/finfo.o \ |
| 211 | $(OBJDIR)/glob.o \ |
| 212 | $(OBJDIR)/graph.o \ |
| 213 | $(OBJDIR)/gzip.o \ |
| 214 | $(OBJDIR)/http.o \ |
| 215 | $(OBJDIR)/http_socket.o \ |
| 216 | $(OBJDIR)/http_ssl.o \ |
| @@ -307,11 +310,11 @@ | |
| 310 | |
| 311 | |
| 312 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 313 | $(OBJDIR)/mkindex $(TRANS_SRC) >$@ |
| 314 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 315 | $(OBJDIR)/makeheaders $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 316 | touch $(OBJDIR)/headers |
| 317 | $(OBJDIR)/headers: Makefile |
| 318 | Makefile: |
| 319 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| 320 | $(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c |
| @@ -514,10 +517,17 @@ | |
| 517 | |
| 518 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 519 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 520 | |
| 521 | $(OBJDIR)/finfo.h: $(OBJDIR)/headers |
| 522 | $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(OBJDIR)/translate |
| 523 | $(OBJDIR)/translate $(SRCDIR)/glob.c >$(OBJDIR)/glob_.c |
| 524 | |
| 525 | $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h |
| 526 | $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c |
| 527 | |
| 528 | $(OBJDIR)/glob.h: $(OBJDIR)/headers |
| 529 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 530 | $(OBJDIR)/translate $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 531 | |
| 532 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 533 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| @@ -882,13 +892,13 @@ | |
| 892 | $(OBJDIR)/zip.h: $(OBJDIR)/headers |
| 893 | $(OBJDIR)/sqlite3.o: $(SRCDIR)/sqlite3.c |
| 894 | $(XTCC) -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 -c $(SRCDIR)/sqlite3.c -o $(OBJDIR)/sqlite3.o |
| 895 | |
| 896 | $(OBJDIR)/shell.o: $(SRCDIR)/shell.c |
| 897 | $(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -Dfopen=fossil_fopen -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o |
| 898 | |
| 899 | $(OBJDIR)/th.o: $(SRCDIR)/th.c |
| 900 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o |
| 901 | |
| 902 | $(OBJDIR)/th_lang.o: $(SRCDIR)/th_lang.c |
| 903 | $(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o |
| 904 | |
| 905 |
+6
-8
| --- src/makemake.tcl | ||
| +++ src/makemake.tcl | ||
| @@ -45,10 +45,11 @@ | ||
| 45 | 45 | encode |
| 46 | 46 | event |
| 47 | 47 | export |
| 48 | 48 | file |
| 49 | 49 | finfo |
| 50 | + glob | |
| 50 | 51 | graph |
| 51 | 52 | gzip |
| 52 | 53 | http |
| 53 | 54 | http_socket |
| 54 | 55 | http_transport |
| @@ -249,10 +250,11 @@ | ||
| 249 | 250 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 250 | 251 | |
| 251 | 252 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c" |
| 252 | 253 | set opt {-Dmain=sqlite3_shell} |
| 253 | 254 | append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1" |
| 255 | +append opt " -Dfopen=fossil_fopen" | |
| 254 | 256 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 255 | 257 | |
| 256 | 258 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 257 | 259 | writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 258 | 260 | |
| @@ -306,11 +308,11 @@ | ||
| 306 | 308 | # will run on the target platform. This is usually the same |
| 307 | 309 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 308 | 310 | # the finished binary for fossil. The BCC compiler above is used |
| 309 | 311 | # for building intermediate code-generator tools. |
| 310 | 312 | # |
| 311 | -TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include | |
| 313 | +TCC = gcc -Os -Wall -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include | |
| 312 | 314 | |
| 313 | 315 | # With HTTPS support |
| 314 | 316 | ifdef FOSSIL_ENABLE_SSL |
| 315 | 317 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 316 | 318 | endif |
| @@ -501,15 +503,13 @@ | ||
| 501 | 503 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 502 | 504 | |
| 503 | 505 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 504 | 506 | SSL = |
| 505 | 507 | |
| 506 | -I18N = -DFOSSIL_I18N=0 | |
| 507 | - | |
| 508 | 508 | CFLAGS = -o |
| 509 | 509 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 510 | -TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) | |
| 510 | +TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) | |
| 511 | 511 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 512 | 512 | } |
| 513 | 513 | writeln "SQLITE_OPTIONS = $SQLITE_OPTIONS\n" |
| 514 | 514 | writeln -nonewline "SRC = " |
| 515 | 515 | foreach s [lsort $src] { |
| @@ -644,15 +644,13 @@ | ||
| 644 | 644 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 645 | 645 | ZLIB = zlib.lib |
| 646 | 646 | |
| 647 | 647 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 648 | 648 | |
| 649 | -I18N = -DFOSSIL_I18N=0 | |
| 650 | - | |
| 651 | 649 | CFLAGS = -nologo -MT -O2 |
| 652 | 650 | BCC = $(CC) $(CFLAGS) |
| 653 | -TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(I18N) $(SSL) $(INCL) | |
| 651 | +TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) | |
| 654 | 652 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 655 | 653 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 656 | 654 | } |
| 657 | 655 | regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS |
| 658 | 656 | writeln "SQLITE_OPTIONS = $MSC_SQLITE_OPTIONS\n" |
| @@ -818,11 +816,11 @@ | ||
| 818 | 816 | |
| 819 | 817 | # define standard C-compiler and flags, used to compile |
| 820 | 818 | # the fossil binary. Some special definitions follow for |
| 821 | 819 | # special files follow |
| 822 | 820 | CC=$(PellesCDir)\bin\pocc.exe |
| 823 | -DEFINES=-DFOSSIL_I18N=0 -D_pgmptr=g.argv[0] | |
| 821 | +DEFINES=-D_pgmptr=g.argv[0] | |
| 824 | 822 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 825 | 823 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 826 | 824 | |
| 827 | 825 | # define commands for building the windows resource files |
| 828 | 826 | RESOURCE=fossil.res |
| 829 | 827 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -45,10 +45,11 @@ | |
| 45 | encode |
| 46 | event |
| 47 | export |
| 48 | file |
| 49 | finfo |
| 50 | graph |
| 51 | gzip |
| 52 | http |
| 53 | http_socket |
| 54 | http_transport |
| @@ -249,10 +250,11 @@ | |
| 249 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 250 | |
| 251 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c" |
| 252 | set opt {-Dmain=sqlite3_shell} |
| 253 | append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1" |
| 254 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 255 | |
| 256 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 257 | writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 258 | |
| @@ -306,11 +308,11 @@ | |
| 306 | # will run on the target platform. This is usually the same |
| 307 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 308 | # the finished binary for fossil. The BCC compiler above is used |
| 309 | # for building intermediate code-generator tools. |
| 310 | # |
| 311 | TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include |
| 312 | |
| 313 | # With HTTPS support |
| 314 | ifdef FOSSIL_ENABLE_SSL |
| 315 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 316 | endif |
| @@ -501,15 +503,13 @@ | |
| 501 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 502 | |
| 503 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 504 | SSL = |
| 505 | |
| 506 | I18N = -DFOSSIL_I18N=0 |
| 507 | |
| 508 | CFLAGS = -o |
| 509 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 510 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 511 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 512 | } |
| 513 | writeln "SQLITE_OPTIONS = $SQLITE_OPTIONS\n" |
| 514 | writeln -nonewline "SRC = " |
| 515 | foreach s [lsort $src] { |
| @@ -644,15 +644,13 @@ | |
| 644 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 645 | ZLIB = zlib.lib |
| 646 | |
| 647 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 648 | |
| 649 | I18N = -DFOSSIL_I18N=0 |
| 650 | |
| 651 | CFLAGS = -nologo -MT -O2 |
| 652 | BCC = $(CC) $(CFLAGS) |
| 653 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(I18N) $(SSL) $(INCL) |
| 654 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 655 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 656 | } |
| 657 | regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS |
| 658 | writeln "SQLITE_OPTIONS = $MSC_SQLITE_OPTIONS\n" |
| @@ -818,11 +816,11 @@ | |
| 818 | |
| 819 | # define standard C-compiler and flags, used to compile |
| 820 | # the fossil binary. Some special definitions follow for |
| 821 | # special files follow |
| 822 | CC=$(PellesCDir)\bin\pocc.exe |
| 823 | DEFINES=-DFOSSIL_I18N=0 -D_pgmptr=g.argv[0] |
| 824 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 825 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 826 | |
| 827 | # define commands for building the windows resource files |
| 828 | RESOURCE=fossil.res |
| 829 |
| --- src/makemake.tcl | |
| +++ src/makemake.tcl | |
| @@ -45,10 +45,11 @@ | |
| 45 | encode |
| 46 | event |
| 47 | export |
| 48 | file |
| 49 | finfo |
| 50 | glob |
| 51 | graph |
| 52 | gzip |
| 53 | http |
| 54 | http_socket |
| 55 | http_transport |
| @@ -249,10 +250,11 @@ | |
| 250 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/sqlite3.c -o \$(OBJDIR)/sqlite3.o\n" |
| 251 | |
| 252 | writeln "\$(OBJDIR)/shell.o:\t\$(SRCDIR)/shell.c" |
| 253 | set opt {-Dmain=sqlite3_shell} |
| 254 | append opt " -DSQLITE_OMIT_LOAD_EXTENSION=1" |
| 255 | append opt " -Dfopen=fossil_fopen" |
| 256 | writeln "\t\$(XTCC) $opt -c \$(SRCDIR)/shell.c -o \$(OBJDIR)/shell.o\n" |
| 257 | |
| 258 | writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c" |
| 259 | writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n" |
| 260 | |
| @@ -306,11 +308,11 @@ | |
| 308 | # will run on the target platform. This is usually the same |
| 309 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 310 | # the finished binary for fossil. The BCC compiler above is used |
| 311 | # for building intermediate code-generator tools. |
| 312 | # |
| 313 | TCC = gcc -Os -Wall -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include |
| 314 | |
| 315 | # With HTTPS support |
| 316 | ifdef FOSSIL_ENABLE_SSL |
| 317 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 318 | endif |
| @@ -501,15 +503,13 @@ | |
| 503 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 504 | |
| 505 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 506 | SSL = |
| 507 | |
| 508 | CFLAGS = -o |
| 509 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 510 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 511 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 512 | } |
| 513 | writeln "SQLITE_OPTIONS = $SQLITE_OPTIONS\n" |
| 514 | writeln -nonewline "SRC = " |
| 515 | foreach s [lsort $src] { |
| @@ -644,15 +644,13 @@ | |
| 644 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 645 | ZLIB = zlib.lib |
| 646 | |
| 647 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 648 | |
| 649 | CFLAGS = -nologo -MT -O2 |
| 650 | BCC = $(CC) $(CFLAGS) |
| 651 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) |
| 652 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 653 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 654 | } |
| 655 | regsub -all {[-]D} $SQLITE_OPTIONS {/D} MSC_SQLITE_OPTIONS |
| 656 | writeln "SQLITE_OPTIONS = $MSC_SQLITE_OPTIONS\n" |
| @@ -818,11 +816,11 @@ | |
| 816 | |
| 817 | # define standard C-compiler and flags, used to compile |
| 818 | # the fossil binary. Some special definitions follow for |
| 819 | # special files follow |
| 820 | CC=$(PellesCDir)\bin\pocc.exe |
| 821 | DEFINES=-D_pgmptr=g.argv[0] |
| 822 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 823 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 824 | |
| 825 | # define commands for building the windows resource files |
| 826 | RESOURCE=fossil.res |
| 827 |
+18
-16
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -1706,30 +1706,32 @@ | ||
| 1706 | 1706 | sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); |
| 1707 | 1707 | tag_insert(zTag, 1, zLength, rid, p->rDate, rid); |
| 1708 | 1708 | free(zTag); |
| 1709 | 1709 | prior = db_int(0, |
| 1710 | 1710 | "SELECT rid FROM tagxref" |
| 1711 | - " WHERE tagid=%d AND mtime<%.17g" | |
| 1711 | + " WHERE tagid=%d AND mtime<%.17g AND rid!=%d" | |
| 1712 | 1712 | " ORDER BY mtime DESC", |
| 1713 | - tagid, p->rDate | |
| 1713 | + tagid, p->rDate, rid | |
| 1714 | + ); | |
| 1715 | + subsequent = db_int(0, | |
| 1716 | + "SELECT rid FROM tagxref" | |
| 1717 | + " WHERE tagid=%d AND mtime>=%.17g AND rid!=%d" | |
| 1718 | + " ORDER BY mtime", | |
| 1719 | + tagid, p->rDate, rid | |
| 1714 | 1720 | ); |
| 1715 | 1721 | if( prior ){ |
| 1716 | 1722 | content_deltify(prior, rid, 0); |
| 1717 | - db_multi_exec( | |
| 1718 | - "DELETE FROM event" | |
| 1719 | - " WHERE type='e'" | |
| 1720 | - " AND tagid=%d" | |
| 1721 | - " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", | |
| 1722 | - tagid, tagid | |
| 1723 | - ); | |
| 1724 | - } | |
| 1725 | - subsequent = db_int(0, | |
| 1726 | - "SELECT rid FROM tagxref" | |
| 1727 | - " WHERE tagid=%d AND mtime>%.17g" | |
| 1728 | - " ORDER BY mtime", | |
| 1729 | - tagid, p->rDate | |
| 1730 | - ); | |
| 1723 | + if( !subsequent ){ | |
| 1724 | + db_multi_exec( | |
| 1725 | + "DELETE FROM event" | |
| 1726 | + " WHERE type='e'" | |
| 1727 | + " AND tagid=%d" | |
| 1728 | + " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", | |
| 1729 | + tagid, tagid | |
| 1730 | + ); | |
| 1731 | + } | |
| 1732 | + } | |
| 1731 | 1733 | if( subsequent ){ |
| 1732 | 1734 | content_deltify(rid, subsequent, 0); |
| 1733 | 1735 | }else{ |
| 1734 | 1736 | db_multi_exec( |
| 1735 | 1737 | "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" |
| 1736 | 1738 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1706,30 +1706,32 @@ | |
| 1706 | sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); |
| 1707 | tag_insert(zTag, 1, zLength, rid, p->rDate, rid); |
| 1708 | free(zTag); |
| 1709 | prior = db_int(0, |
| 1710 | "SELECT rid FROM tagxref" |
| 1711 | " WHERE tagid=%d AND mtime<%.17g" |
| 1712 | " ORDER BY mtime DESC", |
| 1713 | tagid, p->rDate |
| 1714 | ); |
| 1715 | if( prior ){ |
| 1716 | content_deltify(prior, rid, 0); |
| 1717 | db_multi_exec( |
| 1718 | "DELETE FROM event" |
| 1719 | " WHERE type='e'" |
| 1720 | " AND tagid=%d" |
| 1721 | " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", |
| 1722 | tagid, tagid |
| 1723 | ); |
| 1724 | } |
| 1725 | subsequent = db_int(0, |
| 1726 | "SELECT rid FROM tagxref" |
| 1727 | " WHERE tagid=%d AND mtime>%.17g" |
| 1728 | " ORDER BY mtime", |
| 1729 | tagid, p->rDate |
| 1730 | ); |
| 1731 | if( subsequent ){ |
| 1732 | content_deltify(rid, subsequent, 0); |
| 1733 | }else{ |
| 1734 | db_multi_exec( |
| 1735 | "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" |
| 1736 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1706,30 +1706,32 @@ | |
| 1706 | sqlite3_snprintf(sizeof(zLength), zLength, "%d", nWiki); |
| 1707 | tag_insert(zTag, 1, zLength, rid, p->rDate, rid); |
| 1708 | free(zTag); |
| 1709 | prior = db_int(0, |
| 1710 | "SELECT rid FROM tagxref" |
| 1711 | " WHERE tagid=%d AND mtime<%.17g AND rid!=%d" |
| 1712 | " ORDER BY mtime DESC", |
| 1713 | tagid, p->rDate, rid |
| 1714 | ); |
| 1715 | subsequent = db_int(0, |
| 1716 | "SELECT rid FROM tagxref" |
| 1717 | " WHERE tagid=%d AND mtime>=%.17g AND rid!=%d" |
| 1718 | " ORDER BY mtime", |
| 1719 | tagid, p->rDate, rid |
| 1720 | ); |
| 1721 | if( prior ){ |
| 1722 | content_deltify(prior, rid, 0); |
| 1723 | if( !subsequent ){ |
| 1724 | db_multi_exec( |
| 1725 | "DELETE FROM event" |
| 1726 | " WHERE type='e'" |
| 1727 | " AND tagid=%d" |
| 1728 | " AND objid IN (SELECT rid FROM tagxref WHERE tagid=%d)", |
| 1729 | tagid, tagid |
| 1730 | ); |
| 1731 | } |
| 1732 | } |
| 1733 | if( subsequent ){ |
| 1734 | content_deltify(rid, subsequent, 0); |
| 1735 | }else{ |
| 1736 | db_multi_exec( |
| 1737 | "REPLACE INTO event(type,mtime,objid,tagid,user,comment,bgcolor)" |
| 1738 |
+2
-2
| --- src/md5.c | ||
| +++ src/md5.c | ||
| @@ -376,11 +376,11 @@ | ||
| 376 | 376 | FILE *in; |
| 377 | 377 | MD5Context ctx; |
| 378 | 378 | unsigned char zResult[16]; |
| 379 | 379 | char zBuf[10240]; |
| 380 | 380 | |
| 381 | - in = fopen(zFilename,"rb"); | |
| 381 | + in = fossil_fopen(zFilename,"rb"); | |
| 382 | 382 | if( in==0 ){ |
| 383 | 383 | return 1; |
| 384 | 384 | } |
| 385 | 385 | MD5Init(&ctx); |
| 386 | 386 | for(;;){ |
| @@ -438,9 +438,9 @@ | ||
| 438 | 438 | blob_read_from_channel(&in, stdin, -1); |
| 439 | 439 | md5sum_blob(&in, &cksum); |
| 440 | 440 | }else{ |
| 441 | 441 | md5sum_file(g.argv[i], &cksum); |
| 442 | 442 | } |
| 443 | - printf("%s %s\n", blob_str(&cksum), g.argv[i]); | |
| 443 | + fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); | |
| 444 | 444 | blob_reset(&cksum); |
| 445 | 445 | } |
| 446 | 446 | } |
| 447 | 447 |
| --- src/md5.c | |
| +++ src/md5.c | |
| @@ -376,11 +376,11 @@ | |
| 376 | FILE *in; |
| 377 | MD5Context ctx; |
| 378 | unsigned char zResult[16]; |
| 379 | char zBuf[10240]; |
| 380 | |
| 381 | in = fopen(zFilename,"rb"); |
| 382 | if( in==0 ){ |
| 383 | return 1; |
| 384 | } |
| 385 | MD5Init(&ctx); |
| 386 | for(;;){ |
| @@ -438,9 +438,9 @@ | |
| 438 | blob_read_from_channel(&in, stdin, -1); |
| 439 | md5sum_blob(&in, &cksum); |
| 440 | }else{ |
| 441 | md5sum_file(g.argv[i], &cksum); |
| 442 | } |
| 443 | printf("%s %s\n", blob_str(&cksum), g.argv[i]); |
| 444 | blob_reset(&cksum); |
| 445 | } |
| 446 | } |
| 447 |
| --- src/md5.c | |
| +++ src/md5.c | |
| @@ -376,11 +376,11 @@ | |
| 376 | FILE *in; |
| 377 | MD5Context ctx; |
| 378 | unsigned char zResult[16]; |
| 379 | char zBuf[10240]; |
| 380 | |
| 381 | in = fossil_fopen(zFilename,"rb"); |
| 382 | if( in==0 ){ |
| 383 | return 1; |
| 384 | } |
| 385 | MD5Init(&ctx); |
| 386 | for(;;){ |
| @@ -438,9 +438,9 @@ | |
| 438 | blob_read_from_channel(&in, stdin, -1); |
| 439 | md5sum_blob(&in, &cksum); |
| 440 | }else{ |
| 441 | md5sum_file(g.argv[i], &cksum); |
| 442 | } |
| 443 | fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); |
| 444 | blob_reset(&cksum); |
| 445 | } |
| 446 | } |
| 447 |
+19
-17
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -249,20 +249,20 @@ | ||
| 249 | 249 | if( debugFlag ){ |
| 250 | 250 | db_prepare(&q, |
| 251 | 251 | "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, isexe FROM fv" |
| 252 | 252 | ); |
| 253 | 253 | while( db_step(&q)==SQLITE_ROW ){ |
| 254 | - printf("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d\n", | |
| 254 | + fossil_print("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d\n", | |
| 255 | 255 | db_column_int(&q, 0), |
| 256 | 256 | db_column_int(&q, 5), |
| 257 | 257 | db_column_int(&q, 6), |
| 258 | 258 | db_column_int(&q, 7), |
| 259 | 259 | db_column_int(&q, 4), |
| 260 | 260 | db_column_int(&q, 8)); |
| 261 | - printf(" fn = [%s]\n", db_column_text(&q, 1)); | |
| 262 | - printf(" fnp = [%s]\n", db_column_text(&q, 2)); | |
| 263 | - printf(" fnm = [%s]\n", db_column_text(&q, 3)); | |
| 261 | + fossil_print(" fn = [%s]\n", db_column_text(&q, 1)); | |
| 262 | + fossil_print(" fnp = [%s]\n", db_column_text(&q, 2)); | |
| 263 | + fossil_print(" fnm = [%s]\n", db_column_text(&q, 3)); | |
| 264 | 264 | } |
| 265 | 265 | db_finalize(&q); |
| 266 | 266 | } |
| 267 | 267 | |
| 268 | 268 | /* |
| @@ -274,11 +274,11 @@ | ||
| 274 | 274 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 275 | 275 | ); |
| 276 | 276 | while( db_step(&q)==SQLITE_ROW ){ |
| 277 | 277 | int idm = db_column_int(&q, 0); |
| 278 | 278 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 279 | - printf("WARNING - no common ancestor: %s\n", zName); | |
| 279 | + fossil_warning("WARNING - no common ancestor: %s\n", zName); | |
| 280 | 280 | free(zName); |
| 281 | 281 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 282 | 282 | } |
| 283 | 283 | db_finalize(&q); |
| 284 | 284 | |
| @@ -300,11 +300,11 @@ | ||
| 300 | 300 | vid, idm |
| 301 | 301 | ); |
| 302 | 302 | idv = db_last_insert_rowid(); |
| 303 | 303 | db_multi_exec("UPDATE fv SET idv=%d WHERE rowid=%d", idv, rowid); |
| 304 | 304 | zName = db_column_text(&q, 2); |
| 305 | - printf("ADDED %s\n", zName); | |
| 305 | + fossil_print("ADDED %s\n", zName); | |
| 306 | 306 | if( !nochangeFlag ){ |
| 307 | 307 | undo_save(zName); |
| 308 | 308 | vfile_to_disk(0, idm, 0, 0); |
| 309 | 309 | } |
| 310 | 310 | } |
| @@ -322,11 +322,11 @@ | ||
| 322 | 322 | while( db_step(&q)==SQLITE_ROW ){ |
| 323 | 323 | int idv = db_column_int(&q, 0); |
| 324 | 324 | int ridm = db_column_int(&q, 1); |
| 325 | 325 | const char *zName = db_column_text(&q, 2); |
| 326 | 326 | /* Copy content from idm over into idv. Overwrite idv. */ |
| 327 | - printf("UPDATE %s\n", zName); | |
| 327 | + fossil_print("UPDATE %s\n", zName); | |
| 328 | 328 | if( !nochangeFlag ){ |
| 329 | 329 | undo_save(zName); |
| 330 | 330 | db_multi_exec( |
| 331 | 331 | "UPDATE vfile SET mtime=0, mrid=%d, chnged=2 WHERE id=%d", ridm, idv |
| 332 | 332 | ); |
| @@ -355,13 +355,14 @@ | ||
| 355 | 355 | int rc; |
| 356 | 356 | char *zFullPath; |
| 357 | 357 | Blob m, p, r; |
| 358 | 358 | /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */ |
| 359 | 359 | if( detailFlag ){ |
| 360 | - printf("MERGE %s (pivot=%d v1=%d v2=%d)\n", zName, ridp, ridm, ridv); | |
| 360 | + fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n", | |
| 361 | + zName, ridp, ridm, ridv); | |
| 361 | 362 | }else{ |
| 362 | - printf("MERGE %s\n", zName); | |
| 363 | + fossil_print("MERGE %s\n", zName); | |
| 363 | 364 | } |
| 364 | 365 | undo_save(zName); |
| 365 | 366 | zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
| 366 | 367 | content_get(ridp, &p); |
| 367 | 368 | content_get(ridm, &m); |
| @@ -376,15 +377,15 @@ | ||
| 376 | 377 | blob_write_to_file(&r, zFullPath); |
| 377 | 378 | file_setexe(zFullPath, isExe); |
| 378 | 379 | } |
| 379 | 380 | db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv); |
| 380 | 381 | if( rc>0 ){ |
| 381 | - printf("***** %d merge conflicts in %s\n", rc, zName); | |
| 382 | + fossil_print("***** %d merge conflicts in %s\n", rc, zName); | |
| 382 | 383 | nConflict++; |
| 383 | 384 | } |
| 384 | 385 | }else{ |
| 385 | - printf("***** Cannot merge binary file %s\n", zName); | |
| 386 | + fossil_print("***** Cannot merge binary file %s\n", zName); | |
| 386 | 387 | nConflict++; |
| 387 | 388 | } |
| 388 | 389 | blob_reset(&p); |
| 389 | 390 | blob_reset(&m); |
| 390 | 391 | blob_reset(&r); |
| @@ -403,22 +404,22 @@ | ||
| 403 | 404 | while( db_step(&q)==SQLITE_ROW ){ |
| 404 | 405 | int idv = db_column_int(&q, 0); |
| 405 | 406 | const char *zName = db_column_text(&q, 1); |
| 406 | 407 | int chnged = db_column_int(&q, 2); |
| 407 | 408 | /* Delete the file idv */ |
| 408 | - printf("DELETE %s\n", zName); | |
| 409 | + fossil_print("DELETE %s\n", zName); | |
| 409 | 410 | if( chnged ){ |
| 410 | - printf("WARNING: local edits lost for %s\n", zName); | |
| 411 | + fossil_warning("WARNING: local edits lost for %s\n", zName); | |
| 411 | 412 | nConflict++; |
| 412 | 413 | } |
| 413 | 414 | undo_save(zName); |
| 414 | 415 | db_multi_exec( |
| 415 | 416 | "UPDATE vfile SET deleted=1 WHERE id=%d", idv |
| 416 | 417 | ); |
| 417 | 418 | if( !nochangeFlag ){ |
| 418 | 419 | char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName); |
| 419 | - unlink(zFullPath); | |
| 420 | + file_delete(zFullPath); | |
| 420 | 421 | free(zFullPath); |
| 421 | 422 | } |
| 422 | 423 | } |
| 423 | 424 | db_finalize(&q); |
| 424 | 425 | |
| @@ -433,11 +434,11 @@ | ||
| 433 | 434 | ); |
| 434 | 435 | while( db_step(&q)==SQLITE_ROW ){ |
| 435 | 436 | int idv = db_column_int(&q, 0); |
| 436 | 437 | const char *zOldName = db_column_text(&q, 1); |
| 437 | 438 | const char *zNewName = db_column_text(&q, 2); |
| 438 | - printf("RENAME %s -> %s\n", zOldName, zNewName); | |
| 439 | + fossil_print("RENAME %s -> %s\n", zOldName, zNewName); | |
| 439 | 440 | undo_save(zOldName); |
| 440 | 441 | undo_save(zNewName); |
| 441 | 442 | db_multi_exec( |
| 442 | 443 | "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)" |
| 443 | 444 | " WHERE id=%d AND vid=%d", zNewName, idv, vid |
| @@ -444,11 +445,11 @@ | ||
| 444 | 445 | ); |
| 445 | 446 | if( !nochangeFlag ){ |
| 446 | 447 | char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); |
| 447 | 448 | char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); |
| 448 | 449 | file_copy(zFullOldPath, zFullNewPath); |
| 449 | - unlink(zFullOldPath); | |
| 450 | + file_delete(zFullOldPath); | |
| 450 | 451 | free(zFullNewPath); |
| 451 | 452 | free(zFullOldPath); |
| 452 | 453 | } |
| 453 | 454 | } |
| 454 | 455 | db_finalize(&q); |
| @@ -455,11 +456,12 @@ | ||
| 455 | 456 | |
| 456 | 457 | |
| 457 | 458 | /* Report on conflicts |
| 458 | 459 | */ |
| 459 | 460 | if( nConflict && !nochangeFlag ){ |
| 460 | - printf("WARNING: merge conflicts - see messages above for details.\n"); | |
| 461 | + fossil_warning( | |
| 462 | + "WARNING: merge conflicts - see messages above for details.\n"); | |
| 461 | 463 | } |
| 462 | 464 | |
| 463 | 465 | /* |
| 464 | 466 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 465 | 467 | */ |
| 466 | 468 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -249,20 +249,20 @@ | |
| 249 | if( debugFlag ){ |
| 250 | db_prepare(&q, |
| 251 | "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, isexe FROM fv" |
| 252 | ); |
| 253 | while( db_step(&q)==SQLITE_ROW ){ |
| 254 | printf("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d\n", |
| 255 | db_column_int(&q, 0), |
| 256 | db_column_int(&q, 5), |
| 257 | db_column_int(&q, 6), |
| 258 | db_column_int(&q, 7), |
| 259 | db_column_int(&q, 4), |
| 260 | db_column_int(&q, 8)); |
| 261 | printf(" fn = [%s]\n", db_column_text(&q, 1)); |
| 262 | printf(" fnp = [%s]\n", db_column_text(&q, 2)); |
| 263 | printf(" fnm = [%s]\n", db_column_text(&q, 3)); |
| 264 | } |
| 265 | db_finalize(&q); |
| 266 | } |
| 267 | |
| 268 | /* |
| @@ -274,11 +274,11 @@ | |
| 274 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 275 | ); |
| 276 | while( db_step(&q)==SQLITE_ROW ){ |
| 277 | int idm = db_column_int(&q, 0); |
| 278 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 279 | printf("WARNING - no common ancestor: %s\n", zName); |
| 280 | free(zName); |
| 281 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 282 | } |
| 283 | db_finalize(&q); |
| 284 | |
| @@ -300,11 +300,11 @@ | |
| 300 | vid, idm |
| 301 | ); |
| 302 | idv = db_last_insert_rowid(); |
| 303 | db_multi_exec("UPDATE fv SET idv=%d WHERE rowid=%d", idv, rowid); |
| 304 | zName = db_column_text(&q, 2); |
| 305 | printf("ADDED %s\n", zName); |
| 306 | if( !nochangeFlag ){ |
| 307 | undo_save(zName); |
| 308 | vfile_to_disk(0, idm, 0, 0); |
| 309 | } |
| 310 | } |
| @@ -322,11 +322,11 @@ | |
| 322 | while( db_step(&q)==SQLITE_ROW ){ |
| 323 | int idv = db_column_int(&q, 0); |
| 324 | int ridm = db_column_int(&q, 1); |
| 325 | const char *zName = db_column_text(&q, 2); |
| 326 | /* Copy content from idm over into idv. Overwrite idv. */ |
| 327 | printf("UPDATE %s\n", zName); |
| 328 | if( !nochangeFlag ){ |
| 329 | undo_save(zName); |
| 330 | db_multi_exec( |
| 331 | "UPDATE vfile SET mtime=0, mrid=%d, chnged=2 WHERE id=%d", ridm, idv |
| 332 | ); |
| @@ -355,13 +355,14 @@ | |
| 355 | int rc; |
| 356 | char *zFullPath; |
| 357 | Blob m, p, r; |
| 358 | /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */ |
| 359 | if( detailFlag ){ |
| 360 | printf("MERGE %s (pivot=%d v1=%d v2=%d)\n", zName, ridp, ridm, ridv); |
| 361 | }else{ |
| 362 | printf("MERGE %s\n", zName); |
| 363 | } |
| 364 | undo_save(zName); |
| 365 | zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
| 366 | content_get(ridp, &p); |
| 367 | content_get(ridm, &m); |
| @@ -376,15 +377,15 @@ | |
| 376 | blob_write_to_file(&r, zFullPath); |
| 377 | file_setexe(zFullPath, isExe); |
| 378 | } |
| 379 | db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv); |
| 380 | if( rc>0 ){ |
| 381 | printf("***** %d merge conflicts in %s\n", rc, zName); |
| 382 | nConflict++; |
| 383 | } |
| 384 | }else{ |
| 385 | printf("***** Cannot merge binary file %s\n", zName); |
| 386 | nConflict++; |
| 387 | } |
| 388 | blob_reset(&p); |
| 389 | blob_reset(&m); |
| 390 | blob_reset(&r); |
| @@ -403,22 +404,22 @@ | |
| 403 | while( db_step(&q)==SQLITE_ROW ){ |
| 404 | int idv = db_column_int(&q, 0); |
| 405 | const char *zName = db_column_text(&q, 1); |
| 406 | int chnged = db_column_int(&q, 2); |
| 407 | /* Delete the file idv */ |
| 408 | printf("DELETE %s\n", zName); |
| 409 | if( chnged ){ |
| 410 | printf("WARNING: local edits lost for %s\n", zName); |
| 411 | nConflict++; |
| 412 | } |
| 413 | undo_save(zName); |
| 414 | db_multi_exec( |
| 415 | "UPDATE vfile SET deleted=1 WHERE id=%d", idv |
| 416 | ); |
| 417 | if( !nochangeFlag ){ |
| 418 | char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName); |
| 419 | unlink(zFullPath); |
| 420 | free(zFullPath); |
| 421 | } |
| 422 | } |
| 423 | db_finalize(&q); |
| 424 | |
| @@ -433,11 +434,11 @@ | |
| 433 | ); |
| 434 | while( db_step(&q)==SQLITE_ROW ){ |
| 435 | int idv = db_column_int(&q, 0); |
| 436 | const char *zOldName = db_column_text(&q, 1); |
| 437 | const char *zNewName = db_column_text(&q, 2); |
| 438 | printf("RENAME %s -> %s\n", zOldName, zNewName); |
| 439 | undo_save(zOldName); |
| 440 | undo_save(zNewName); |
| 441 | db_multi_exec( |
| 442 | "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)" |
| 443 | " WHERE id=%d AND vid=%d", zNewName, idv, vid |
| @@ -444,11 +445,11 @@ | |
| 444 | ); |
| 445 | if( !nochangeFlag ){ |
| 446 | char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); |
| 447 | char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); |
| 448 | file_copy(zFullOldPath, zFullNewPath); |
| 449 | unlink(zFullOldPath); |
| 450 | free(zFullNewPath); |
| 451 | free(zFullOldPath); |
| 452 | } |
| 453 | } |
| 454 | db_finalize(&q); |
| @@ -455,11 +456,12 @@ | |
| 455 | |
| 456 | |
| 457 | /* Report on conflicts |
| 458 | */ |
| 459 | if( nConflict && !nochangeFlag ){ |
| 460 | printf("WARNING: merge conflicts - see messages above for details.\n"); |
| 461 | } |
| 462 | |
| 463 | /* |
| 464 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 465 | */ |
| 466 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -249,20 +249,20 @@ | |
| 249 | if( debugFlag ){ |
| 250 | db_prepare(&q, |
| 251 | "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, isexe FROM fv" |
| 252 | ); |
| 253 | while( db_step(&q)==SQLITE_ROW ){ |
| 254 | fossil_print("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d\n", |
| 255 | db_column_int(&q, 0), |
| 256 | db_column_int(&q, 5), |
| 257 | db_column_int(&q, 6), |
| 258 | db_column_int(&q, 7), |
| 259 | db_column_int(&q, 4), |
| 260 | db_column_int(&q, 8)); |
| 261 | fossil_print(" fn = [%s]\n", db_column_text(&q, 1)); |
| 262 | fossil_print(" fnp = [%s]\n", db_column_text(&q, 2)); |
| 263 | fossil_print(" fnm = [%s]\n", db_column_text(&q, 3)); |
| 264 | } |
| 265 | db_finalize(&q); |
| 266 | } |
| 267 | |
| 268 | /* |
| @@ -274,11 +274,11 @@ | |
| 274 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 275 | ); |
| 276 | while( db_step(&q)==SQLITE_ROW ){ |
| 277 | int idm = db_column_int(&q, 0); |
| 278 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 279 | fossil_warning("WARNING - no common ancestor: %s\n", zName); |
| 280 | free(zName); |
| 281 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 282 | } |
| 283 | db_finalize(&q); |
| 284 | |
| @@ -300,11 +300,11 @@ | |
| 300 | vid, idm |
| 301 | ); |
| 302 | idv = db_last_insert_rowid(); |
| 303 | db_multi_exec("UPDATE fv SET idv=%d WHERE rowid=%d", idv, rowid); |
| 304 | zName = db_column_text(&q, 2); |
| 305 | fossil_print("ADDED %s\n", zName); |
| 306 | if( !nochangeFlag ){ |
| 307 | undo_save(zName); |
| 308 | vfile_to_disk(0, idm, 0, 0); |
| 309 | } |
| 310 | } |
| @@ -322,11 +322,11 @@ | |
| 322 | while( db_step(&q)==SQLITE_ROW ){ |
| 323 | int idv = db_column_int(&q, 0); |
| 324 | int ridm = db_column_int(&q, 1); |
| 325 | const char *zName = db_column_text(&q, 2); |
| 326 | /* Copy content from idm over into idv. Overwrite idv. */ |
| 327 | fossil_print("UPDATE %s\n", zName); |
| 328 | if( !nochangeFlag ){ |
| 329 | undo_save(zName); |
| 330 | db_multi_exec( |
| 331 | "UPDATE vfile SET mtime=0, mrid=%d, chnged=2 WHERE id=%d", ridm, idv |
| 332 | ); |
| @@ -355,13 +355,14 @@ | |
| 355 | int rc; |
| 356 | char *zFullPath; |
| 357 | Blob m, p, r; |
| 358 | /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */ |
| 359 | if( detailFlag ){ |
| 360 | fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n", |
| 361 | zName, ridp, ridm, ridv); |
| 362 | }else{ |
| 363 | fossil_print("MERGE %s\n", zName); |
| 364 | } |
| 365 | undo_save(zName); |
| 366 | zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
| 367 | content_get(ridp, &p); |
| 368 | content_get(ridm, &m); |
| @@ -376,15 +377,15 @@ | |
| 377 | blob_write_to_file(&r, zFullPath); |
| 378 | file_setexe(zFullPath, isExe); |
| 379 | } |
| 380 | db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv); |
| 381 | if( rc>0 ){ |
| 382 | fossil_print("***** %d merge conflicts in %s\n", rc, zName); |
| 383 | nConflict++; |
| 384 | } |
| 385 | }else{ |
| 386 | fossil_print("***** Cannot merge binary file %s\n", zName); |
| 387 | nConflict++; |
| 388 | } |
| 389 | blob_reset(&p); |
| 390 | blob_reset(&m); |
| 391 | blob_reset(&r); |
| @@ -403,22 +404,22 @@ | |
| 404 | while( db_step(&q)==SQLITE_ROW ){ |
| 405 | int idv = db_column_int(&q, 0); |
| 406 | const char *zName = db_column_text(&q, 1); |
| 407 | int chnged = db_column_int(&q, 2); |
| 408 | /* Delete the file idv */ |
| 409 | fossil_print("DELETE %s\n", zName); |
| 410 | if( chnged ){ |
| 411 | fossil_warning("WARNING: local edits lost for %s\n", zName); |
| 412 | nConflict++; |
| 413 | } |
| 414 | undo_save(zName); |
| 415 | db_multi_exec( |
| 416 | "UPDATE vfile SET deleted=1 WHERE id=%d", idv |
| 417 | ); |
| 418 | if( !nochangeFlag ){ |
| 419 | char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName); |
| 420 | file_delete(zFullPath); |
| 421 | free(zFullPath); |
| 422 | } |
| 423 | } |
| 424 | db_finalize(&q); |
| 425 | |
| @@ -433,11 +434,11 @@ | |
| 434 | ); |
| 435 | while( db_step(&q)==SQLITE_ROW ){ |
| 436 | int idv = db_column_int(&q, 0); |
| 437 | const char *zOldName = db_column_text(&q, 1); |
| 438 | const char *zNewName = db_column_text(&q, 2); |
| 439 | fossil_print("RENAME %s -> %s\n", zOldName, zNewName); |
| 440 | undo_save(zOldName); |
| 441 | undo_save(zNewName); |
| 442 | db_multi_exec( |
| 443 | "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)" |
| 444 | " WHERE id=%d AND vid=%d", zNewName, idv, vid |
| @@ -444,11 +445,11 @@ | |
| 445 | ); |
| 446 | if( !nochangeFlag ){ |
| 447 | char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); |
| 448 | char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); |
| 449 | file_copy(zFullOldPath, zFullNewPath); |
| 450 | file_delete(zFullOldPath); |
| 451 | free(zFullNewPath); |
| 452 | free(zFullOldPath); |
| 453 | } |
| 454 | } |
| 455 | db_finalize(&q); |
| @@ -455,11 +456,12 @@ | |
| 456 | |
| 457 | |
| 458 | /* Report on conflicts |
| 459 | */ |
| 460 | if( nConflict && !nochangeFlag ){ |
| 461 | fossil_warning( |
| 462 | "WARNING: merge conflicts - see messages above for details.\n"); |
| 463 | } |
| 464 | |
| 465 | /* |
| 466 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 467 | */ |
| 468 |
+19
-20
| --- src/merge3.c | ||
| +++ src/merge3.c | ||
| @@ -153,15 +153,17 @@ | ||
| 153 | 153 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 154 | 154 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 155 | 155 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 156 | 156 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 157 | 157 | static const char zBegin[] = |
| 158 | - "<<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<<\n"; | |
| 159 | - static const char zMid[] = | |
| 160 | - "======= original content above; conflict below =============\n"; | |
| 158 | + "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n"; | |
| 159 | + static const char zMid1[] = | |
| 160 | + "======= COMMON ANCESTOR content follows ============================\n"; | |
| 161 | + static const char zMid2[] = | |
| 162 | + "======= MERGED IN content follows ==================================\n"; | |
| 161 | 163 | static const char zEnd[] = |
| 162 | - ">>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>>\n"; | |
| 164 | + ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; | |
| 163 | 165 | |
| 164 | 166 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 165 | 167 | |
| 166 | 168 | /* Compute the edits that occur from pPivot => pV1 (into aC1) |
| 167 | 169 | ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is |
| @@ -192,11 +194,11 @@ | ||
| 192 | 194 | DEBUG( |
| 193 | 195 | for(i1=0; i1<limit1; i1+=3){ |
| 194 | 196 | printf("c1: %4d %4d %4d\n", aC1[i1], aC1[i1+1], aC1[i1+2]); |
| 195 | 197 | } |
| 196 | 198 | for(i2=0; i2<limit2; i2+=3){ |
| 197 | - printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); | |
| 199 | + printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); | |
| 198 | 200 | } |
| 199 | 201 | ) |
| 200 | 202 | |
| 201 | 203 | /* Loop over the two edit vectors and use them to compute merged text |
| 202 | 204 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| @@ -264,15 +266,16 @@ | ||
| 264 | 266 | sz++; |
| 265 | 267 | } |
| 266 | 268 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 267 | 269 | blob_appendf(pOut, zBegin); |
| 268 | 270 | i1 = output_one_side(pOut, pV1, aC1, i1, sz); |
| 269 | - blob_appendf(pOut, zMid); | |
| 271 | + blob_appendf(pOut, zMid1); | |
| 272 | + blob_copy_lines(pOut, pPivot, sz); | |
| 273 | + blob_appendf(pOut, zMid2); | |
| 270 | 274 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 271 | 275 | blob_appendf(pOut, zEnd); |
| 272 | - blob_copy_lines(0, pPivot, sz); | |
| 273 | - } | |
| 276 | + } | |
| 274 | 277 | |
| 275 | 278 | /* If we are finished with an edit triple, advance to the next |
| 276 | 279 | ** triple. |
| 277 | 280 | */ |
| 278 | 281 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| @@ -311,25 +314,21 @@ | ||
| 311 | 314 | Blob pivot, v1, v2, merged; |
| 312 | 315 | if( g.argc!=6 ){ |
| 313 | 316 | usage("PIVOT V1 V2 MERGED"); |
| 314 | 317 | } |
| 315 | 318 | if( blob_read_from_file(&pivot, g.argv[2])<0 ){ |
| 316 | - fprintf(stderr,"cannot read %s\n", g.argv[2]); | |
| 317 | - fossil_exit(1); | |
| 319 | + fossil_fatal("cannot read %s\n", g.argv[2]); | |
| 318 | 320 | } |
| 319 | 321 | if( blob_read_from_file(&v1, g.argv[3])<0 ){ |
| 320 | - fprintf(stderr,"cannot read %s\n", g.argv[3]); | |
| 321 | - fossil_exit(1); | |
| 322 | + fossil_fatal("cannot read %s\n", g.argv[3]); | |
| 322 | 323 | } |
| 323 | 324 | if( blob_read_from_file(&v2, g.argv[4])<0 ){ |
| 324 | - fprintf(stderr,"cannot read %s\n", g.argv[4]); | |
| 325 | - fossil_exit(1); | |
| 325 | + fossil_fatal("cannot read %s\n", g.argv[4]); | |
| 326 | 326 | } |
| 327 | 327 | blob_merge(&pivot, &v1, &v2, &merged); |
| 328 | 328 | if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){ |
| 329 | - fprintf(stderr,"cannot write %s\n", g.argv[4]); | |
| 330 | - fossil_exit(1); | |
| 329 | + fossil_fatal("cannot write %s\n", g.argv[4]); | |
| 331 | 330 | } |
| 332 | 331 | blob_reset(&pivot); |
| 333 | 332 | blob_reset(&v1); |
| 334 | 333 | blob_reset(&v2); |
| 335 | 334 | blob_reset(&merged); |
| @@ -425,14 +424,14 @@ | ||
| 425 | 424 | zCmd = string_subst(zGMerge, 8, azSubst); |
| 426 | 425 | printf("%s\n", zCmd); fflush(stdout); |
| 427 | 426 | fossil_system(zCmd); |
| 428 | 427 | if( file_size(zOut)>=0 ){ |
| 429 | 428 | blob_read_from_file(pOut, zOut); |
| 430 | - unlink(zPivot); | |
| 431 | - unlink(zOrig); | |
| 432 | - unlink(zOther); | |
| 433 | - unlink(zOut); | |
| 429 | + file_delete(zPivot); | |
| 430 | + file_delete(zOrig); | |
| 431 | + file_delete(zOther); | |
| 432 | + file_delete(zOut); | |
| 434 | 433 | } |
| 435 | 434 | fossil_free(zCmd); |
| 436 | 435 | fossil_free(zOut); |
| 437 | 436 | } |
| 438 | 437 | fossil_free(zPivot); |
| 439 | 438 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -153,15 +153,17 @@ | |
| 153 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 154 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 155 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 156 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 157 | static const char zBegin[] = |
| 158 | "<<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<<\n"; |
| 159 | static const char zMid[] = |
| 160 | "======= original content above; conflict below =============\n"; |
| 161 | static const char zEnd[] = |
| 162 | ">>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>>\n"; |
| 163 | |
| 164 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 165 | |
| 166 | /* Compute the edits that occur from pPivot => pV1 (into aC1) |
| 167 | ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is |
| @@ -192,11 +194,11 @@ | |
| 192 | DEBUG( |
| 193 | for(i1=0; i1<limit1; i1+=3){ |
| 194 | printf("c1: %4d %4d %4d\n", aC1[i1], aC1[i1+1], aC1[i1+2]); |
| 195 | } |
| 196 | for(i2=0; i2<limit2; i2+=3){ |
| 197 | printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); |
| 198 | } |
| 199 | ) |
| 200 | |
| 201 | /* Loop over the two edit vectors and use them to compute merged text |
| 202 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| @@ -264,15 +266,16 @@ | |
| 264 | sz++; |
| 265 | } |
| 266 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 267 | blob_appendf(pOut, zBegin); |
| 268 | i1 = output_one_side(pOut, pV1, aC1, i1, sz); |
| 269 | blob_appendf(pOut, zMid); |
| 270 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 271 | blob_appendf(pOut, zEnd); |
| 272 | blob_copy_lines(0, pPivot, sz); |
| 273 | } |
| 274 | |
| 275 | /* If we are finished with an edit triple, advance to the next |
| 276 | ** triple. |
| 277 | */ |
| 278 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| @@ -311,25 +314,21 @@ | |
| 311 | Blob pivot, v1, v2, merged; |
| 312 | if( g.argc!=6 ){ |
| 313 | usage("PIVOT V1 V2 MERGED"); |
| 314 | } |
| 315 | if( blob_read_from_file(&pivot, g.argv[2])<0 ){ |
| 316 | fprintf(stderr,"cannot read %s\n", g.argv[2]); |
| 317 | fossil_exit(1); |
| 318 | } |
| 319 | if( blob_read_from_file(&v1, g.argv[3])<0 ){ |
| 320 | fprintf(stderr,"cannot read %s\n", g.argv[3]); |
| 321 | fossil_exit(1); |
| 322 | } |
| 323 | if( blob_read_from_file(&v2, g.argv[4])<0 ){ |
| 324 | fprintf(stderr,"cannot read %s\n", g.argv[4]); |
| 325 | fossil_exit(1); |
| 326 | } |
| 327 | blob_merge(&pivot, &v1, &v2, &merged); |
| 328 | if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){ |
| 329 | fprintf(stderr,"cannot write %s\n", g.argv[4]); |
| 330 | fossil_exit(1); |
| 331 | } |
| 332 | blob_reset(&pivot); |
| 333 | blob_reset(&v1); |
| 334 | blob_reset(&v2); |
| 335 | blob_reset(&merged); |
| @@ -425,14 +424,14 @@ | |
| 425 | zCmd = string_subst(zGMerge, 8, azSubst); |
| 426 | printf("%s\n", zCmd); fflush(stdout); |
| 427 | fossil_system(zCmd); |
| 428 | if( file_size(zOut)>=0 ){ |
| 429 | blob_read_from_file(pOut, zOut); |
| 430 | unlink(zPivot); |
| 431 | unlink(zOrig); |
| 432 | unlink(zOther); |
| 433 | unlink(zOut); |
| 434 | } |
| 435 | fossil_free(zCmd); |
| 436 | fossil_free(zOut); |
| 437 | } |
| 438 | fossil_free(zPivot); |
| 439 |
| --- src/merge3.c | |
| +++ src/merge3.c | |
| @@ -153,15 +153,17 @@ | |
| 153 | int i1, i2; /* Index into aC1[] and aC2[] */ |
| 154 | int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ |
| 155 | int limit1, limit2; /* Sizes of aC1[] and aC2[] */ |
| 156 | int nConflict = 0; /* Number of merge conflicts seen so far */ |
| 157 | static const char zBegin[] = |
| 158 | "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n"; |
| 159 | static const char zMid1[] = |
| 160 | "======= COMMON ANCESTOR content follows ============================\n"; |
| 161 | static const char zMid2[] = |
| 162 | "======= MERGED IN content follows ==================================\n"; |
| 163 | static const char zEnd[] = |
| 164 | ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; |
| 165 | |
| 166 | blob_zero(pOut); /* Merge results stored in pOut */ |
| 167 | |
| 168 | /* Compute the edits that occur from pPivot => pV1 (into aC1) |
| 169 | ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is |
| @@ -192,11 +194,11 @@ | |
| 194 | DEBUG( |
| 195 | for(i1=0; i1<limit1; i1+=3){ |
| 196 | printf("c1: %4d %4d %4d\n", aC1[i1], aC1[i1+1], aC1[i1+2]); |
| 197 | } |
| 198 | for(i2=0; i2<limit2; i2+=3){ |
| 199 | printf("c2: %4d %4d %4d\n", aC2[i2], aC2[i2+1], aC2[i2+2]); |
| 200 | } |
| 201 | ) |
| 202 | |
| 203 | /* Loop over the two edit vectors and use them to compute merged text |
| 204 | ** which is written into pOut. i1 and i2 are multiples of 3 which are |
| @@ -264,15 +266,16 @@ | |
| 266 | sz++; |
| 267 | } |
| 268 | DEBUG( printf("CONFLICT %d\n", sz); ) |
| 269 | blob_appendf(pOut, zBegin); |
| 270 | i1 = output_one_side(pOut, pV1, aC1, i1, sz); |
| 271 | blob_appendf(pOut, zMid1); |
| 272 | blob_copy_lines(pOut, pPivot, sz); |
| 273 | blob_appendf(pOut, zMid2); |
| 274 | i2 = output_one_side(pOut, pV2, aC2, i2, sz); |
| 275 | blob_appendf(pOut, zEnd); |
| 276 | } |
| 277 | |
| 278 | /* If we are finished with an edit triple, advance to the next |
| 279 | ** triple. |
| 280 | */ |
| 281 | if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; |
| @@ -311,25 +314,21 @@ | |
| 314 | Blob pivot, v1, v2, merged; |
| 315 | if( g.argc!=6 ){ |
| 316 | usage("PIVOT V1 V2 MERGED"); |
| 317 | } |
| 318 | if( blob_read_from_file(&pivot, g.argv[2])<0 ){ |
| 319 | fossil_fatal("cannot read %s\n", g.argv[2]); |
| 320 | } |
| 321 | if( blob_read_from_file(&v1, g.argv[3])<0 ){ |
| 322 | fossil_fatal("cannot read %s\n", g.argv[3]); |
| 323 | } |
| 324 | if( blob_read_from_file(&v2, g.argv[4])<0 ){ |
| 325 | fossil_fatal("cannot read %s\n", g.argv[4]); |
| 326 | } |
| 327 | blob_merge(&pivot, &v1, &v2, &merged); |
| 328 | if( blob_write_to_file(&merged, g.argv[5])<blob_size(&merged) ){ |
| 329 | fossil_fatal("cannot write %s\n", g.argv[4]); |
| 330 | } |
| 331 | blob_reset(&pivot); |
| 332 | blob_reset(&v1); |
| 333 | blob_reset(&v2); |
| 334 | blob_reset(&merged); |
| @@ -425,14 +424,14 @@ | |
| 424 | zCmd = string_subst(zGMerge, 8, azSubst); |
| 425 | printf("%s\n", zCmd); fflush(stdout); |
| 426 | fossil_system(zCmd); |
| 427 | if( file_size(zOut)>=0 ){ |
| 428 | blob_read_from_file(pOut, zOut); |
| 429 | file_delete(zPivot); |
| 430 | file_delete(zOrig); |
| 431 | file_delete(zOther); |
| 432 | file_delete(zOut); |
| 433 | } |
| 434 | fossil_free(zCmd); |
| 435 | fossil_free(zOut); |
| 436 | } |
| 437 | fossil_free(zPivot); |
| 438 |
+5
-5
| --- src/name.c | ||
| +++ src/name.c | ||
| @@ -201,12 +201,12 @@ | ||
| 201 | 201 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 202 | 202 | "(SELECT pid FROM plink WHERE cid=%d AND isprim)", |
| 203 | 203 | vid); |
| 204 | 204 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 205 | 205 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 206 | - "(SELECT cid FROM plink WHERE pid=%d AND isprim" | |
| 207 | - " ORDER BY mtime DESC)", | |
| 206 | + "(SELECT cid FROM plink WHERE pid=%d" | |
| 207 | + " ORDER BY isprim DESC, mtime DESC)", | |
| 208 | 208 | vid); |
| 209 | 209 | } |
| 210 | 210 | } |
| 211 | 211 | } |
| 212 | 212 | return zUuid; |
| @@ -267,16 +267,16 @@ | ||
| 267 | 267 | int i; |
| 268 | 268 | Blob name; |
| 269 | 269 | db_must_be_within_tree(); |
| 270 | 270 | for(i=2; i<g.argc; i++){ |
| 271 | 271 | blob_init(&name, g.argv[i], -1); |
| 272 | - printf("%s -> ", g.argv[i]); | |
| 272 | + fossil_print("%s -> ", g.argv[i]); | |
| 273 | 273 | if( name_to_uuid(&name, 1) ){ |
| 274 | - printf("ERROR: %s\n", g.zErrMsg); | |
| 274 | + fossil_print("ERROR: %s\n", g.zErrMsg); | |
| 275 | 275 | fossil_error_reset(); |
| 276 | 276 | }else{ |
| 277 | - printf("%s\n", blob_buffer(&name)); | |
| 277 | + fossil_print("%s\n", blob_buffer(&name)); | |
| 278 | 278 | } |
| 279 | 279 | blob_reset(&name); |
| 280 | 280 | } |
| 281 | 281 | } |
| 282 | 282 | |
| 283 | 283 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -201,12 +201,12 @@ | |
| 201 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 202 | "(SELECT pid FROM plink WHERE cid=%d AND isprim)", |
| 203 | vid); |
| 204 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 205 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 206 | "(SELECT cid FROM plink WHERE pid=%d AND isprim" |
| 207 | " ORDER BY mtime DESC)", |
| 208 | vid); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | return zUuid; |
| @@ -267,16 +267,16 @@ | |
| 267 | int i; |
| 268 | Blob name; |
| 269 | db_must_be_within_tree(); |
| 270 | for(i=2; i<g.argc; i++){ |
| 271 | blob_init(&name, g.argv[i], -1); |
| 272 | printf("%s -> ", g.argv[i]); |
| 273 | if( name_to_uuid(&name, 1) ){ |
| 274 | printf("ERROR: %s\n", g.zErrMsg); |
| 275 | fossil_error_reset(); |
| 276 | }else{ |
| 277 | printf("%s\n", blob_buffer(&name)); |
| 278 | } |
| 279 | blob_reset(&name); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 |
| --- src/name.c | |
| +++ src/name.c | |
| @@ -201,12 +201,12 @@ | |
| 201 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 202 | "(SELECT pid FROM plink WHERE cid=%d AND isprim)", |
| 203 | vid); |
| 204 | }else if( fossil_strcmp(zTag, "next")==0 ){ |
| 205 | zUuid = db_text(0, "SELECT uuid FROM blob WHERE rid=" |
| 206 | "(SELECT cid FROM plink WHERE pid=%d" |
| 207 | " ORDER BY isprim DESC, mtime DESC)", |
| 208 | vid); |
| 209 | } |
| 210 | } |
| 211 | } |
| 212 | return zUuid; |
| @@ -267,16 +267,16 @@ | |
| 267 | int i; |
| 268 | Blob name; |
| 269 | db_must_be_within_tree(); |
| 270 | for(i=2; i<g.argc; i++){ |
| 271 | blob_init(&name, g.argv[i], -1); |
| 272 | fossil_print("%s -> ", g.argv[i]); |
| 273 | if( name_to_uuid(&name, 1) ){ |
| 274 | fossil_print("ERROR: %s\n", g.zErrMsg); |
| 275 | fossil_error_reset(); |
| 276 | }else{ |
| 277 | fossil_print("%s\n", blob_buffer(&name)); |
| 278 | } |
| 279 | blob_reset(&name); |
| 280 | } |
| 281 | } |
| 282 | |
| 283 |
+10
-9
| --- src/path.c | ||
| +++ src/path.c | ||
| @@ -213,16 +213,17 @@ | ||
| 213 | 213 | z = db_text(0, |
| 214 | 214 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 215 | 215 | " FROM blob, event" |
| 216 | 216 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 217 | 217 | p->rid, p->rid); |
| 218 | - printf("%4d: %s", n, z); | |
| 218 | + fossil_print("%4d: %s", n, z); | |
| 219 | 219 | fossil_free(z); |
| 220 | 220 | if( p->u.pTo ){ |
| 221 | - printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child"); | |
| 221 | + fossil_print(" is a %s of\n", | |
| 222 | + p->u.pTo->fromIsParent ? "parent" : "child"); | |
| 222 | 223 | }else{ |
| 223 | - printf("\n"); | |
| 224 | + fossil_print("\n"); | |
| 224 | 225 | } |
| 225 | 226 | } |
| 226 | 227 | } |
| 227 | 228 | |
| 228 | 229 | /* |
| @@ -312,16 +313,16 @@ | ||
| 312 | 313 | z = db_text(0, |
| 313 | 314 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 314 | 315 | " FROM blob, event" |
| 315 | 316 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 316 | 317 | p->rid, p->rid); |
| 317 | - printf("%4d: %s", n, z); | |
| 318 | + fossil_print("%4d: %s", n, z); | |
| 318 | 319 | fossil_free(z); |
| 319 | - if( p->rid==iFrom ) printf(" VERSION1"); | |
| 320 | - if( p->rid==iTo ) printf(" VERSION2"); | |
| 321 | - if( p->rid==iPivot ) printf(" PIVOT"); | |
| 322 | - printf("\n"); | |
| 320 | + if( p->rid==iFrom ) fossil_print(" VERSION1"); | |
| 321 | + if( p->rid==iTo ) fossil_print(" VERSION2"); | |
| 322 | + if( p->rid==iPivot ) fossil_print(" PIVOT"); | |
| 323 | + fossil_print("\n"); | |
| 323 | 324 | } |
| 324 | 325 | } |
| 325 | 326 | |
| 326 | 327 | |
| 327 | 328 | /* |
| @@ -445,11 +446,11 @@ | ||
| 445 | 446 | for(i=0; i<nChng; i++){ |
| 446 | 447 | char *zFrom, *zTo; |
| 447 | 448 | |
| 448 | 449 | zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); |
| 449 | 450 | zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); |
| 450 | - printf("[%s] -> [%s]\n", zFrom, zTo); | |
| 451 | + fossil_print("[%s] -> [%s]\n", zFrom, zTo); | |
| 451 | 452 | fossil_free(zFrom); |
| 452 | 453 | fossil_free(zTo); |
| 453 | 454 | } |
| 454 | 455 | fossil_free(aChng); |
| 455 | 456 | } |
| 456 | 457 |
| --- src/path.c | |
| +++ src/path.c | |
| @@ -213,16 +213,17 @@ | |
| 213 | z = db_text(0, |
| 214 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 215 | " FROM blob, event" |
| 216 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 217 | p->rid, p->rid); |
| 218 | printf("%4d: %s", n, z); |
| 219 | fossil_free(z); |
| 220 | if( p->u.pTo ){ |
| 221 | printf(" is a %s of\n", p->u.pTo->fromIsParent ? "parent" : "child"); |
| 222 | }else{ |
| 223 | printf("\n"); |
| 224 | } |
| 225 | } |
| 226 | } |
| 227 | |
| 228 | /* |
| @@ -312,16 +313,16 @@ | |
| 312 | z = db_text(0, |
| 313 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 314 | " FROM blob, event" |
| 315 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 316 | p->rid, p->rid); |
| 317 | printf("%4d: %s", n, z); |
| 318 | fossil_free(z); |
| 319 | if( p->rid==iFrom ) printf(" VERSION1"); |
| 320 | if( p->rid==iTo ) printf(" VERSION2"); |
| 321 | if( p->rid==iPivot ) printf(" PIVOT"); |
| 322 | printf("\n"); |
| 323 | } |
| 324 | } |
| 325 | |
| 326 | |
| 327 | /* |
| @@ -445,11 +446,11 @@ | |
| 445 | for(i=0; i<nChng; i++){ |
| 446 | char *zFrom, *zTo; |
| 447 | |
| 448 | zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); |
| 449 | zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); |
| 450 | printf("[%s] -> [%s]\n", zFrom, zTo); |
| 451 | fossil_free(zFrom); |
| 452 | fossil_free(zTo); |
| 453 | } |
| 454 | fossil_free(aChng); |
| 455 | } |
| 456 |
| --- src/path.c | |
| +++ src/path.c | |
| @@ -213,16 +213,17 @@ | |
| 213 | z = db_text(0, |
| 214 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 215 | " FROM blob, event" |
| 216 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 217 | p->rid, p->rid); |
| 218 | fossil_print("%4d: %s", n, z); |
| 219 | fossil_free(z); |
| 220 | if( p->u.pTo ){ |
| 221 | fossil_print(" is a %s of\n", |
| 222 | p->u.pTo->fromIsParent ? "parent" : "child"); |
| 223 | }else{ |
| 224 | fossil_print("\n"); |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | |
| 229 | /* |
| @@ -312,16 +313,16 @@ | |
| 313 | z = db_text(0, |
| 314 | "SELECT substr(uuid,1,12) || ' ' || datetime(mtime)" |
| 315 | " FROM blob, event" |
| 316 | " WHERE blob.rid=%d AND event.objid=%d AND event.type='ci'", |
| 317 | p->rid, p->rid); |
| 318 | fossil_print("%4d: %s", n, z); |
| 319 | fossil_free(z); |
| 320 | if( p->rid==iFrom ) fossil_print(" VERSION1"); |
| 321 | if( p->rid==iTo ) fossil_print(" VERSION2"); |
| 322 | if( p->rid==iPivot ) fossil_print(" PIVOT"); |
| 323 | fossil_print("\n"); |
| 324 | } |
| 325 | } |
| 326 | |
| 327 | |
| 328 | /* |
| @@ -445,11 +446,11 @@ | |
| 446 | for(i=0; i<nChng; i++){ |
| 447 | char *zFrom, *zTo; |
| 448 | |
| 449 | zFrom = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); |
| 450 | zTo = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); |
| 451 | fossil_print("[%s] -> [%s]\n", zFrom, zTo); |
| 452 | fossil_free(zFrom); |
| 453 | fossil_free(zTo); |
| 454 | } |
| 455 | fossil_free(aChng); |
| 456 | } |
| 457 |
+27
-1
| --- src/printf.c | ||
| +++ src/printf.c | ||
| @@ -797,10 +797,36 @@ | ||
| 797 | 797 | void fossil_error_reset(void){ |
| 798 | 798 | free(g.zErrMsg); |
| 799 | 799 | g.zErrMsg = 0; |
| 800 | 800 | g.iErrPriority = 0; |
| 801 | 801 | } |
| 802 | + | |
| 803 | +/* | |
| 804 | +** Write to standard output or standard error. | |
| 805 | +** | |
| 806 | +** On windows, transform the output into the current terminal encoding | |
| 807 | +** if the output is going to the screen. If output is redirected into | |
| 808 | +** a file, no translation occurs. No translation ever occurs on unix. | |
| 809 | +*/ | |
| 810 | +void fossil_puts(const char *z, int toStdErr){ | |
| 811 | +#if defined(_WIN32) | |
| 812 | + static int once = 1; | |
| 813 | + static int istty[2]; | |
| 814 | + char *zToFree = 0; | |
| 815 | + if( once ){ | |
| 816 | + istty[0] = _isatty(fileno(stdout)); | |
| 817 | + istty[1] = _isatty(fileno(stderr)); | |
| 818 | + once = 0; | |
| 819 | + } | |
| 820 | + assert( toStdErr==0 || toStdErr==1 ); | |
| 821 | + if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); | |
| 822 | + fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); | |
| 823 | + free(zToFree); | |
| 824 | +#else | |
| 825 | + fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); | |
| 826 | +#endif | |
| 827 | +} | |
| 802 | 828 | |
| 803 | 829 | /* |
| 804 | 830 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| 805 | 831 | ** send the output as part of the CGI reply. If g.cgiOutput is false, |
| 806 | 832 | ** then write on standard output. |
| @@ -811,11 +837,11 @@ | ||
| 811 | 837 | if( g.cgiOutput ){ |
| 812 | 838 | cgi_vprintf(zFormat, ap); |
| 813 | 839 | }else{ |
| 814 | 840 | Blob b = empty_blob; |
| 815 | 841 | vxprintf(&b, zFormat, ap); |
| 816 | - fwrite(blob_buffer(&b), 1, blob_size(&b), stdout); | |
| 842 | + fossil_puts(blob_str(&b), 0); | |
| 817 | 843 | blob_reset(&b); |
| 818 | 844 | } |
| 819 | 845 | } |
| 820 | 846 | |
| 821 | 847 | /* |
| 822 | 848 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -797,10 +797,36 @@ | |
| 797 | void fossil_error_reset(void){ |
| 798 | free(g.zErrMsg); |
| 799 | g.zErrMsg = 0; |
| 800 | g.iErrPriority = 0; |
| 801 | } |
| 802 | |
| 803 | /* |
| 804 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| 805 | ** send the output as part of the CGI reply. If g.cgiOutput is false, |
| 806 | ** then write on standard output. |
| @@ -811,11 +837,11 @@ | |
| 811 | if( g.cgiOutput ){ |
| 812 | cgi_vprintf(zFormat, ap); |
| 813 | }else{ |
| 814 | Blob b = empty_blob; |
| 815 | vxprintf(&b, zFormat, ap); |
| 816 | fwrite(blob_buffer(&b), 1, blob_size(&b), stdout); |
| 817 | blob_reset(&b); |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | /* |
| 822 |
| --- src/printf.c | |
| +++ src/printf.c | |
| @@ -797,10 +797,36 @@ | |
| 797 | void fossil_error_reset(void){ |
| 798 | free(g.zErrMsg); |
| 799 | g.zErrMsg = 0; |
| 800 | g.iErrPriority = 0; |
| 801 | } |
| 802 | |
| 803 | /* |
| 804 | ** Write to standard output or standard error. |
| 805 | ** |
| 806 | ** On windows, transform the output into the current terminal encoding |
| 807 | ** if the output is going to the screen. If output is redirected into |
| 808 | ** a file, no translation occurs. No translation ever occurs on unix. |
| 809 | */ |
| 810 | void fossil_puts(const char *z, int toStdErr){ |
| 811 | #if defined(_WIN32) |
| 812 | static int once = 1; |
| 813 | static int istty[2]; |
| 814 | char *zToFree = 0; |
| 815 | if( once ){ |
| 816 | istty[0] = _isatty(fileno(stdout)); |
| 817 | istty[1] = _isatty(fileno(stderr)); |
| 818 | once = 0; |
| 819 | } |
| 820 | assert( toStdErr==0 || toStdErr==1 ); |
| 821 | if( istty[toStdErr] ) z = zToFree = fossil_utf8_to_console(z); |
| 822 | fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); |
| 823 | free(zToFree); |
| 824 | #else |
| 825 | fwrite(z, 1, strlen(z), toStdErr ? stderr : stdout); |
| 826 | #endif |
| 827 | } |
| 828 | |
| 829 | /* |
| 830 | ** Write output for user consumption. If g.cgiOutput is enabled, then |
| 831 | ** send the output as part of the CGI reply. If g.cgiOutput is false, |
| 832 | ** then write on standard output. |
| @@ -811,11 +837,11 @@ | |
| 837 | if( g.cgiOutput ){ |
| 838 | cgi_vprintf(zFormat, ap); |
| 839 | }else{ |
| 840 | Blob b = empty_blob; |
| 841 | vxprintf(&b, zFormat, ap); |
| 842 | fossil_puts(blob_str(&b), 0); |
| 843 | blob_reset(&b); |
| 844 | } |
| 845 | } |
| 846 | |
| 847 | /* |
| 848 |
+127
-40
| --- src/rebuild.c | ||
| +++ src/rebuild.c | ||
| @@ -22,13 +22,15 @@ | ||
| 22 | 22 | #include <assert.h> |
| 23 | 23 | #include <dirent.h> |
| 24 | 24 | #include <errno.h> |
| 25 | 25 | |
| 26 | 26 | /* |
| 27 | -** Schema changes | |
| 27 | +** Make changes to the stable part of the schema (the part that is not | |
| 28 | +** simply deleted and reconstructed on a rebuild) to bring the schema | |
| 29 | +** up to the latest. | |
| 28 | 30 | */ |
| 29 | -static const char zSchemaUpdates[] = | |
| 31 | +static const char zSchemaUpdates1[] = | |
| 30 | 32 | @ -- Index on the delta table |
| 31 | 33 | @ -- |
| 32 | 34 | @ CREATE INDEX IF NOT EXISTS delta_i1 ON delta(srcid); |
| 33 | 35 | @ |
| 34 | 36 | @ -- Artifacts that should not be processed are identified in the |
| @@ -39,41 +41,124 @@ | ||
| 39 | 41 | @ -- |
| 40 | 42 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 41 | 43 | @ -- have not artifact ID (rid) and we thus must store their full |
| 42 | 44 | @ -- UUID. |
| 43 | 45 | @ -- |
| 44 | -@ CREATE TABLE IF NOT EXISTS shun(uuid UNIQUE); | |
| 46 | +@ CREATE TABLE IF NOT EXISTS shun( | |
| 47 | +@ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form | |
| 48 | +@ mtime INTEGER, -- When added. Seconds since 1970 | |
| 49 | +@ scom TEXT -- Optional text explaining why the shun occurred | |
| 50 | +@ ); | |
| 45 | 51 | @ |
| 46 | 52 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 47 | 53 | @ -- table. |
| 48 | 54 | @ -- |
| 49 | 55 | @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY); |
| 50 | 56 | @ |
| 51 | -@ -- An entry in this table describes a database query that generates a | |
| 52 | -@ -- table of tickets. | |
| 53 | -@ -- | |
| 54 | -@ CREATE TABLE IF NOT EXISTS reportfmt( | |
| 55 | -@ rn integer primary key, -- Report number | |
| 56 | -@ owner text, -- Owner of this report format (not used) | |
| 57 | -@ title text, -- Title of this report | |
| 58 | -@ cols text, -- A color-key specification | |
| 59 | -@ sqlcode text -- An SQL SELECT statement for this report | |
| 60 | -@ ); | |
| 61 | -@ | |
| 62 | 57 | @ -- Some ticket content (such as the originators email address or contact |
| 63 | 58 | @ -- information) needs to be obscured to protect privacy. This is achieved |
| 64 | 59 | @ -- by storing an SHA1 hash of the content. For display, the hash is |
| 65 | 60 | @ -- mapped back into the original text using this table. |
| 66 | 61 | @ -- |
| 67 | 62 | @ -- This table contains sensitive information and should not be shared |
| 68 | 63 | @ -- with unauthorized users. |
| 69 | 64 | @ -- |
| 70 | 65 | @ CREATE TABLE IF NOT EXISTS concealed( |
| 71 | -@ hash TEXT PRIMARY KEY, | |
| 72 | -@ content TEXT | |
| 66 | +@ hash TEXT PRIMARY KEY, -- The SHA1 hash of content | |
| 67 | +@ mtime INTEGER, -- Time created. Seconds since 1970 | |
| 68 | +@ content TEXT -- Content intended to be concealed | |
| 69 | +@ ); | |
| 70 | +; | |
| 71 | +static const char zSchemaUpdates2[] = | |
| 72 | +@ -- An entry in this table describes a database query that generates a | |
| 73 | +@ -- table of tickets. | |
| 74 | +@ -- | |
| 75 | +@ CREATE TABLE IF NOT EXISTS reportfmt( | |
| 76 | +@ rn INTEGER PRIMARY KEY, -- Report number | |
| 77 | +@ owner TEXT, -- Owner of this report format (not used) | |
| 78 | +@ title TEXT UNIQUE, -- Title of this report | |
| 79 | +@ mtime INTEGER, -- Time last modified. Seconds since 1970 | |
| 80 | +@ cols TEXT, -- A color-key specification | |
| 81 | +@ sqlcode TEXT -- An SQL SELECT statement for this report | |
| 73 | 82 | @ ); |
| 74 | 83 | ; |
| 84 | + | |
| 85 | +static void rebuild_update_schema(void){ | |
| 86 | + int rc; | |
| 87 | + db_multi_exec(zSchemaUpdates1); | |
| 88 | + db_multi_exec(zSchemaUpdates2); | |
| 89 | + | |
| 90 | + rc = db_exists("SELECT 1 FROM sqlite_master" | |
| 91 | + " WHERE name='user' AND sql GLOB '* mtime *'"); | |
| 92 | + if( rc==0 ){ | |
| 93 | + db_multi_exec( | |
| 94 | + "CREATE TEMP TABLE temp_user AS SELECT * FROM user;" | |
| 95 | + "DROP TABLE user;" | |
| 96 | + "CREATE TABLE user(\n" | |
| 97 | + " uid INTEGER PRIMARY KEY,\n" | |
| 98 | + " login TEXT UNIQUE,\n" | |
| 99 | + " pw TEXT,\n" | |
| 100 | + " cap TEXT,\n" | |
| 101 | + " cookie TEXT,\n" | |
| 102 | + " ipaddr TEXT,\n" | |
| 103 | + " cexpire DATETIME,\n" | |
| 104 | + " info TEXT,\n" | |
| 105 | + " mtime DATE,\n" | |
| 106 | + " photo BLOB\n" | |
| 107 | + ");" | |
| 108 | + "INSERT OR IGNORE INTO user" | |
| 109 | + " SELECT uid, login, pw, cap, cookie," | |
| 110 | + " ipaddr, cexpire, info, now(), photo FROM temp_user;" | |
| 111 | + "DROP TABLE temp_user;" | |
| 112 | + ); | |
| 113 | + } | |
| 114 | + | |
| 115 | + rc = db_exists("SELECT 1 FROM sqlite_master" | |
| 116 | + " WHERE name='config' AND sql GLOB '* mtime *'"); | |
| 117 | + if( rc==0 ){ | |
| 118 | + db_multi_exec( | |
| 119 | + "ALTER TABLE config ADD COLUMN mtime INTEGER;" | |
| 120 | + "UPDATE config SET mtime=now();" | |
| 121 | + ); | |
| 122 | + } | |
| 123 | + | |
| 124 | + rc = db_exists("SELECT 1 FROM sqlite_master" | |
| 125 | + " WHERE name='shun' AND sql GLOB '* mtime *'"); | |
| 126 | + if( rc==0 ){ | |
| 127 | + db_multi_exec( | |
| 128 | + "ALTER TABLE shun ADD COLUMN mtime INTEGER;" | |
| 129 | + "ALTER TABLE shun ADD COLUMN scom TEXT;" | |
| 130 | + "UPDATE shun SET mtime=now();" | |
| 131 | + ); | |
| 132 | + } | |
| 133 | + | |
| 134 | + rc = db_exists("SELECT 1 FROM sqlite_master" | |
| 135 | + " WHERE name='reportfmt' AND sql GLOB '* mtime *'"); | |
| 136 | + if( rc==0 ){ | |
| 137 | + db_multi_exec( | |
| 138 | + "CREATE TEMP TABLE old_fmt AS SELECT * FROM reportfmt;" | |
| 139 | + "DROP TABLE reportfmt;" | |
| 140 | + ); | |
| 141 | + db_multi_exec(zSchemaUpdates2); | |
| 142 | + db_multi_exec( | |
| 143 | + "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)" | |
| 144 | + " SELECT rn, owner, title, cols, sqlcode, now() FROM old_fmt;" | |
| 145 | + "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)" | |
| 146 | + " SELECT rn, owner, title || ' (' || rn || ')', cols, sqlcode, now()" | |
| 147 | + " FROM old_fmt;" | |
| 148 | + ); | |
| 149 | + } | |
| 150 | + | |
| 151 | + rc = db_exists("SELECT 1 FROM sqlite_master" | |
| 152 | + " WHERE name='concealed' AND sql GLOB '* mtime *'"); | |
| 153 | + if( rc==0 ){ | |
| 154 | + db_multi_exec( | |
| 155 | + "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" | |
| 156 | + "UPDATE concealed SET mtime=now();" | |
| 157 | + ); | |
| 158 | + } | |
| 159 | +} | |
| 75 | 160 | |
| 76 | 161 | /* |
| 77 | 162 | ** Variables used to store state information about an on-going "rebuild" |
| 78 | 163 | ** or "deconstruct". |
| 79 | 164 | */ |
| @@ -91,11 +176,11 @@ | ||
| 91 | 176 | ** The input is actually the permill complete. |
| 92 | 177 | */ |
| 93 | 178 | static void percent_complete(int permill){ |
| 94 | 179 | static int lastOutput = -1; |
| 95 | 180 | if( permill>lastOutput ){ |
| 96 | - printf(" %d.%d%% complete...\r", permill/10, permill%10); | |
| 181 | + fossil_print(" %d.%d%% complete...\r", permill/10, permill%10); | |
| 97 | 182 | fflush(stdout); |
| 98 | 183 | lastOutput = permill; |
| 99 | 184 | } |
| 100 | 185 | } |
| 101 | 186 | |
| @@ -256,11 +341,11 @@ | ||
| 256 | 341 | ttyOutput = doOut; |
| 257 | 342 | processCnt = 0; |
| 258 | 343 | if (!g.fQuiet) { |
| 259 | 344 | percent_complete(0); |
| 260 | 345 | } |
| 261 | - db_multi_exec(zSchemaUpdates); | |
| 346 | + rebuild_update_schema(); | |
| 262 | 347 | for(;;){ |
| 263 | 348 | zTable = db_text(0, |
| 264 | 349 | "SELECT name FROM sqlite_master /*scan*/" |
| 265 | 350 | " WHERE type='table'" |
| 266 | 351 | " AND name NOT IN ('blob','delta','rcvfrom','user'," |
| @@ -335,11 +420,11 @@ | ||
| 335 | 420 | if( !g.fQuiet && totalSize>0 ){ |
| 336 | 421 | processCnt += incrSize; |
| 337 | 422 | percent_complete((processCnt*1000)/totalSize); |
| 338 | 423 | } |
| 339 | 424 | if(!g.fQuiet && ttyOutput ){ |
| 340 | - printf("\n"); | |
| 425 | + fossil_print("\n"); | |
| 341 | 426 | } |
| 342 | 427 | return errCnt; |
| 343 | 428 | } |
| 344 | 429 | |
| 345 | 430 | /* |
| @@ -459,37 +544,39 @@ | ||
| 459 | 544 | } |
| 460 | 545 | db_begin_transaction(); |
| 461 | 546 | ttyOutput = 1; |
| 462 | 547 | errCnt = rebuild_db(randomizeFlag, 1, doClustering); |
| 463 | 548 | db_multi_exec( |
| 464 | - "REPLACE INTO config(name,value) VALUES('content-schema','%s');" | |
| 465 | - "REPLACE INTO config(name,value) VALUES('aux-schema','%s');", | |
| 549 | + "REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());" | |
| 550 | + "REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());", | |
| 466 | 551 | CONTENT_SCHEMA, AUX_SCHEMA |
| 467 | 552 | ); |
| 468 | 553 | if( errCnt && !forceFlag ){ |
| 469 | - printf("%d errors. Rolling back changes. Use --force to force a commit.\n", | |
| 470 | - errCnt); | |
| 554 | + fossil_print( | |
| 555 | + "%d errors. Rolling back changes. Use --force to force a commit.\n", | |
| 556 | + errCnt | |
| 557 | + ); | |
| 471 | 558 | db_end_transaction(1); |
| 472 | 559 | }else{ |
| 473 | 560 | if( runCompress ){ |
| 474 | - printf("Extra delta compression... "); fflush(stdout); | |
| 561 | + fossil_print("Extra delta compression... "); fflush(stdout); | |
| 475 | 562 | extra_deltification(); |
| 476 | 563 | runVacuum = 1; |
| 477 | 564 | } |
| 478 | 565 | if( omitVerify ) verify_cancel(); |
| 479 | 566 | db_end_transaction(0); |
| 480 | - if( runCompress ) printf("done\n"); | |
| 567 | + if( runCompress ) fossil_print("done\n"); | |
| 481 | 568 | db_close(0); |
| 482 | 569 | db_open_repository(g.zRepositoryName); |
| 483 | 570 | if( newPagesize ){ |
| 484 | 571 | db_multi_exec("PRAGMA page_size=%d", newPagesize); |
| 485 | 572 | runVacuum = 1; |
| 486 | 573 | } |
| 487 | 574 | if( runVacuum ){ |
| 488 | - printf("Vacuuming the database... "); fflush(stdout); | |
| 575 | + fossil_print("Vacuuming the database... "); fflush(stdout); | |
| 489 | 576 | db_multi_exec("VACUUM"); |
| 490 | - printf("done\n"); | |
| 577 | + fossil_print("done\n"); | |
| 491 | 578 | } |
| 492 | 579 | if( activateWal ){ |
| 493 | 580 | db_multi_exec("PRAGMA journal_mode=WAL;"); |
| 494 | 581 | } |
| 495 | 582 | } |
| @@ -593,16 +680,16 @@ | ||
| 593 | 680 | manifest_destroy(p); |
| 594 | 681 | } |
| 595 | 682 | n = db_int(0, "SELECT count(*) FROM /*scan*/" |
| 596 | 683 | " (SELECT rid FROM blob EXCEPT SELECT x FROM xdone)"); |
| 597 | 684 | if( n==0 ){ |
| 598 | - printf("all artifacts reachable through clusters\n"); | |
| 685 | + fossil_print("all artifacts reachable through clusters\n"); | |
| 599 | 686 | }else{ |
| 600 | - printf("%d unreachable artifacts:\n", n); | |
| 687 | + fossil_print("%d unreachable artifacts:\n", n); | |
| 601 | 688 | db_prepare(&q, "SELECT rid, uuid FROM blob WHERE rid NOT IN xdone"); |
| 602 | 689 | while( db_step(&q)==SQLITE_ROW ){ |
| 603 | - printf(" %3d %s\n", db_column_int(&q,0), db_column_text(&q,1)); | |
| 690 | + fossil_print(" %3d %s\n", db_column_int(&q,0), db_column_text(&q,1)); | |
| 604 | 691 | } |
| 605 | 692 | db_finalize(&q); |
| 606 | 693 | } |
| 607 | 694 | } |
| 608 | 695 | |
| @@ -712,11 +799,11 @@ | ||
| 712 | 799 | } |
| 713 | 800 | content_put(&aContent); |
| 714 | 801 | blob_reset(&path); |
| 715 | 802 | blob_reset(&aContent); |
| 716 | 803 | free(zSubpath); |
| 717 | - printf("\r%d", ++nFileRead); | |
| 804 | + fossil_print("\r%d", ++nFileRead); | |
| 718 | 805 | fflush(stdout); |
| 719 | 806 | } |
| 720 | 807 | closedir(d); |
| 721 | 808 | }else { |
| 722 | 809 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| @@ -739,22 +826,22 @@ | ||
| 739 | 826 | char *zPassword; |
| 740 | 827 | if( g.argc!=4 ){ |
| 741 | 828 | usage("FILENAME DIRECTORY"); |
| 742 | 829 | } |
| 743 | 830 | if( file_isdir(g.argv[3])!=1 ){ |
| 744 | - printf("\"%s\" is not a directory\n\n", g.argv[3]); | |
| 831 | + fossil_print("\"%s\" is not a directory\n\n", g.argv[3]); | |
| 745 | 832 | usage("FILENAME DIRECTORY"); |
| 746 | 833 | } |
| 747 | 834 | db_create_repository(g.argv[2]); |
| 748 | 835 | db_open_repository(g.argv[2]); |
| 749 | 836 | db_open_config(0); |
| 750 | 837 | db_begin_transaction(); |
| 751 | 838 | db_initial_setup(0, 0, 1); |
| 752 | 839 | |
| 753 | - printf("Reading files from directory \"%s\"...\n", g.argv[3]); | |
| 840 | + fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); | |
| 754 | 841 | recon_read_dir(g.argv[3]); |
| 755 | - printf("\nBuilding the Fossil repository...\n"); | |
| 842 | + fossil_print("\nBuilding the Fossil repository...\n"); | |
| 756 | 843 | |
| 757 | 844 | rebuild_db(0, 1, 1); |
| 758 | 845 | |
| 759 | 846 | /* Reconstruct the private table. The private table contains the rid |
| 760 | 847 | ** of every manifest that is tagged with "private" and every file that |
| @@ -776,14 +863,14 @@ | ||
| 776 | 863 | ** long time. |
| 777 | 864 | */ |
| 778 | 865 | verify_cancel(); |
| 779 | 866 | |
| 780 | 867 | db_end_transaction(0); |
| 781 | - printf("project-id: %s\n", db_get("project-code", 0)); | |
| 782 | - printf("server-id: %s\n", db_get("server-code", 0)); | |
| 868 | + fossil_print("project-id: %s\n", db_get("project-code", 0)); | |
| 869 | + fossil_print("server-id: %s\n", db_get("server-code", 0)); | |
| 783 | 870 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 784 | - printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); | |
| 871 | + fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); | |
| 785 | 872 | } |
| 786 | 873 | |
| 787 | 874 | /* |
| 788 | 875 | ** COMMAND: deconstruct |
| 789 | 876 | ** |
| @@ -824,11 +911,11 @@ | ||
| 824 | 911 | }else{ |
| 825 | 912 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 826 | 913 | } |
| 827 | 914 | } |
| 828 | 915 | #ifndef _WIN32 |
| 829 | - if( access(zDestDir, W_OK) ){ | |
| 916 | + if( file_access(zDestDir, W_OK) ){ | |
| 830 | 917 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 831 | 918 | } |
| 832 | 919 | #else |
| 833 | 920 | /* write access on windows is not checked, errors will be |
| 834 | 921 | ** dected on blob_write_to_file |
| @@ -843,11 +930,11 @@ | ||
| 843 | 930 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 844 | 931 | bag_init(&bagDone); |
| 845 | 932 | ttyOutput = 1; |
| 846 | 933 | processCnt = 0; |
| 847 | 934 | if (!g.fQuiet) { |
| 848 | - printf("0 (0%%)...\r"); | |
| 935 | + fossil_print("0 (0%%)...\r"); | |
| 849 | 936 | fflush(stdout); |
| 850 | 937 | } |
| 851 | 938 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 852 | 939 | db_prepare(&s, |
| 853 | 940 | "SELECT rid, size FROM blob /*scan*/" |
| @@ -879,12 +966,12 @@ | ||
| 879 | 966 | } |
| 880 | 967 | } |
| 881 | 968 | } |
| 882 | 969 | db_finalize(&s); |
| 883 | 970 | if(!g.fQuiet && ttyOutput ){ |
| 884 | - printf("\n"); | |
| 971 | + fossil_print("\n"); | |
| 885 | 972 | } |
| 886 | 973 | |
| 887 | 974 | /* free filename format string */ |
| 888 | 975 | free(zFNameFormat); |
| 889 | 976 | zFNameFormat = 0; |
| 890 | 977 | } |
| 891 | 978 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -22,13 +22,15 @@ | |
| 22 | #include <assert.h> |
| 23 | #include <dirent.h> |
| 24 | #include <errno.h> |
| 25 | |
| 26 | /* |
| 27 | ** Schema changes |
| 28 | */ |
| 29 | static const char zSchemaUpdates[] = |
| 30 | @ -- Index on the delta table |
| 31 | @ -- |
| 32 | @ CREATE INDEX IF NOT EXISTS delta_i1 ON delta(srcid); |
| 33 | @ |
| 34 | @ -- Artifacts that should not be processed are identified in the |
| @@ -39,41 +41,124 @@ | |
| 39 | @ -- |
| 40 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 41 | @ -- have not artifact ID (rid) and we thus must store their full |
| 42 | @ -- UUID. |
| 43 | @ -- |
| 44 | @ CREATE TABLE IF NOT EXISTS shun(uuid UNIQUE); |
| 45 | @ |
| 46 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 47 | @ -- table. |
| 48 | @ -- |
| 49 | @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY); |
| 50 | @ |
| 51 | @ -- An entry in this table describes a database query that generates a |
| 52 | @ -- table of tickets. |
| 53 | @ -- |
| 54 | @ CREATE TABLE IF NOT EXISTS reportfmt( |
| 55 | @ rn integer primary key, -- Report number |
| 56 | @ owner text, -- Owner of this report format (not used) |
| 57 | @ title text, -- Title of this report |
| 58 | @ cols text, -- A color-key specification |
| 59 | @ sqlcode text -- An SQL SELECT statement for this report |
| 60 | @ ); |
| 61 | @ |
| 62 | @ -- Some ticket content (such as the originators email address or contact |
| 63 | @ -- information) needs to be obscured to protect privacy. This is achieved |
| 64 | @ -- by storing an SHA1 hash of the content. For display, the hash is |
| 65 | @ -- mapped back into the original text using this table. |
| 66 | @ -- |
| 67 | @ -- This table contains sensitive information and should not be shared |
| 68 | @ -- with unauthorized users. |
| 69 | @ -- |
| 70 | @ CREATE TABLE IF NOT EXISTS concealed( |
| 71 | @ hash TEXT PRIMARY KEY, |
| 72 | @ content TEXT |
| 73 | @ ); |
| 74 | ; |
| 75 | |
| 76 | /* |
| 77 | ** Variables used to store state information about an on-going "rebuild" |
| 78 | ** or "deconstruct". |
| 79 | */ |
| @@ -91,11 +176,11 @@ | |
| 91 | ** The input is actually the permill complete. |
| 92 | */ |
| 93 | static void percent_complete(int permill){ |
| 94 | static int lastOutput = -1; |
| 95 | if( permill>lastOutput ){ |
| 96 | printf(" %d.%d%% complete...\r", permill/10, permill%10); |
| 97 | fflush(stdout); |
| 98 | lastOutput = permill; |
| 99 | } |
| 100 | } |
| 101 | |
| @@ -256,11 +341,11 @@ | |
| 256 | ttyOutput = doOut; |
| 257 | processCnt = 0; |
| 258 | if (!g.fQuiet) { |
| 259 | percent_complete(0); |
| 260 | } |
| 261 | db_multi_exec(zSchemaUpdates); |
| 262 | for(;;){ |
| 263 | zTable = db_text(0, |
| 264 | "SELECT name FROM sqlite_master /*scan*/" |
| 265 | " WHERE type='table'" |
| 266 | " AND name NOT IN ('blob','delta','rcvfrom','user'," |
| @@ -335,11 +420,11 @@ | |
| 335 | if( !g.fQuiet && totalSize>0 ){ |
| 336 | processCnt += incrSize; |
| 337 | percent_complete((processCnt*1000)/totalSize); |
| 338 | } |
| 339 | if(!g.fQuiet && ttyOutput ){ |
| 340 | printf("\n"); |
| 341 | } |
| 342 | return errCnt; |
| 343 | } |
| 344 | |
| 345 | /* |
| @@ -459,37 +544,39 @@ | |
| 459 | } |
| 460 | db_begin_transaction(); |
| 461 | ttyOutput = 1; |
| 462 | errCnt = rebuild_db(randomizeFlag, 1, doClustering); |
| 463 | db_multi_exec( |
| 464 | "REPLACE INTO config(name,value) VALUES('content-schema','%s');" |
| 465 | "REPLACE INTO config(name,value) VALUES('aux-schema','%s');", |
| 466 | CONTENT_SCHEMA, AUX_SCHEMA |
| 467 | ); |
| 468 | if( errCnt && !forceFlag ){ |
| 469 | printf("%d errors. Rolling back changes. Use --force to force a commit.\n", |
| 470 | errCnt); |
| 471 | db_end_transaction(1); |
| 472 | }else{ |
| 473 | if( runCompress ){ |
| 474 | printf("Extra delta compression... "); fflush(stdout); |
| 475 | extra_deltification(); |
| 476 | runVacuum = 1; |
| 477 | } |
| 478 | if( omitVerify ) verify_cancel(); |
| 479 | db_end_transaction(0); |
| 480 | if( runCompress ) printf("done\n"); |
| 481 | db_close(0); |
| 482 | db_open_repository(g.zRepositoryName); |
| 483 | if( newPagesize ){ |
| 484 | db_multi_exec("PRAGMA page_size=%d", newPagesize); |
| 485 | runVacuum = 1; |
| 486 | } |
| 487 | if( runVacuum ){ |
| 488 | printf("Vacuuming the database... "); fflush(stdout); |
| 489 | db_multi_exec("VACUUM"); |
| 490 | printf("done\n"); |
| 491 | } |
| 492 | if( activateWal ){ |
| 493 | db_multi_exec("PRAGMA journal_mode=WAL;"); |
| 494 | } |
| 495 | } |
| @@ -593,16 +680,16 @@ | |
| 593 | manifest_destroy(p); |
| 594 | } |
| 595 | n = db_int(0, "SELECT count(*) FROM /*scan*/" |
| 596 | " (SELECT rid FROM blob EXCEPT SELECT x FROM xdone)"); |
| 597 | if( n==0 ){ |
| 598 | printf("all artifacts reachable through clusters\n"); |
| 599 | }else{ |
| 600 | printf("%d unreachable artifacts:\n", n); |
| 601 | db_prepare(&q, "SELECT rid, uuid FROM blob WHERE rid NOT IN xdone"); |
| 602 | while( db_step(&q)==SQLITE_ROW ){ |
| 603 | printf(" %3d %s\n", db_column_int(&q,0), db_column_text(&q,1)); |
| 604 | } |
| 605 | db_finalize(&q); |
| 606 | } |
| 607 | } |
| 608 | |
| @@ -712,11 +799,11 @@ | |
| 712 | } |
| 713 | content_put(&aContent); |
| 714 | blob_reset(&path); |
| 715 | blob_reset(&aContent); |
| 716 | free(zSubpath); |
| 717 | printf("\r%d", ++nFileRead); |
| 718 | fflush(stdout); |
| 719 | } |
| 720 | closedir(d); |
| 721 | }else { |
| 722 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| @@ -739,22 +826,22 @@ | |
| 739 | char *zPassword; |
| 740 | if( g.argc!=4 ){ |
| 741 | usage("FILENAME DIRECTORY"); |
| 742 | } |
| 743 | if( file_isdir(g.argv[3])!=1 ){ |
| 744 | printf("\"%s\" is not a directory\n\n", g.argv[3]); |
| 745 | usage("FILENAME DIRECTORY"); |
| 746 | } |
| 747 | db_create_repository(g.argv[2]); |
| 748 | db_open_repository(g.argv[2]); |
| 749 | db_open_config(0); |
| 750 | db_begin_transaction(); |
| 751 | db_initial_setup(0, 0, 1); |
| 752 | |
| 753 | printf("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 754 | recon_read_dir(g.argv[3]); |
| 755 | printf("\nBuilding the Fossil repository...\n"); |
| 756 | |
| 757 | rebuild_db(0, 1, 1); |
| 758 | |
| 759 | /* Reconstruct the private table. The private table contains the rid |
| 760 | ** of every manifest that is tagged with "private" and every file that |
| @@ -776,14 +863,14 @@ | |
| 776 | ** long time. |
| 777 | */ |
| 778 | verify_cancel(); |
| 779 | |
| 780 | db_end_transaction(0); |
| 781 | printf("project-id: %s\n", db_get("project-code", 0)); |
| 782 | printf("server-id: %s\n", db_get("server-code", 0)); |
| 783 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 784 | printf("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| 785 | } |
| 786 | |
| 787 | /* |
| 788 | ** COMMAND: deconstruct |
| 789 | ** |
| @@ -824,11 +911,11 @@ | |
| 824 | }else{ |
| 825 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 826 | } |
| 827 | } |
| 828 | #ifndef _WIN32 |
| 829 | if( access(zDestDir, W_OK) ){ |
| 830 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 831 | } |
| 832 | #else |
| 833 | /* write access on windows is not checked, errors will be |
| 834 | ** dected on blob_write_to_file |
| @@ -843,11 +930,11 @@ | |
| 843 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 844 | bag_init(&bagDone); |
| 845 | ttyOutput = 1; |
| 846 | processCnt = 0; |
| 847 | if (!g.fQuiet) { |
| 848 | printf("0 (0%%)...\r"); |
| 849 | fflush(stdout); |
| 850 | } |
| 851 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 852 | db_prepare(&s, |
| 853 | "SELECT rid, size FROM blob /*scan*/" |
| @@ -879,12 +966,12 @@ | |
| 879 | } |
| 880 | } |
| 881 | } |
| 882 | db_finalize(&s); |
| 883 | if(!g.fQuiet && ttyOutput ){ |
| 884 | printf("\n"); |
| 885 | } |
| 886 | |
| 887 | /* free filename format string */ |
| 888 | free(zFNameFormat); |
| 889 | zFNameFormat = 0; |
| 890 | } |
| 891 |
| --- src/rebuild.c | |
| +++ src/rebuild.c | |
| @@ -22,13 +22,15 @@ | |
| 22 | #include <assert.h> |
| 23 | #include <dirent.h> |
| 24 | #include <errno.h> |
| 25 | |
| 26 | /* |
| 27 | ** Make changes to the stable part of the schema (the part that is not |
| 28 | ** simply deleted and reconstructed on a rebuild) to bring the schema |
| 29 | ** up to the latest. |
| 30 | */ |
| 31 | static const char zSchemaUpdates1[] = |
| 32 | @ -- Index on the delta table |
| 33 | @ -- |
| 34 | @ CREATE INDEX IF NOT EXISTS delta_i1 ON delta(srcid); |
| 35 | @ |
| 36 | @ -- Artifacts that should not be processed are identified in the |
| @@ -39,41 +41,124 @@ | |
| 41 | @ -- |
| 42 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 43 | @ -- have not artifact ID (rid) and we thus must store their full |
| 44 | @ -- UUID. |
| 45 | @ -- |
| 46 | @ CREATE TABLE IF NOT EXISTS shun( |
| 47 | @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form |
| 48 | @ mtime INTEGER, -- When added. Seconds since 1970 |
| 49 | @ scom TEXT -- Optional text explaining why the shun occurred |
| 50 | @ ); |
| 51 | @ |
| 52 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 53 | @ -- table. |
| 54 | @ -- |
| 55 | @ CREATE TABLE IF NOT EXISTS private(rid INTEGER PRIMARY KEY); |
| 56 | @ |
| 57 | @ -- Some ticket content (such as the originators email address or contact |
| 58 | @ -- information) needs to be obscured to protect privacy. This is achieved |
| 59 | @ -- by storing an SHA1 hash of the content. For display, the hash is |
| 60 | @ -- mapped back into the original text using this table. |
| 61 | @ -- |
| 62 | @ -- This table contains sensitive information and should not be shared |
| 63 | @ -- with unauthorized users. |
| 64 | @ -- |
| 65 | @ CREATE TABLE IF NOT EXISTS concealed( |
| 66 | @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content |
| 67 | @ mtime INTEGER, -- Time created. Seconds since 1970 |
| 68 | @ content TEXT -- Content intended to be concealed |
| 69 | @ ); |
| 70 | ; |
| 71 | static const char zSchemaUpdates2[] = |
| 72 | @ -- An entry in this table describes a database query that generates a |
| 73 | @ -- table of tickets. |
| 74 | @ -- |
| 75 | @ CREATE TABLE IF NOT EXISTS reportfmt( |
| 76 | @ rn INTEGER PRIMARY KEY, -- Report number |
| 77 | @ owner TEXT, -- Owner of this report format (not used) |
| 78 | @ title TEXT UNIQUE, -- Title of this report |
| 79 | @ mtime INTEGER, -- Time last modified. Seconds since 1970 |
| 80 | @ cols TEXT, -- A color-key specification |
| 81 | @ sqlcode TEXT -- An SQL SELECT statement for this report |
| 82 | @ ); |
| 83 | ; |
| 84 | |
| 85 | static void rebuild_update_schema(void){ |
| 86 | int rc; |
| 87 | db_multi_exec(zSchemaUpdates1); |
| 88 | db_multi_exec(zSchemaUpdates2); |
| 89 | |
| 90 | rc = db_exists("SELECT 1 FROM sqlite_master" |
| 91 | " WHERE name='user' AND sql GLOB '* mtime *'"); |
| 92 | if( rc==0 ){ |
| 93 | db_multi_exec( |
| 94 | "CREATE TEMP TABLE temp_user AS SELECT * FROM user;" |
| 95 | "DROP TABLE user;" |
| 96 | "CREATE TABLE user(\n" |
| 97 | " uid INTEGER PRIMARY KEY,\n" |
| 98 | " login TEXT UNIQUE,\n" |
| 99 | " pw TEXT,\n" |
| 100 | " cap TEXT,\n" |
| 101 | " cookie TEXT,\n" |
| 102 | " ipaddr TEXT,\n" |
| 103 | " cexpire DATETIME,\n" |
| 104 | " info TEXT,\n" |
| 105 | " mtime DATE,\n" |
| 106 | " photo BLOB\n" |
| 107 | ");" |
| 108 | "INSERT OR IGNORE INTO user" |
| 109 | " SELECT uid, login, pw, cap, cookie," |
| 110 | " ipaddr, cexpire, info, now(), photo FROM temp_user;" |
| 111 | "DROP TABLE temp_user;" |
| 112 | ); |
| 113 | } |
| 114 | |
| 115 | rc = db_exists("SELECT 1 FROM sqlite_master" |
| 116 | " WHERE name='config' AND sql GLOB '* mtime *'"); |
| 117 | if( rc==0 ){ |
| 118 | db_multi_exec( |
| 119 | "ALTER TABLE config ADD COLUMN mtime INTEGER;" |
| 120 | "UPDATE config SET mtime=now();" |
| 121 | ); |
| 122 | } |
| 123 | |
| 124 | rc = db_exists("SELECT 1 FROM sqlite_master" |
| 125 | " WHERE name='shun' AND sql GLOB '* mtime *'"); |
| 126 | if( rc==0 ){ |
| 127 | db_multi_exec( |
| 128 | "ALTER TABLE shun ADD COLUMN mtime INTEGER;" |
| 129 | "ALTER TABLE shun ADD COLUMN scom TEXT;" |
| 130 | "UPDATE shun SET mtime=now();" |
| 131 | ); |
| 132 | } |
| 133 | |
| 134 | rc = db_exists("SELECT 1 FROM sqlite_master" |
| 135 | " WHERE name='reportfmt' AND sql GLOB '* mtime *'"); |
| 136 | if( rc==0 ){ |
| 137 | db_multi_exec( |
| 138 | "CREATE TEMP TABLE old_fmt AS SELECT * FROM reportfmt;" |
| 139 | "DROP TABLE reportfmt;" |
| 140 | ); |
| 141 | db_multi_exec(zSchemaUpdates2); |
| 142 | db_multi_exec( |
| 143 | "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)" |
| 144 | " SELECT rn, owner, title, cols, sqlcode, now() FROM old_fmt;" |
| 145 | "INSERT OR IGNORE INTO reportfmt(rn,owner,title,cols,sqlcode,mtime)" |
| 146 | " SELECT rn, owner, title || ' (' || rn || ')', cols, sqlcode, now()" |
| 147 | " FROM old_fmt;" |
| 148 | ); |
| 149 | } |
| 150 | |
| 151 | rc = db_exists("SELECT 1 FROM sqlite_master" |
| 152 | " WHERE name='concealed' AND sql GLOB '* mtime *'"); |
| 153 | if( rc==0 ){ |
| 154 | db_multi_exec( |
| 155 | "ALTER TABLE concealed ADD COLUMN mtime INTEGER;" |
| 156 | "UPDATE concealed SET mtime=now();" |
| 157 | ); |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | /* |
| 162 | ** Variables used to store state information about an on-going "rebuild" |
| 163 | ** or "deconstruct". |
| 164 | */ |
| @@ -91,11 +176,11 @@ | |
| 176 | ** The input is actually the permill complete. |
| 177 | */ |
| 178 | static void percent_complete(int permill){ |
| 179 | static int lastOutput = -1; |
| 180 | if( permill>lastOutput ){ |
| 181 | fossil_print(" %d.%d%% complete...\r", permill/10, permill%10); |
| 182 | fflush(stdout); |
| 183 | lastOutput = permill; |
| 184 | } |
| 185 | } |
| 186 | |
| @@ -256,11 +341,11 @@ | |
| 341 | ttyOutput = doOut; |
| 342 | processCnt = 0; |
| 343 | if (!g.fQuiet) { |
| 344 | percent_complete(0); |
| 345 | } |
| 346 | rebuild_update_schema(); |
| 347 | for(;;){ |
| 348 | zTable = db_text(0, |
| 349 | "SELECT name FROM sqlite_master /*scan*/" |
| 350 | " WHERE type='table'" |
| 351 | " AND name NOT IN ('blob','delta','rcvfrom','user'," |
| @@ -335,11 +420,11 @@ | |
| 420 | if( !g.fQuiet && totalSize>0 ){ |
| 421 | processCnt += incrSize; |
| 422 | percent_complete((processCnt*1000)/totalSize); |
| 423 | } |
| 424 | if(!g.fQuiet && ttyOutput ){ |
| 425 | fossil_print("\n"); |
| 426 | } |
| 427 | return errCnt; |
| 428 | } |
| 429 | |
| 430 | /* |
| @@ -459,37 +544,39 @@ | |
| 544 | } |
| 545 | db_begin_transaction(); |
| 546 | ttyOutput = 1; |
| 547 | errCnt = rebuild_db(randomizeFlag, 1, doClustering); |
| 548 | db_multi_exec( |
| 549 | "REPLACE INTO config(name,value,mtime) VALUES('content-schema','%s',now());" |
| 550 | "REPLACE INTO config(name,value,mtime) VALUES('aux-schema','%s',now());", |
| 551 | CONTENT_SCHEMA, AUX_SCHEMA |
| 552 | ); |
| 553 | if( errCnt && !forceFlag ){ |
| 554 | fossil_print( |
| 555 | "%d errors. Rolling back changes. Use --force to force a commit.\n", |
| 556 | errCnt |
| 557 | ); |
| 558 | db_end_transaction(1); |
| 559 | }else{ |
| 560 | if( runCompress ){ |
| 561 | fossil_print("Extra delta compression... "); fflush(stdout); |
| 562 | extra_deltification(); |
| 563 | runVacuum = 1; |
| 564 | } |
| 565 | if( omitVerify ) verify_cancel(); |
| 566 | db_end_transaction(0); |
| 567 | if( runCompress ) fossil_print("done\n"); |
| 568 | db_close(0); |
| 569 | db_open_repository(g.zRepositoryName); |
| 570 | if( newPagesize ){ |
| 571 | db_multi_exec("PRAGMA page_size=%d", newPagesize); |
| 572 | runVacuum = 1; |
| 573 | } |
| 574 | if( runVacuum ){ |
| 575 | fossil_print("Vacuuming the database... "); fflush(stdout); |
| 576 | db_multi_exec("VACUUM"); |
| 577 | fossil_print("done\n"); |
| 578 | } |
| 579 | if( activateWal ){ |
| 580 | db_multi_exec("PRAGMA journal_mode=WAL;"); |
| 581 | } |
| 582 | } |
| @@ -593,16 +680,16 @@ | |
| 680 | manifest_destroy(p); |
| 681 | } |
| 682 | n = db_int(0, "SELECT count(*) FROM /*scan*/" |
| 683 | " (SELECT rid FROM blob EXCEPT SELECT x FROM xdone)"); |
| 684 | if( n==0 ){ |
| 685 | fossil_print("all artifacts reachable through clusters\n"); |
| 686 | }else{ |
| 687 | fossil_print("%d unreachable artifacts:\n", n); |
| 688 | db_prepare(&q, "SELECT rid, uuid FROM blob WHERE rid NOT IN xdone"); |
| 689 | while( db_step(&q)==SQLITE_ROW ){ |
| 690 | fossil_print(" %3d %s\n", db_column_int(&q,0), db_column_text(&q,1)); |
| 691 | } |
| 692 | db_finalize(&q); |
| 693 | } |
| 694 | } |
| 695 | |
| @@ -712,11 +799,11 @@ | |
| 799 | } |
| 800 | content_put(&aContent); |
| 801 | blob_reset(&path); |
| 802 | blob_reset(&aContent); |
| 803 | free(zSubpath); |
| 804 | fossil_print("\r%d", ++nFileRead); |
| 805 | fflush(stdout); |
| 806 | } |
| 807 | closedir(d); |
| 808 | }else { |
| 809 | fossil_panic("encountered error %d while trying to open \"%s\".", |
| @@ -739,22 +826,22 @@ | |
| 826 | char *zPassword; |
| 827 | if( g.argc!=4 ){ |
| 828 | usage("FILENAME DIRECTORY"); |
| 829 | } |
| 830 | if( file_isdir(g.argv[3])!=1 ){ |
| 831 | fossil_print("\"%s\" is not a directory\n\n", g.argv[3]); |
| 832 | usage("FILENAME DIRECTORY"); |
| 833 | } |
| 834 | db_create_repository(g.argv[2]); |
| 835 | db_open_repository(g.argv[2]); |
| 836 | db_open_config(0); |
| 837 | db_begin_transaction(); |
| 838 | db_initial_setup(0, 0, 1); |
| 839 | |
| 840 | fossil_print("Reading files from directory \"%s\"...\n", g.argv[3]); |
| 841 | recon_read_dir(g.argv[3]); |
| 842 | fossil_print("\nBuilding the Fossil repository...\n"); |
| 843 | |
| 844 | rebuild_db(0, 1, 1); |
| 845 | |
| 846 | /* Reconstruct the private table. The private table contains the rid |
| 847 | ** of every manifest that is tagged with "private" and every file that |
| @@ -776,14 +863,14 @@ | |
| 863 | ** long time. |
| 864 | */ |
| 865 | verify_cancel(); |
| 866 | |
| 867 | db_end_transaction(0); |
| 868 | fossil_print("project-id: %s\n", db_get("project-code", 0)); |
| 869 | fossil_print("server-id: %s\n", db_get("server-code", 0)); |
| 870 | zPassword = db_text(0, "SELECT pw FROM user WHERE login=%Q", g.zLogin); |
| 871 | fossil_print("admin-user: %s (initial password is \"%s\")\n", g.zLogin, zPassword); |
| 872 | } |
| 873 | |
| 874 | /* |
| 875 | ** COMMAND: deconstruct |
| 876 | ** |
| @@ -824,11 +911,11 @@ | |
| 911 | }else{ |
| 912 | fossil_fatal("N(%s) is not a a valid prefix length!",zPrefixOpt); |
| 913 | } |
| 914 | } |
| 915 | #ifndef _WIN32 |
| 916 | if( file_access(zDestDir, W_OK) ){ |
| 917 | fossil_fatal("DESTINATION(%s) is not writeable!",zDestDir); |
| 918 | } |
| 919 | #else |
| 920 | /* write access on windows is not checked, errors will be |
| 921 | ** dected on blob_write_to_file |
| @@ -843,11 +930,11 @@ | |
| 930 | db_find_and_open_repository(OPEN_ANY_SCHEMA, 0); |
| 931 | bag_init(&bagDone); |
| 932 | ttyOutput = 1; |
| 933 | processCnt = 0; |
| 934 | if (!g.fQuiet) { |
| 935 | fossil_print("0 (0%%)...\r"); |
| 936 | fflush(stdout); |
| 937 | } |
| 938 | totalSize = db_int(0, "SELECT count(*) FROM blob"); |
| 939 | db_prepare(&s, |
| 940 | "SELECT rid, size FROM blob /*scan*/" |
| @@ -879,12 +966,12 @@ | |
| 966 | } |
| 967 | } |
| 968 | } |
| 969 | db_finalize(&s); |
| 970 | if(!g.fQuiet && ttyOutput ){ |
| 971 | fossil_print("\n"); |
| 972 | } |
| 973 | |
| 974 | /* free filename format string */ |
| 975 | free(zFNameFormat); |
| 976 | zFNameFormat = 0; |
| 977 | } |
| 978 |
+18
-12
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -360,19 +360,25 @@ | ||
| 360 | 360 | }else if( (zTitle = trim_string(zTitle))[0]==0 ){ |
| 361 | 361 | zErr = "Please supply a title"; |
| 362 | 362 | }else{ |
| 363 | 363 | zErr = verify_sql_statement(zSQL); |
| 364 | 364 | } |
| 365 | + if( zErr==0 | |
| 366 | + && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", | |
| 367 | + zTitle, rn) | |
| 368 | + ){ | |
| 369 | + zErr = mprintf("There is already another report named \"%h\"", zTitle); | |
| 370 | + } | |
| 365 | 371 | if( zErr==0 ){ |
| 366 | 372 | login_verify_csrf_secret(); |
| 367 | 373 | if( rn>0 ){ |
| 368 | 374 | db_multi_exec("UPDATE reportfmt SET title=%Q, sqlcode=%Q," |
| 369 | - " owner=%Q, cols=%Q WHERE rn=%d", | |
| 375 | + " owner=%Q, cols=%Q, mtime=now() WHERE rn=%d", | |
| 370 | 376 | zTitle, zSQL, zOwner, zClrKey, rn); |
| 371 | 377 | }else{ |
| 372 | - db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols) " | |
| 373 | - "VALUES(%Q,%Q,%Q,%Q)", | |
| 378 | + db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime) " | |
| 379 | + "VALUES(%Q,%Q,%Q,%Q,now())", | |
| 374 | 380 | zTitle, zSQL, zOwner, zClrKey); |
| 375 | 381 | rn = db_last_insert_rowid(); |
| 376 | 382 | } |
| 377 | 383 | cgi_redirect(mprintf("rptview?rn=%d", rn)); |
| 378 | 384 | return; |
| @@ -994,19 +1000,19 @@ | ||
| 994 | 1000 | */ |
| 995 | 1001 | void rpt_list_reports(void){ |
| 996 | 1002 | Stmt q; |
| 997 | 1003 | char const aRptOutFrmt[] = "%s\t%s\n"; |
| 998 | 1004 | |
| 999 | - printf("Available reports:\n"); | |
| 1000 | - printf(aRptOutFrmt,"report number","report title"); | |
| 1001 | - printf(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle); | |
| 1005 | + fossil_print("Available reports:\n"); | |
| 1006 | + fossil_print(aRptOutFrmt,"report number","report title"); | |
| 1007 | + fossil_print(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle); | |
| 1002 | 1008 | db_prepare(&q,"SELECT rn,title FROM reportfmt ORDER BY rn"); |
| 1003 | 1009 | while( db_step(&q)==SQLITE_ROW ){ |
| 1004 | 1010 | const char *zRn = db_column_text(&q, 0); |
| 1005 | 1011 | const char *zTitle = db_column_text(&q, 1); |
| 1006 | 1012 | |
| 1007 | - printf(aRptOutFrmt,zRn,zTitle); | |
| 1013 | + fossil_print(aRptOutFrmt,zRn,zTitle); | |
| 1008 | 1014 | } |
| 1009 | 1015 | db_finalize(&q); |
| 1010 | 1016 | } |
| 1011 | 1017 | |
| 1012 | 1018 | /* |
| @@ -1031,25 +1037,25 @@ | ||
| 1031 | 1037 | case tktFossilize: |
| 1032 | 1038 | { char *zFosZ; |
| 1033 | 1039 | |
| 1034 | 1040 | if( z && *z ){ |
| 1035 | 1041 | zFosZ = fossilize(z,-1); |
| 1036 | - printf("%s",zFosZ); | |
| 1042 | + fossil_print("%s",zFosZ); | |
| 1037 | 1043 | free(zFosZ); |
| 1038 | 1044 | } |
| 1039 | 1045 | break; |
| 1040 | 1046 | } |
| 1041 | 1047 | default: |
| 1042 | 1048 | while( z && z[0] ){ |
| 1043 | 1049 | int i, j; |
| 1044 | 1050 | for(i=0; z[i] && (!fossil_isspace(z[i]) || z[i]==' '); i++){} |
| 1045 | 1051 | if( i>0 ){ |
| 1046 | - printf("%.*s", i, z); | |
| 1052 | + fossil_print("%.*s", i, z); | |
| 1047 | 1053 | } |
| 1048 | 1054 | for(j=i; fossil_isspace(z[j]); j++){} |
| 1049 | 1055 | if( j>i ){ |
| 1050 | - printf("%*s", j-i, ""); | |
| 1056 | + fossil_print("%*s", j-i, ""); | |
| 1051 | 1057 | } |
| 1052 | 1058 | z += j; |
| 1053 | 1059 | } |
| 1054 | 1060 | break; |
| 1055 | 1061 | } |
| @@ -1068,17 +1074,17 @@ | ||
| 1068 | 1074 | int i; |
| 1069 | 1075 | |
| 1070 | 1076 | if( *pCount==0 ){ |
| 1071 | 1077 | for(i=0; i<nArg; i++){ |
| 1072 | 1078 | output_no_tabs_file(azName[i]); |
| 1073 | - printf("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); | |
| 1079 | + fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); | |
| 1074 | 1080 | } |
| 1075 | 1081 | } |
| 1076 | 1082 | ++*pCount; |
| 1077 | 1083 | for(i=0; i<nArg; i++){ |
| 1078 | 1084 | output_no_tabs_file(azArg[i]); |
| 1079 | - printf("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); | |
| 1085 | + fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); | |
| 1080 | 1086 | } |
| 1081 | 1087 | return 0; |
| 1082 | 1088 | } |
| 1083 | 1089 | |
| 1084 | 1090 | /* |
| 1085 | 1091 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -360,19 +360,25 @@ | |
| 360 | }else if( (zTitle = trim_string(zTitle))[0]==0 ){ |
| 361 | zErr = "Please supply a title"; |
| 362 | }else{ |
| 363 | zErr = verify_sql_statement(zSQL); |
| 364 | } |
| 365 | if( zErr==0 ){ |
| 366 | login_verify_csrf_secret(); |
| 367 | if( rn>0 ){ |
| 368 | db_multi_exec("UPDATE reportfmt SET title=%Q, sqlcode=%Q," |
| 369 | " owner=%Q, cols=%Q WHERE rn=%d", |
| 370 | zTitle, zSQL, zOwner, zClrKey, rn); |
| 371 | }else{ |
| 372 | db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols) " |
| 373 | "VALUES(%Q,%Q,%Q,%Q)", |
| 374 | zTitle, zSQL, zOwner, zClrKey); |
| 375 | rn = db_last_insert_rowid(); |
| 376 | } |
| 377 | cgi_redirect(mprintf("rptview?rn=%d", rn)); |
| 378 | return; |
| @@ -994,19 +1000,19 @@ | |
| 994 | */ |
| 995 | void rpt_list_reports(void){ |
| 996 | Stmt q; |
| 997 | char const aRptOutFrmt[] = "%s\t%s\n"; |
| 998 | |
| 999 | printf("Available reports:\n"); |
| 1000 | printf(aRptOutFrmt,"report number","report title"); |
| 1001 | printf(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle); |
| 1002 | db_prepare(&q,"SELECT rn,title FROM reportfmt ORDER BY rn"); |
| 1003 | while( db_step(&q)==SQLITE_ROW ){ |
| 1004 | const char *zRn = db_column_text(&q, 0); |
| 1005 | const char *zTitle = db_column_text(&q, 1); |
| 1006 | |
| 1007 | printf(aRptOutFrmt,zRn,zTitle); |
| 1008 | } |
| 1009 | db_finalize(&q); |
| 1010 | } |
| 1011 | |
| 1012 | /* |
| @@ -1031,25 +1037,25 @@ | |
| 1031 | case tktFossilize: |
| 1032 | { char *zFosZ; |
| 1033 | |
| 1034 | if( z && *z ){ |
| 1035 | zFosZ = fossilize(z,-1); |
| 1036 | printf("%s",zFosZ); |
| 1037 | free(zFosZ); |
| 1038 | } |
| 1039 | break; |
| 1040 | } |
| 1041 | default: |
| 1042 | while( z && z[0] ){ |
| 1043 | int i, j; |
| 1044 | for(i=0; z[i] && (!fossil_isspace(z[i]) || z[i]==' '); i++){} |
| 1045 | if( i>0 ){ |
| 1046 | printf("%.*s", i, z); |
| 1047 | } |
| 1048 | for(j=i; fossil_isspace(z[j]); j++){} |
| 1049 | if( j>i ){ |
| 1050 | printf("%*s", j-i, ""); |
| 1051 | } |
| 1052 | z += j; |
| 1053 | } |
| 1054 | break; |
| 1055 | } |
| @@ -1068,17 +1074,17 @@ | |
| 1068 | int i; |
| 1069 | |
| 1070 | if( *pCount==0 ){ |
| 1071 | for(i=0; i<nArg; i++){ |
| 1072 | output_no_tabs_file(azName[i]); |
| 1073 | printf("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); |
| 1074 | } |
| 1075 | } |
| 1076 | ++*pCount; |
| 1077 | for(i=0; i<nArg; i++){ |
| 1078 | output_no_tabs_file(azArg[i]); |
| 1079 | printf("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); |
| 1080 | } |
| 1081 | return 0; |
| 1082 | } |
| 1083 | |
| 1084 | /* |
| 1085 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -360,19 +360,25 @@ | |
| 360 | }else if( (zTitle = trim_string(zTitle))[0]==0 ){ |
| 361 | zErr = "Please supply a title"; |
| 362 | }else{ |
| 363 | zErr = verify_sql_statement(zSQL); |
| 364 | } |
| 365 | if( zErr==0 |
| 366 | && db_exists("SELECT 1 FROM reportfmt WHERE title=%Q and rn<>%d", |
| 367 | zTitle, rn) |
| 368 | ){ |
| 369 | zErr = mprintf("There is already another report named \"%h\"", zTitle); |
| 370 | } |
| 371 | if( zErr==0 ){ |
| 372 | login_verify_csrf_secret(); |
| 373 | if( rn>0 ){ |
| 374 | db_multi_exec("UPDATE reportfmt SET title=%Q, sqlcode=%Q," |
| 375 | " owner=%Q, cols=%Q, mtime=now() WHERE rn=%d", |
| 376 | zTitle, zSQL, zOwner, zClrKey, rn); |
| 377 | }else{ |
| 378 | db_multi_exec("INSERT INTO reportfmt(title,sqlcode,owner,cols,mtime) " |
| 379 | "VALUES(%Q,%Q,%Q,%Q,now())", |
| 380 | zTitle, zSQL, zOwner, zClrKey); |
| 381 | rn = db_last_insert_rowid(); |
| 382 | } |
| 383 | cgi_redirect(mprintf("rptview?rn=%d", rn)); |
| 384 | return; |
| @@ -994,19 +1000,19 @@ | |
| 1000 | */ |
| 1001 | void rpt_list_reports(void){ |
| 1002 | Stmt q; |
| 1003 | char const aRptOutFrmt[] = "%s\t%s\n"; |
| 1004 | |
| 1005 | fossil_print("Available reports:\n"); |
| 1006 | fossil_print(aRptOutFrmt,"report number","report title"); |
| 1007 | fossil_print(aRptOutFrmt,zFullTicketRptRn,zFullTicketRptTitle); |
| 1008 | db_prepare(&q,"SELECT rn,title FROM reportfmt ORDER BY rn"); |
| 1009 | while( db_step(&q)==SQLITE_ROW ){ |
| 1010 | const char *zRn = db_column_text(&q, 0); |
| 1011 | const char *zTitle = db_column_text(&q, 1); |
| 1012 | |
| 1013 | fossil_print(aRptOutFrmt,zRn,zTitle); |
| 1014 | } |
| 1015 | db_finalize(&q); |
| 1016 | } |
| 1017 | |
| 1018 | /* |
| @@ -1031,25 +1037,25 @@ | |
| 1037 | case tktFossilize: |
| 1038 | { char *zFosZ; |
| 1039 | |
| 1040 | if( z && *z ){ |
| 1041 | zFosZ = fossilize(z,-1); |
| 1042 | fossil_print("%s",zFosZ); |
| 1043 | free(zFosZ); |
| 1044 | } |
| 1045 | break; |
| 1046 | } |
| 1047 | default: |
| 1048 | while( z && z[0] ){ |
| 1049 | int i, j; |
| 1050 | for(i=0; z[i] && (!fossil_isspace(z[i]) || z[i]==' '); i++){} |
| 1051 | if( i>0 ){ |
| 1052 | fossil_print("%.*s", i, z); |
| 1053 | } |
| 1054 | for(j=i; fossil_isspace(z[j]); j++){} |
| 1055 | if( j>i ){ |
| 1056 | fossil_print("%*s", j-i, ""); |
| 1057 | } |
| 1058 | z += j; |
| 1059 | } |
| 1060 | break; |
| 1061 | } |
| @@ -1068,17 +1074,17 @@ | |
| 1074 | int i; |
| 1075 | |
| 1076 | if( *pCount==0 ){ |
| 1077 | for(i=0; i<nArg; i++){ |
| 1078 | output_no_tabs_file(azName[i]); |
| 1079 | fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); |
| 1080 | } |
| 1081 | } |
| 1082 | ++*pCount; |
| 1083 | for(i=0; i<nArg; i++){ |
| 1084 | output_no_tabs_file(azArg[i]); |
| 1085 | fossil_print("%s", i<nArg-1 ? (zSep?zSep:"\t") : "\n"); |
| 1086 | } |
| 1087 | return 0; |
| 1088 | } |
| 1089 | |
| 1090 | /* |
| 1091 |
+41
-21
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -39,12 +39,12 @@ | ||
| 39 | 39 | ** changes. The aux tables have an arbitrary version number (typically |
| 40 | 40 | ** a date) which can change frequently. When the content schema changes, |
| 41 | 41 | ** we have to execute special procedures to update the schema. When |
| 42 | 42 | ** the aux schema changes, all we need to do is rebuild the database. |
| 43 | 43 | */ |
| 44 | -#define CONTENT_SCHEMA "1" | |
| 45 | -#define AUX_SCHEMA "2011-02-25 14:52" | |
| 44 | +#define CONTENT_SCHEMA "2" | |
| 45 | +#define AUX_SCHEMA "2011-04-25 19:50" | |
| 46 | 46 | |
| 47 | 47 | #endif /* INTERFACE */ |
| 48 | 48 | |
| 49 | 49 | |
| 50 | 50 | /* |
| @@ -51,21 +51,25 @@ | ||
| 51 | 51 | ** The schema for a repository database. |
| 52 | 52 | ** |
| 53 | 53 | ** Schema1[] contains parts of the schema that are fixed and unchanging |
| 54 | 54 | ** across versions. Schema2[] contains parts of the schema that can |
| 55 | 55 | ** change from one version to the next. The information in Schema2[] |
| 56 | -** can be reconstructed from the information in Schema1[]. | |
| 56 | +** is reconstructed from the information in Schema1[] by the "rebuild" | |
| 57 | +** operation. | |
| 57 | 58 | */ |
| 58 | 59 | const char zRepositorySchema1[] = |
| 59 | 60 | @ -- The BLOB and DELTA tables contain all records held in the repository. |
| 60 | 61 | @ -- |
| 61 | -@ -- The BLOB.CONTENT column is always compressed using libz. This | |
| 62 | +@ -- The BLOB.CONTENT column is always compressed using zlib. This | |
| 62 | 63 | @ -- column might hold the full text of the record or it might hold |
| 63 | 64 | @ -- a delta that is able to reconstruct the record from some other |
| 64 | 65 | @ -- record. If BLOB.CONTENT holds a delta, then a DELTA table entry |
| 65 | 66 | @ -- will exist for the record and that entry will point to another |
| 66 | 67 | @ -- entry that holds the source of the delta. Deltas can be chained. |
| 68 | +@ -- | |
| 69 | +@ -- The blob and delta tables collectively hold the "global state" of | |
| 70 | +@ -- a Fossil repository. | |
| 67 | 71 | @ -- |
| 68 | 72 | @ CREATE TABLE blob( |
| 69 | 73 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 70 | 74 | @ rcvid INTEGER, -- Origin of this record |
| 71 | 75 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| @@ -77,17 +81,24 @@ | ||
| 77 | 81 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 78 | 82 | @ srcid INTEGER NOT NULL REFERENCES blob -- Record holding source document |
| 79 | 83 | @ ); |
| 80 | 84 | @ CREATE INDEX delta_i1 ON delta(srcid); |
| 81 | 85 | @ |
| 86 | +@ ------------------------------------------------------------------------- | |
| 87 | +@ -- The BLOB and DELTA tables above hold the "global state" of a Fossil | |
| 88 | +@ -- project; the stuff that is normally exchanged during "sync". The | |
| 89 | +@ -- "local state" of a repository is contained in the remaining tables of | |
| 90 | +@ -- the zRepositorySchema1 string. | |
| 91 | +@ ------------------------------------------------------------------------- | |
| 92 | +@ | |
| 82 | 93 | @ -- Whenever new blobs are received into the repository, an entry |
| 83 | 94 | @ -- in this table records the source of the blob. |
| 84 | 95 | @ -- |
| 85 | 96 | @ CREATE TABLE rcvfrom( |
| 86 | 97 | @ rcvid INTEGER PRIMARY KEY, -- Received-From ID |
| 87 | 98 | @ uid INTEGER REFERENCES user, -- User login |
| 88 | -@ mtime DATETIME, -- Time or receipt | |
| 99 | +@ mtime DATETIME, -- Time of receipt. Julian day. | |
| 89 | 100 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 90 | 101 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 91 | 102 | @ ); |
| 92 | 103 | @ |
| 93 | 104 | @ -- Information about users |
| @@ -99,26 +110,28 @@ | ||
| 99 | 110 | @ -- hash based on the project-code, the user login, and the cleartext |
| 100 | 111 | @ -- password. |
| 101 | 112 | @ -- |
| 102 | 113 | @ CREATE TABLE user( |
| 103 | 114 | @ uid INTEGER PRIMARY KEY, -- User ID |
| 104 | -@ login TEXT, -- login name of the user | |
| 115 | +@ login TEXT UNIQUE, -- login name of the user | |
| 105 | 116 | @ pw TEXT, -- password |
| 106 | 117 | @ cap TEXT, -- Capabilities of this user |
| 107 | 118 | @ cookie TEXT, -- WWW login cookie |
| 108 | 119 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 109 | 120 | @ cexpire DATETIME, -- Time when cookie expires |
| 110 | 121 | @ info TEXT, -- contact information |
| 122 | +@ mtime DATE, -- last change. seconds since 1970 | |
| 111 | 123 | @ photo BLOB -- JPEG image of this user |
| 112 | 124 | @ ); |
| 113 | 125 | @ |
| 114 | 126 | @ -- The VAR table holds miscellanous information about the repository. |
| 115 | 127 | @ -- in the form of name-value pairs. |
| 116 | 128 | @ -- |
| 117 | 129 | @ CREATE TABLE config( |
| 118 | 130 | @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry |
| 119 | 131 | @ value CLOB, -- Content of the named parameter |
| 132 | +@ mtime DATE, -- last modified. seconds since 1970 | |
| 120 | 133 | @ CHECK( typeof(name)='text' AND length(name)>=1 ) |
| 121 | 134 | @ ); |
| 122 | 135 | @ |
| 123 | 136 | @ -- Artifacts that should not be processed are identified in the |
| 124 | 137 | @ -- "shun" table. Artifacts that are control-file forgeries or |
| @@ -128,11 +141,15 @@ | ||
| 128 | 141 | @ -- |
| 129 | 142 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 130 | 143 | @ -- have not artifact ID (rid) and we thus must store their full |
| 131 | 144 | @ -- UUID. |
| 132 | 145 | @ -- |
| 133 | -@ CREATE TABLE shun(uuid UNIQUE); | |
| 146 | +@ CREATE TABLE shun( | |
| 147 | +@ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form | |
| 148 | +@ mtime DATE, -- When added. seconds since 1970 | |
| 149 | +@ scom TEXT -- Optional text explaining why the shun occurred | |
| 150 | +@ ); | |
| 134 | 151 | @ |
| 135 | 152 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 136 | 153 | @ -- table. Private artifacts are omitted from the "unclustered" and |
| 137 | 154 | @ -- "unsent" tables. |
| 138 | 155 | @ -- |
| @@ -140,17 +157,19 @@ | ||
| 140 | 157 | @ |
| 141 | 158 | @ -- An entry in this table describes a database query that generates a |
| 142 | 159 | @ -- table of tickets. |
| 143 | 160 | @ -- |
| 144 | 161 | @ CREATE TABLE reportfmt( |
| 145 | -@ rn integer primary key, -- Report number | |
| 146 | -@ owner text, -- Owner of this report format (not used) | |
| 147 | -@ title text, -- Title of this report | |
| 148 | -@ cols text, -- A color-key specification | |
| 149 | -@ sqlcode text -- An SQL SELECT statement for this report | |
| 162 | +@ rn INTEGER PRIMARY KEY, -- Report number | |
| 163 | +@ owner TEXT, -- Owner of this report format (not used) | |
| 164 | +@ title TEXT UNIQUE, -- Title of this report | |
| 165 | +@ mtime DATE, -- Last modified. seconds since 1970 | |
| 166 | +@ cols TEXT, -- A color-key specification | |
| 167 | +@ sqlcode TEXT -- An SQL SELECT statement for this report | |
| 150 | 168 | @ ); |
| 151 | -@ INSERT INTO reportfmt(title,cols,sqlcode) VALUES('All Tickets','#ffffff Key: | |
| 169 | +@ INSERT INTO reportfmt(title,mtime,cols,sqlcode) | |
| 170 | +@ VALUES('All Tickets',julianday('1970-01-01'),'#ffffff Key: | |
| 152 | 171 | @ #f2dcdc Active |
| 153 | 172 | @ #e8e8e8 Review |
| 154 | 173 | @ #cfe8bd Fixed |
| 155 | 174 | @ #bde5d6 Tested |
| 156 | 175 | @ #cacae5 Deferred |
| @@ -176,12 +195,13 @@ | ||
| 176 | 195 | @ -- |
| 177 | 196 | @ -- This table contains sensitive information and should not be shared |
| 178 | 197 | @ -- with unauthorized users. |
| 179 | 198 | @ -- |
| 180 | 199 | @ CREATE TABLE concealed( |
| 181 | -@ hash TEXT PRIMARY KEY, | |
| 182 | -@ content TEXT | |
| 200 | +@ hash TEXT PRIMARY KEY, -- The SHA1 hash of content | |
| 201 | +@ mtime DATE, -- Time created. Seconds since 1970 | |
| 202 | +@ content TEXT -- Content intended to be concealed | |
| 183 | 203 | @ ); |
| 184 | 204 | ; |
| 185 | 205 | |
| 186 | 206 | const char zRepositorySchema2[] = |
| 187 | 207 | @ -- Filenames |
| @@ -214,11 +234,11 @@ | ||
| 214 | 234 | @ -- |
| 215 | 235 | @ CREATE TABLE plink( |
| 216 | 236 | @ pid INTEGER REFERENCES blob, -- Parent manifest |
| 217 | 237 | @ cid INTEGER REFERENCES blob, -- Child manifest |
| 218 | 238 | @ isprim BOOLEAN, -- pid is the primary parent of cid |
| 219 | -@ mtime DATETIME, -- the date/time stamp on cid | |
| 239 | +@ mtime DATETIME, -- the date/time stamp on cid. Julian day. | |
| 220 | 240 | @ UNIQUE(pid, cid) |
| 221 | 241 | @ ); |
| 222 | 242 | @ CREATE INDEX plink_i2 ON plink(cid,pid); |
| 223 | 243 | @ |
| 224 | 244 | @ -- A "leaf" checkin is a checkin that has no children in the same |
| @@ -232,11 +252,11 @@ | ||
| 232 | 252 | @ |
| 233 | 253 | @ -- Events used to generate a timeline |
| 234 | 254 | @ -- |
| 235 | 255 | @ CREATE TABLE event( |
| 236 | 256 | @ type TEXT, -- Type of event: 'ci', 'w', 'e', 't' |
| 237 | -@ mtime DATETIME, -- Date and time when the event occurs | |
| 257 | +@ mtime DATETIME, -- Time of occurrence. Julian day. | |
| 238 | 258 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 239 | 259 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 240 | 260 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 241 | 261 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 242 | 262 | @ euser TEXT, -- User set by 'user' property |
| @@ -319,11 +339,11 @@ | ||
| 319 | 339 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 320 | 340 | @ tagtype INTEGER, -- 0:-,cancel 1:+,single 2:*,propagate |
| 321 | 341 | @ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags |
| 322 | 342 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag |
| 323 | 343 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 324 | -@ mtime TIMESTAMP, -- Time of addition or removal | |
| 344 | +@ mtime TIMESTAMP, -- Time of addition or removal. Julian day | |
| 325 | 345 | @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to |
| 326 | 346 | @ UNIQUE(rid, tagid) |
| 327 | 347 | @ ); |
| 328 | 348 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 329 | 349 | @ |
| @@ -334,11 +354,11 @@ | ||
| 334 | 354 | @ -- |
| 335 | 355 | @ CREATE TABLE backlink( |
| 336 | 356 | @ target TEXT, -- Where the hyperlink points to |
| 337 | 357 | @ srctype INT, -- 0: check-in 1: ticket 2: wiki |
| 338 | 358 | @ srcid INT, -- rid for checkin or wiki. tkt_id for ticket. |
| 339 | -@ mtime TIMESTAMP, -- time that the hyperlink was added | |
| 359 | +@ mtime TIMESTAMP, -- time that the hyperlink was added. Julian day. | |
| 340 | 360 | @ UNIQUE(target, srctype, srcid) |
| 341 | 361 | @ ); |
| 342 | 362 | @ CREATE INDEX backlink_src ON backlink(srcid, srctype); |
| 343 | 363 | @ |
| 344 | 364 | @ -- Each attachment is an entry in the following table. Only |
| @@ -345,11 +365,11 @@ | ||
| 345 | 365 | @ -- the most recent attachment (identified by the D card) is saved. |
| 346 | 366 | @ -- |
| 347 | 367 | @ CREATE TABLE attachment( |
| 348 | 368 | @ attachid INTEGER PRIMARY KEY, -- Local id for this attachment |
| 349 | 369 | @ isLatest BOOLEAN DEFAULT 0, -- True if this is the one to use |
| 350 | -@ mtime TIMESTAMP, -- Time when attachment last changed | |
| 370 | +@ mtime TIMESTAMP, -- Last changed. Julian day. | |
| 351 | 371 | @ src TEXT, -- UUID of the attachment. NULL to delete |
| 352 | 372 | @ target TEXT, -- Object attached to. Wikiname or Tkt UUID |
| 353 | 373 | @ filename TEXT, -- Filename for the attachment |
| 354 | 374 | @ comment TEXT, -- Comment associated with this attachment |
| 355 | 375 | @ user TEXT -- Name of user adding attachment |
| @@ -443,11 +463,11 @@ | ||
| 443 | 463 | @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add |
| 444 | 464 | @ deleted BOOLEAN DEFAULT 0, -- True if deleted |
| 445 | 465 | @ isexe BOOLEAN, -- True if file should be executable |
| 446 | 466 | @ rid INTEGER, -- Originally from this repository record |
| 447 | 467 | @ mrid INTEGER, -- Based on this record due to a merge |
| 448 | -@ mtime INTEGER, -- Modification time of file on disk | |
| 468 | +@ mtime INTEGER, -- Mtime of file on disk. sec since 1970 | |
| 449 | 469 | @ pathname TEXT, -- Full pathname relative to root |
| 450 | 470 | @ origname TEXT, -- Original pathname. NULL if unchanged |
| 451 | 471 | @ UNIQUE(pathname,vid) |
| 452 | 472 | @ ); |
| 453 | 473 | @ |
| 454 | 474 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -39,12 +39,12 @@ | |
| 39 | ** changes. The aux tables have an arbitrary version number (typically |
| 40 | ** a date) which can change frequently. When the content schema changes, |
| 41 | ** we have to execute special procedures to update the schema. When |
| 42 | ** the aux schema changes, all we need to do is rebuild the database. |
| 43 | */ |
| 44 | #define CONTENT_SCHEMA "1" |
| 45 | #define AUX_SCHEMA "2011-02-25 14:52" |
| 46 | |
| 47 | #endif /* INTERFACE */ |
| 48 | |
| 49 | |
| 50 | /* |
| @@ -51,21 +51,25 @@ | |
| 51 | ** The schema for a repository database. |
| 52 | ** |
| 53 | ** Schema1[] contains parts of the schema that are fixed and unchanging |
| 54 | ** across versions. Schema2[] contains parts of the schema that can |
| 55 | ** change from one version to the next. The information in Schema2[] |
| 56 | ** can be reconstructed from the information in Schema1[]. |
| 57 | */ |
| 58 | const char zRepositorySchema1[] = |
| 59 | @ -- The BLOB and DELTA tables contain all records held in the repository. |
| 60 | @ -- |
| 61 | @ -- The BLOB.CONTENT column is always compressed using libz. This |
| 62 | @ -- column might hold the full text of the record or it might hold |
| 63 | @ -- a delta that is able to reconstruct the record from some other |
| 64 | @ -- record. If BLOB.CONTENT holds a delta, then a DELTA table entry |
| 65 | @ -- will exist for the record and that entry will point to another |
| 66 | @ -- entry that holds the source of the delta. Deltas can be chained. |
| 67 | @ -- |
| 68 | @ CREATE TABLE blob( |
| 69 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 70 | @ rcvid INTEGER, -- Origin of this record |
| 71 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| @@ -77,17 +81,24 @@ | |
| 77 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 78 | @ srcid INTEGER NOT NULL REFERENCES blob -- Record holding source document |
| 79 | @ ); |
| 80 | @ CREATE INDEX delta_i1 ON delta(srcid); |
| 81 | @ |
| 82 | @ -- Whenever new blobs are received into the repository, an entry |
| 83 | @ -- in this table records the source of the blob. |
| 84 | @ -- |
| 85 | @ CREATE TABLE rcvfrom( |
| 86 | @ rcvid INTEGER PRIMARY KEY, -- Received-From ID |
| 87 | @ uid INTEGER REFERENCES user, -- User login |
| 88 | @ mtime DATETIME, -- Time or receipt |
| 89 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 90 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 91 | @ ); |
| 92 | @ |
| 93 | @ -- Information about users |
| @@ -99,26 +110,28 @@ | |
| 99 | @ -- hash based on the project-code, the user login, and the cleartext |
| 100 | @ -- password. |
| 101 | @ -- |
| 102 | @ CREATE TABLE user( |
| 103 | @ uid INTEGER PRIMARY KEY, -- User ID |
| 104 | @ login TEXT, -- login name of the user |
| 105 | @ pw TEXT, -- password |
| 106 | @ cap TEXT, -- Capabilities of this user |
| 107 | @ cookie TEXT, -- WWW login cookie |
| 108 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 109 | @ cexpire DATETIME, -- Time when cookie expires |
| 110 | @ info TEXT, -- contact information |
| 111 | @ photo BLOB -- JPEG image of this user |
| 112 | @ ); |
| 113 | @ |
| 114 | @ -- The VAR table holds miscellanous information about the repository. |
| 115 | @ -- in the form of name-value pairs. |
| 116 | @ -- |
| 117 | @ CREATE TABLE config( |
| 118 | @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry |
| 119 | @ value CLOB, -- Content of the named parameter |
| 120 | @ CHECK( typeof(name)='text' AND length(name)>=1 ) |
| 121 | @ ); |
| 122 | @ |
| 123 | @ -- Artifacts that should not be processed are identified in the |
| 124 | @ -- "shun" table. Artifacts that are control-file forgeries or |
| @@ -128,11 +141,15 @@ | |
| 128 | @ -- |
| 129 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 130 | @ -- have not artifact ID (rid) and we thus must store their full |
| 131 | @ -- UUID. |
| 132 | @ -- |
| 133 | @ CREATE TABLE shun(uuid UNIQUE); |
| 134 | @ |
| 135 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 136 | @ -- table. Private artifacts are omitted from the "unclustered" and |
| 137 | @ -- "unsent" tables. |
| 138 | @ -- |
| @@ -140,17 +157,19 @@ | |
| 140 | @ |
| 141 | @ -- An entry in this table describes a database query that generates a |
| 142 | @ -- table of tickets. |
| 143 | @ -- |
| 144 | @ CREATE TABLE reportfmt( |
| 145 | @ rn integer primary key, -- Report number |
| 146 | @ owner text, -- Owner of this report format (not used) |
| 147 | @ title text, -- Title of this report |
| 148 | @ cols text, -- A color-key specification |
| 149 | @ sqlcode text -- An SQL SELECT statement for this report |
| 150 | @ ); |
| 151 | @ INSERT INTO reportfmt(title,cols,sqlcode) VALUES('All Tickets','#ffffff Key: |
| 152 | @ #f2dcdc Active |
| 153 | @ #e8e8e8 Review |
| 154 | @ #cfe8bd Fixed |
| 155 | @ #bde5d6 Tested |
| 156 | @ #cacae5 Deferred |
| @@ -176,12 +195,13 @@ | |
| 176 | @ -- |
| 177 | @ -- This table contains sensitive information and should not be shared |
| 178 | @ -- with unauthorized users. |
| 179 | @ -- |
| 180 | @ CREATE TABLE concealed( |
| 181 | @ hash TEXT PRIMARY KEY, |
| 182 | @ content TEXT |
| 183 | @ ); |
| 184 | ; |
| 185 | |
| 186 | const char zRepositorySchema2[] = |
| 187 | @ -- Filenames |
| @@ -214,11 +234,11 @@ | |
| 214 | @ -- |
| 215 | @ CREATE TABLE plink( |
| 216 | @ pid INTEGER REFERENCES blob, -- Parent manifest |
| 217 | @ cid INTEGER REFERENCES blob, -- Child manifest |
| 218 | @ isprim BOOLEAN, -- pid is the primary parent of cid |
| 219 | @ mtime DATETIME, -- the date/time stamp on cid |
| 220 | @ UNIQUE(pid, cid) |
| 221 | @ ); |
| 222 | @ CREATE INDEX plink_i2 ON plink(cid,pid); |
| 223 | @ |
| 224 | @ -- A "leaf" checkin is a checkin that has no children in the same |
| @@ -232,11 +252,11 @@ | |
| 232 | @ |
| 233 | @ -- Events used to generate a timeline |
| 234 | @ -- |
| 235 | @ CREATE TABLE event( |
| 236 | @ type TEXT, -- Type of event: 'ci', 'w', 'e', 't' |
| 237 | @ mtime DATETIME, -- Date and time when the event occurs |
| 238 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 239 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 240 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 241 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 242 | @ euser TEXT, -- User set by 'user' property |
| @@ -319,11 +339,11 @@ | |
| 319 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 320 | @ tagtype INTEGER, -- 0:-,cancel 1:+,single 2:*,propagate |
| 321 | @ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags |
| 322 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag |
| 323 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 324 | @ mtime TIMESTAMP, -- Time of addition or removal |
| 325 | @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to |
| 326 | @ UNIQUE(rid, tagid) |
| 327 | @ ); |
| 328 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 329 | @ |
| @@ -334,11 +354,11 @@ | |
| 334 | @ -- |
| 335 | @ CREATE TABLE backlink( |
| 336 | @ target TEXT, -- Where the hyperlink points to |
| 337 | @ srctype INT, -- 0: check-in 1: ticket 2: wiki |
| 338 | @ srcid INT, -- rid for checkin or wiki. tkt_id for ticket. |
| 339 | @ mtime TIMESTAMP, -- time that the hyperlink was added |
| 340 | @ UNIQUE(target, srctype, srcid) |
| 341 | @ ); |
| 342 | @ CREATE INDEX backlink_src ON backlink(srcid, srctype); |
| 343 | @ |
| 344 | @ -- Each attachment is an entry in the following table. Only |
| @@ -345,11 +365,11 @@ | |
| 345 | @ -- the most recent attachment (identified by the D card) is saved. |
| 346 | @ -- |
| 347 | @ CREATE TABLE attachment( |
| 348 | @ attachid INTEGER PRIMARY KEY, -- Local id for this attachment |
| 349 | @ isLatest BOOLEAN DEFAULT 0, -- True if this is the one to use |
| 350 | @ mtime TIMESTAMP, -- Time when attachment last changed |
| 351 | @ src TEXT, -- UUID of the attachment. NULL to delete |
| 352 | @ target TEXT, -- Object attached to. Wikiname or Tkt UUID |
| 353 | @ filename TEXT, -- Filename for the attachment |
| 354 | @ comment TEXT, -- Comment associated with this attachment |
| 355 | @ user TEXT -- Name of user adding attachment |
| @@ -443,11 +463,11 @@ | |
| 443 | @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add |
| 444 | @ deleted BOOLEAN DEFAULT 0, -- True if deleted |
| 445 | @ isexe BOOLEAN, -- True if file should be executable |
| 446 | @ rid INTEGER, -- Originally from this repository record |
| 447 | @ mrid INTEGER, -- Based on this record due to a merge |
| 448 | @ mtime INTEGER, -- Modification time of file on disk |
| 449 | @ pathname TEXT, -- Full pathname relative to root |
| 450 | @ origname TEXT, -- Original pathname. NULL if unchanged |
| 451 | @ UNIQUE(pathname,vid) |
| 452 | @ ); |
| 453 | @ |
| 454 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -39,12 +39,12 @@ | |
| 39 | ** changes. The aux tables have an arbitrary version number (typically |
| 40 | ** a date) which can change frequently. When the content schema changes, |
| 41 | ** we have to execute special procedures to update the schema. When |
| 42 | ** the aux schema changes, all we need to do is rebuild the database. |
| 43 | */ |
| 44 | #define CONTENT_SCHEMA "2" |
| 45 | #define AUX_SCHEMA "2011-04-25 19:50" |
| 46 | |
| 47 | #endif /* INTERFACE */ |
| 48 | |
| 49 | |
| 50 | /* |
| @@ -51,21 +51,25 @@ | |
| 51 | ** The schema for a repository database. |
| 52 | ** |
| 53 | ** Schema1[] contains parts of the schema that are fixed and unchanging |
| 54 | ** across versions. Schema2[] contains parts of the schema that can |
| 55 | ** change from one version to the next. The information in Schema2[] |
| 56 | ** is reconstructed from the information in Schema1[] by the "rebuild" |
| 57 | ** operation. |
| 58 | */ |
| 59 | const char zRepositorySchema1[] = |
| 60 | @ -- The BLOB and DELTA tables contain all records held in the repository. |
| 61 | @ -- |
| 62 | @ -- The BLOB.CONTENT column is always compressed using zlib. This |
| 63 | @ -- column might hold the full text of the record or it might hold |
| 64 | @ -- a delta that is able to reconstruct the record from some other |
| 65 | @ -- record. If BLOB.CONTENT holds a delta, then a DELTA table entry |
| 66 | @ -- will exist for the record and that entry will point to another |
| 67 | @ -- entry that holds the source of the delta. Deltas can be chained. |
| 68 | @ -- |
| 69 | @ -- The blob and delta tables collectively hold the "global state" of |
| 70 | @ -- a Fossil repository. |
| 71 | @ -- |
| 72 | @ CREATE TABLE blob( |
| 73 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 74 | @ rcvid INTEGER, -- Origin of this record |
| 75 | @ size INTEGER, -- Size of content. -1 for a phantom. |
| @@ -77,17 +81,24 @@ | |
| 81 | @ rid INTEGER PRIMARY KEY, -- Record ID |
| 82 | @ srcid INTEGER NOT NULL REFERENCES blob -- Record holding source document |
| 83 | @ ); |
| 84 | @ CREATE INDEX delta_i1 ON delta(srcid); |
| 85 | @ |
| 86 | @ ------------------------------------------------------------------------- |
| 87 | @ -- The BLOB and DELTA tables above hold the "global state" of a Fossil |
| 88 | @ -- project; the stuff that is normally exchanged during "sync". The |
| 89 | @ -- "local state" of a repository is contained in the remaining tables of |
| 90 | @ -- the zRepositorySchema1 string. |
| 91 | @ ------------------------------------------------------------------------- |
| 92 | @ |
| 93 | @ -- Whenever new blobs are received into the repository, an entry |
| 94 | @ -- in this table records the source of the blob. |
| 95 | @ -- |
| 96 | @ CREATE TABLE rcvfrom( |
| 97 | @ rcvid INTEGER PRIMARY KEY, -- Received-From ID |
| 98 | @ uid INTEGER REFERENCES user, -- User login |
| 99 | @ mtime DATETIME, -- Time of receipt. Julian day. |
| 100 | @ nonce TEXT UNIQUE, -- Nonce used for login |
| 101 | @ ipaddr TEXT -- Remote IP address. NULL for direct. |
| 102 | @ ); |
| 103 | @ |
| 104 | @ -- Information about users |
| @@ -99,26 +110,28 @@ | |
| 110 | @ -- hash based on the project-code, the user login, and the cleartext |
| 111 | @ -- password. |
| 112 | @ -- |
| 113 | @ CREATE TABLE user( |
| 114 | @ uid INTEGER PRIMARY KEY, -- User ID |
| 115 | @ login TEXT UNIQUE, -- login name of the user |
| 116 | @ pw TEXT, -- password |
| 117 | @ cap TEXT, -- Capabilities of this user |
| 118 | @ cookie TEXT, -- WWW login cookie |
| 119 | @ ipaddr TEXT, -- IP address for which cookie is valid |
| 120 | @ cexpire DATETIME, -- Time when cookie expires |
| 121 | @ info TEXT, -- contact information |
| 122 | @ mtime DATE, -- last change. seconds since 1970 |
| 123 | @ photo BLOB -- JPEG image of this user |
| 124 | @ ); |
| 125 | @ |
| 126 | @ -- The VAR table holds miscellanous information about the repository. |
| 127 | @ -- in the form of name-value pairs. |
| 128 | @ -- |
| 129 | @ CREATE TABLE config( |
| 130 | @ name TEXT PRIMARY KEY NOT NULL, -- Primary name of the entry |
| 131 | @ value CLOB, -- Content of the named parameter |
| 132 | @ mtime DATE, -- last modified. seconds since 1970 |
| 133 | @ CHECK( typeof(name)='text' AND length(name)>=1 ) |
| 134 | @ ); |
| 135 | @ |
| 136 | @ -- Artifacts that should not be processed are identified in the |
| 137 | @ -- "shun" table. Artifacts that are control-file forgeries or |
| @@ -128,11 +141,15 @@ | |
| 141 | @ -- |
| 142 | @ -- Shunned artifacts do not exist in the blob table. Hence they |
| 143 | @ -- have not artifact ID (rid) and we thus must store their full |
| 144 | @ -- UUID. |
| 145 | @ -- |
| 146 | @ CREATE TABLE shun( |
| 147 | @ uuid UNIQUE, -- UUID of artifact to be shunned. Canonical form |
| 148 | @ mtime DATE, -- When added. seconds since 1970 |
| 149 | @ scom TEXT -- Optional text explaining why the shun occurred |
| 150 | @ ); |
| 151 | @ |
| 152 | @ -- Artifacts that should not be pushed are stored in the "private" |
| 153 | @ -- table. Private artifacts are omitted from the "unclustered" and |
| 154 | @ -- "unsent" tables. |
| 155 | @ -- |
| @@ -140,17 +157,19 @@ | |
| 157 | @ |
| 158 | @ -- An entry in this table describes a database query that generates a |
| 159 | @ -- table of tickets. |
| 160 | @ -- |
| 161 | @ CREATE TABLE reportfmt( |
| 162 | @ rn INTEGER PRIMARY KEY, -- Report number |
| 163 | @ owner TEXT, -- Owner of this report format (not used) |
| 164 | @ title TEXT UNIQUE, -- Title of this report |
| 165 | @ mtime DATE, -- Last modified. seconds since 1970 |
| 166 | @ cols TEXT, -- A color-key specification |
| 167 | @ sqlcode TEXT -- An SQL SELECT statement for this report |
| 168 | @ ); |
| 169 | @ INSERT INTO reportfmt(title,mtime,cols,sqlcode) |
| 170 | @ VALUES('All Tickets',julianday('1970-01-01'),'#ffffff Key: |
| 171 | @ #f2dcdc Active |
| 172 | @ #e8e8e8 Review |
| 173 | @ #cfe8bd Fixed |
| 174 | @ #bde5d6 Tested |
| 175 | @ #cacae5 Deferred |
| @@ -176,12 +195,13 @@ | |
| 195 | @ -- |
| 196 | @ -- This table contains sensitive information and should not be shared |
| 197 | @ -- with unauthorized users. |
| 198 | @ -- |
| 199 | @ CREATE TABLE concealed( |
| 200 | @ hash TEXT PRIMARY KEY, -- The SHA1 hash of content |
| 201 | @ mtime DATE, -- Time created. Seconds since 1970 |
| 202 | @ content TEXT -- Content intended to be concealed |
| 203 | @ ); |
| 204 | ; |
| 205 | |
| 206 | const char zRepositorySchema2[] = |
| 207 | @ -- Filenames |
| @@ -214,11 +234,11 @@ | |
| 234 | @ -- |
| 235 | @ CREATE TABLE plink( |
| 236 | @ pid INTEGER REFERENCES blob, -- Parent manifest |
| 237 | @ cid INTEGER REFERENCES blob, -- Child manifest |
| 238 | @ isprim BOOLEAN, -- pid is the primary parent of cid |
| 239 | @ mtime DATETIME, -- the date/time stamp on cid. Julian day. |
| 240 | @ UNIQUE(pid, cid) |
| 241 | @ ); |
| 242 | @ CREATE INDEX plink_i2 ON plink(cid,pid); |
| 243 | @ |
| 244 | @ -- A "leaf" checkin is a checkin that has no children in the same |
| @@ -232,11 +252,11 @@ | |
| 252 | @ |
| 253 | @ -- Events used to generate a timeline |
| 254 | @ -- |
| 255 | @ CREATE TABLE event( |
| 256 | @ type TEXT, -- Type of event: 'ci', 'w', 'e', 't' |
| 257 | @ mtime DATETIME, -- Time of occurrence. Julian day. |
| 258 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 259 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 260 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 261 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 262 | @ euser TEXT, -- User set by 'user' property |
| @@ -319,11 +339,11 @@ | |
| 339 | @ tagid INTEGER REFERENCES tag, -- The tag that added or removed |
| 340 | @ tagtype INTEGER, -- 0:-,cancel 1:+,single 2:*,propagate |
| 341 | @ srcid INTEGER REFERENCES blob, -- Artifact of tag. 0 for propagated tags |
| 342 | @ origid INTEGER REFERENCES blob, -- check-in holding propagated tag |
| 343 | @ value TEXT, -- Value of the tag. Might be NULL. |
| 344 | @ mtime TIMESTAMP, -- Time of addition or removal. Julian day |
| 345 | @ rid INTEGER REFERENCE blob, -- Artifact tag is applied to |
| 346 | @ UNIQUE(rid, tagid) |
| 347 | @ ); |
| 348 | @ CREATE INDEX tagxref_i1 ON tagxref(tagid, mtime); |
| 349 | @ |
| @@ -334,11 +354,11 @@ | |
| 354 | @ -- |
| 355 | @ CREATE TABLE backlink( |
| 356 | @ target TEXT, -- Where the hyperlink points to |
| 357 | @ srctype INT, -- 0: check-in 1: ticket 2: wiki |
| 358 | @ srcid INT, -- rid for checkin or wiki. tkt_id for ticket. |
| 359 | @ mtime TIMESTAMP, -- time that the hyperlink was added. Julian day. |
| 360 | @ UNIQUE(target, srctype, srcid) |
| 361 | @ ); |
| 362 | @ CREATE INDEX backlink_src ON backlink(srcid, srctype); |
| 363 | @ |
| 364 | @ -- Each attachment is an entry in the following table. Only |
| @@ -345,11 +365,11 @@ | |
| 365 | @ -- the most recent attachment (identified by the D card) is saved. |
| 366 | @ -- |
| 367 | @ CREATE TABLE attachment( |
| 368 | @ attachid INTEGER PRIMARY KEY, -- Local id for this attachment |
| 369 | @ isLatest BOOLEAN DEFAULT 0, -- True if this is the one to use |
| 370 | @ mtime TIMESTAMP, -- Last changed. Julian day. |
| 371 | @ src TEXT, -- UUID of the attachment. NULL to delete |
| 372 | @ target TEXT, -- Object attached to. Wikiname or Tkt UUID |
| 373 | @ filename TEXT, -- Filename for the attachment |
| 374 | @ comment TEXT, -- Comment associated with this attachment |
| 375 | @ user TEXT -- Name of user adding attachment |
| @@ -443,11 +463,11 @@ | |
| 463 | @ chnged INT DEFAULT 0, -- 0:unchnged 1:edited 2:m-chng 3:m-add |
| 464 | @ deleted BOOLEAN DEFAULT 0, -- True if deleted |
| 465 | @ isexe BOOLEAN, -- True if file should be executable |
| 466 | @ rid INTEGER, -- Originally from this repository record |
| 467 | @ mrid INTEGER, -- Based on this record due to a merge |
| 468 | @ mtime INTEGER, -- Mtime of file on disk. sec since 1970 |
| 469 | @ pathname TEXT, -- Full pathname relative to root |
| 470 | @ origname TEXT, -- Original pathname. NULL if unchanged |
| 471 | @ UNIQUE(pathname,vid) |
| 472 | @ ); |
| 473 | @ |
| 474 |
+7
-6
| --- src/setup.c | ||
| +++ src/setup.c | ||
| @@ -354,12 +354,12 @@ | ||
| 354 | 354 | style_footer(); |
| 355 | 355 | return; |
| 356 | 356 | } |
| 357 | 357 | login_verify_csrf_secret(); |
| 358 | 358 | db_multi_exec( |
| 359 | - "REPLACE INTO user(uid,login,info,pw,cap) " | |
| 360 | - "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')", | |
| 359 | + "REPLACE INTO user(uid,login,info,pw,cap,mtime) " | |
| 360 | + "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s',now())", | |
| 361 | 361 | uid, P("login"), P("info"), zPw, zCap |
| 362 | 362 | ); |
| 363 | 363 | if( atoi(PD("all","0"))>0 ){ |
| 364 | 364 | Blob sql; |
| 365 | 365 | char *zErr = 0; |
| @@ -375,11 +375,12 @@ | ||
| 375 | 375 | blob_appendf(&sql, |
| 376 | 376 | "UPDATE user SET login=%Q," |
| 377 | 377 | " pw=coalesce(shared_secret(%Q,%Q," |
| 378 | 378 | "(SELECT value FROM config WHERE name='project-code')),pw)," |
| 379 | 379 | " info=%Q," |
| 380 | - " cap=%Q" | |
| 380 | + " cap=%Q," | |
| 381 | + " mtime=now()" | |
| 381 | 382 | " WHERE login=%Q;", |
| 382 | 383 | zLogin, P("pw"), zLogin, P("info"), zCap, |
| 383 | 384 | zOldLogin |
| 384 | 385 | ); |
| 385 | 386 | login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); |
| @@ -1286,18 +1287,18 @@ | ||
| 1286 | 1287 | if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){ |
| 1287 | 1288 | Blob img; |
| 1288 | 1289 | Stmt ins; |
| 1289 | 1290 | blob_init(&img, aImg, szImg); |
| 1290 | 1291 | db_prepare(&ins, |
| 1291 | - "REPLACE INTO config(name, value)" | |
| 1292 | - " VALUES('logo-image',:bytes)" | |
| 1292 | + "REPLACE INTO config(name,value,mtime)" | |
| 1293 | + " VALUES('logo-image',:bytes,now())" | |
| 1293 | 1294 | ); |
| 1294 | 1295 | db_bind_blob(&ins, ":bytes", &img); |
| 1295 | 1296 | db_step(&ins); |
| 1296 | 1297 | db_finalize(&ins); |
| 1297 | 1298 | db_multi_exec( |
| 1298 | - "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)", | |
| 1299 | + "REPLACE INTO config(name,value,mtime) VALUES('logo-mimetype',%Q,now())", | |
| 1299 | 1300 | zMime |
| 1300 | 1301 | ); |
| 1301 | 1302 | db_end_transaction(0); |
| 1302 | 1303 | cgi_redirect("setup_logo"); |
| 1303 | 1304 | }else if( P("clr")!=0 ){ |
| 1304 | 1305 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -354,12 +354,12 @@ | |
| 354 | style_footer(); |
| 355 | return; |
| 356 | } |
| 357 | login_verify_csrf_secret(); |
| 358 | db_multi_exec( |
| 359 | "REPLACE INTO user(uid,login,info,pw,cap) " |
| 360 | "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s')", |
| 361 | uid, P("login"), P("info"), zPw, zCap |
| 362 | ); |
| 363 | if( atoi(PD("all","0"))>0 ){ |
| 364 | Blob sql; |
| 365 | char *zErr = 0; |
| @@ -375,11 +375,12 @@ | |
| 375 | blob_appendf(&sql, |
| 376 | "UPDATE user SET login=%Q," |
| 377 | " pw=coalesce(shared_secret(%Q,%Q," |
| 378 | "(SELECT value FROM config WHERE name='project-code')),pw)," |
| 379 | " info=%Q," |
| 380 | " cap=%Q" |
| 381 | " WHERE login=%Q;", |
| 382 | zLogin, P("pw"), zLogin, P("info"), zCap, |
| 383 | zOldLogin |
| 384 | ); |
| 385 | login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); |
| @@ -1286,18 +1287,18 @@ | |
| 1286 | if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){ |
| 1287 | Blob img; |
| 1288 | Stmt ins; |
| 1289 | blob_init(&img, aImg, szImg); |
| 1290 | db_prepare(&ins, |
| 1291 | "REPLACE INTO config(name, value)" |
| 1292 | " VALUES('logo-image',:bytes)" |
| 1293 | ); |
| 1294 | db_bind_blob(&ins, ":bytes", &img); |
| 1295 | db_step(&ins); |
| 1296 | db_finalize(&ins); |
| 1297 | db_multi_exec( |
| 1298 | "REPLACE INTO config(name, value) VALUES('logo-mimetype',%Q)", |
| 1299 | zMime |
| 1300 | ); |
| 1301 | db_end_transaction(0); |
| 1302 | cgi_redirect("setup_logo"); |
| 1303 | }else if( P("clr")!=0 ){ |
| 1304 |
| --- src/setup.c | |
| +++ src/setup.c | |
| @@ -354,12 +354,12 @@ | |
| 354 | style_footer(); |
| 355 | return; |
| 356 | } |
| 357 | login_verify_csrf_secret(); |
| 358 | db_multi_exec( |
| 359 | "REPLACE INTO user(uid,login,info,pw,cap,mtime) " |
| 360 | "VALUES(nullif(%d,0),%Q,%Q,%Q,'%s',now())", |
| 361 | uid, P("login"), P("info"), zPw, zCap |
| 362 | ); |
| 363 | if( atoi(PD("all","0"))>0 ){ |
| 364 | Blob sql; |
| 365 | char *zErr = 0; |
| @@ -375,11 +375,12 @@ | |
| 375 | blob_appendf(&sql, |
| 376 | "UPDATE user SET login=%Q," |
| 377 | " pw=coalesce(shared_secret(%Q,%Q," |
| 378 | "(SELECT value FROM config WHERE name='project-code')),pw)," |
| 379 | " info=%Q," |
| 380 | " cap=%Q," |
| 381 | " mtime=now()" |
| 382 | " WHERE login=%Q;", |
| 383 | zLogin, P("pw"), zLogin, P("info"), zCap, |
| 384 | zOldLogin |
| 385 | ); |
| 386 | login_group_sql(blob_str(&sql), "<li> ", " </li>\n", &zErr); |
| @@ -1286,18 +1287,18 @@ | |
| 1287 | if( P("set")!=0 && zMime && zMime[0] && szImg>0 ){ |
| 1288 | Blob img; |
| 1289 | Stmt ins; |
| 1290 | blob_init(&img, aImg, szImg); |
| 1291 | db_prepare(&ins, |
| 1292 | "REPLACE INTO config(name,value,mtime)" |
| 1293 | " VALUES('logo-image',:bytes,now())" |
| 1294 | ); |
| 1295 | db_bind_blob(&ins, ":bytes", &img); |
| 1296 | db_step(&ins); |
| 1297 | db_finalize(&ins); |
| 1298 | db_multi_exec( |
| 1299 | "REPLACE INTO config(name,value,mtime) VALUES('logo-mimetype',%Q,now())", |
| 1300 | zMime |
| 1301 | ); |
| 1302 | db_end_transaction(0); |
| 1303 | cgi_redirect("setup_logo"); |
| 1304 | }else if( P("clr")!=0 ){ |
| 1305 |
+2
-2
| --- src/sha1.c | ||
| +++ src/sha1.c | ||
| @@ -266,11 +266,11 @@ | ||
| 266 | 266 | FILE *in; |
| 267 | 267 | SHA1Context ctx; |
| 268 | 268 | unsigned char zResult[20]; |
| 269 | 269 | char zBuf[10240]; |
| 270 | 270 | |
| 271 | - in = fopen(zFilename,"rb"); | |
| 271 | + in = fossil_fopen(zFilename,"rb"); | |
| 272 | 272 | if( in==0 ){ |
| 273 | 273 | return 1; |
| 274 | 274 | } |
| 275 | 275 | SHA1Init(&ctx); |
| 276 | 276 | for(;;){ |
| @@ -430,9 +430,9 @@ | ||
| 430 | 430 | blob_read_from_channel(&in, stdin, -1); |
| 431 | 431 | sha1sum_blob(&in, &cksum); |
| 432 | 432 | }else{ |
| 433 | 433 | sha1sum_file(g.argv[i], &cksum); |
| 434 | 434 | } |
| 435 | - printf("%s %s\n", blob_str(&cksum), g.argv[i]); | |
| 435 | + fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); | |
| 436 | 436 | blob_reset(&cksum); |
| 437 | 437 | } |
| 438 | 438 | } |
| 439 | 439 |
| --- src/sha1.c | |
| +++ src/sha1.c | |
| @@ -266,11 +266,11 @@ | |
| 266 | FILE *in; |
| 267 | SHA1Context ctx; |
| 268 | unsigned char zResult[20]; |
| 269 | char zBuf[10240]; |
| 270 | |
| 271 | in = fopen(zFilename,"rb"); |
| 272 | if( in==0 ){ |
| 273 | return 1; |
| 274 | } |
| 275 | SHA1Init(&ctx); |
| 276 | for(;;){ |
| @@ -430,9 +430,9 @@ | |
| 430 | blob_read_from_channel(&in, stdin, -1); |
| 431 | sha1sum_blob(&in, &cksum); |
| 432 | }else{ |
| 433 | sha1sum_file(g.argv[i], &cksum); |
| 434 | } |
| 435 | printf("%s %s\n", blob_str(&cksum), g.argv[i]); |
| 436 | blob_reset(&cksum); |
| 437 | } |
| 438 | } |
| 439 |
| --- src/sha1.c | |
| +++ src/sha1.c | |
| @@ -266,11 +266,11 @@ | |
| 266 | FILE *in; |
| 267 | SHA1Context ctx; |
| 268 | unsigned char zResult[20]; |
| 269 | char zBuf[10240]; |
| 270 | |
| 271 | in = fossil_fopen(zFilename,"rb"); |
| 272 | if( in==0 ){ |
| 273 | return 1; |
| 274 | } |
| 275 | SHA1Init(&ctx); |
| 276 | for(;;){ |
| @@ -430,9 +430,9 @@ | |
| 430 | blob_read_from_channel(&in, stdin, -1); |
| 431 | sha1sum_blob(&in, &cksum); |
| 432 | }else{ |
| 433 | sha1sum_file(g.argv[i], &cksum); |
| 434 | } |
| 435 | fossil_print("%s %s\n", blob_str(&cksum), g.argv[i]); |
| 436 | blob_reset(&cksum); |
| 437 | } |
| 438 | } |
| 439 |
+11
-8
| --- src/shell.c | ||
| +++ src/shell.c | ||
| @@ -68,21 +68,21 @@ | ||
| 68 | 68 | * thus we always assume that we have a console. That can be |
| 69 | 69 | * overridden with the -batch command line option. |
| 70 | 70 | */ |
| 71 | 71 | #define isatty(x) 1 |
| 72 | 72 | #endif |
| 73 | + | |
| 74 | +/* True if the timer is enabled */ | |
| 75 | +static int enableTimer = 0; | |
| 73 | 76 | |
| 74 | 77 | #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 75 | 78 | #include <sys/time.h> |
| 76 | 79 | #include <sys/resource.h> |
| 77 | 80 | |
| 78 | 81 | /* Saved resource information for the beginning of an operation */ |
| 79 | 82 | static struct rusage sBegin; |
| 80 | 83 | |
| 81 | -/* True if the timer is enabled */ | |
| 82 | -static int enableTimer = 0; | |
| 83 | - | |
| 84 | 84 | /* |
| 85 | 85 | ** Begin timing an operation |
| 86 | 86 | */ |
| 87 | 87 | static void beginTimer(void){ |
| 88 | 88 | if( enableTimer ){ |
| @@ -122,13 +122,10 @@ | ||
| 122 | 122 | static FILETIME ftKernelBegin; |
| 123 | 123 | static FILETIME ftUserBegin; |
| 124 | 124 | typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); |
| 125 | 125 | static GETPROCTIMES getProcessTimesAddr = NULL; |
| 126 | 126 | |
| 127 | -/* True if the timer is enabled */ | |
| 128 | -static int enableTimer = 0; | |
| 129 | - | |
| 130 | 127 | /* |
| 131 | 128 | ** Check to see if we have timer support. Return 1 if necessary |
| 132 | 129 | ** support found (or found previously). |
| 133 | 130 | */ |
| 134 | 131 | static int hasTimer(void){ |
| @@ -2197,12 +2194,12 @@ | ||
| 2197 | 2194 | int i, n; |
| 2198 | 2195 | open_db(p); |
| 2199 | 2196 | |
| 2200 | 2197 | /* convert testctrl text option to value. allow any unique prefix |
| 2201 | 2198 | ** of the option name, or a numerical value. */ |
| 2202 | - n = strlen(azArg[1]); | |
| 2203 | - for(i=0; i<sizeof(aCtrl)/sizeof(aCtrl[0]); i++){ | |
| 2199 | + n = strlen30(azArg[1]); | |
| 2200 | + for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){ | |
| 2204 | 2201 | if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ |
| 2205 | 2202 | if( testctrl<0 ){ |
| 2206 | 2203 | testctrl = aCtrl[i].ctrlCode; |
| 2207 | 2204 | }else{ |
| 2208 | 2205 | fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]); |
| @@ -2650,10 +2647,11 @@ | ||
| 2650 | 2647 | static void main_init(struct callback_data *data) { |
| 2651 | 2648 | memset(data, 0, sizeof(*data)); |
| 2652 | 2649 | data->mode = MODE_List; |
| 2653 | 2650 | memcpy(data->separator,"|", 2); |
| 2654 | 2651 | data->showHeader = 0; |
| 2652 | + sqlite3_config(SQLITE_CONFIG_URI, 1); | |
| 2655 | 2653 | sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); |
| 2656 | 2654 | sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); |
| 2657 | 2655 | sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); |
| 2658 | 2656 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 2659 | 2657 | } |
| @@ -2664,10 +2662,15 @@ | ||
| 2664 | 2662 | const char *zInitFile = 0; |
| 2665 | 2663 | char *zFirstCmd = 0; |
| 2666 | 2664 | int i; |
| 2667 | 2665 | int rc = 0; |
| 2668 | 2666 | |
| 2667 | + if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ | |
| 2668 | + fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", | |
| 2669 | + sqlite3_sourceid(), SQLITE_SOURCE_ID); | |
| 2670 | + exit(1); | |
| 2671 | + } | |
| 2669 | 2672 | Argv0 = argv[0]; |
| 2670 | 2673 | main_init(&data); |
| 2671 | 2674 | stdin_is_interactive = isatty(0); |
| 2672 | 2675 | |
| 2673 | 2676 | /* Make sure we have a valid signal handler early, before anything |
| 2674 | 2677 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -68,21 +68,21 @@ | |
| 68 | * thus we always assume that we have a console. That can be |
| 69 | * overridden with the -batch command line option. |
| 70 | */ |
| 71 | #define isatty(x) 1 |
| 72 | #endif |
| 73 | |
| 74 | #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 75 | #include <sys/time.h> |
| 76 | #include <sys/resource.h> |
| 77 | |
| 78 | /* Saved resource information for the beginning of an operation */ |
| 79 | static struct rusage sBegin; |
| 80 | |
| 81 | /* True if the timer is enabled */ |
| 82 | static int enableTimer = 0; |
| 83 | |
| 84 | /* |
| 85 | ** Begin timing an operation |
| 86 | */ |
| 87 | static void beginTimer(void){ |
| 88 | if( enableTimer ){ |
| @@ -122,13 +122,10 @@ | |
| 122 | static FILETIME ftKernelBegin; |
| 123 | static FILETIME ftUserBegin; |
| 124 | typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); |
| 125 | static GETPROCTIMES getProcessTimesAddr = NULL; |
| 126 | |
| 127 | /* True if the timer is enabled */ |
| 128 | static int enableTimer = 0; |
| 129 | |
| 130 | /* |
| 131 | ** Check to see if we have timer support. Return 1 if necessary |
| 132 | ** support found (or found previously). |
| 133 | */ |
| 134 | static int hasTimer(void){ |
| @@ -2197,12 +2194,12 @@ | |
| 2197 | int i, n; |
| 2198 | open_db(p); |
| 2199 | |
| 2200 | /* convert testctrl text option to value. allow any unique prefix |
| 2201 | ** of the option name, or a numerical value. */ |
| 2202 | n = strlen(azArg[1]); |
| 2203 | for(i=0; i<sizeof(aCtrl)/sizeof(aCtrl[0]); i++){ |
| 2204 | if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ |
| 2205 | if( testctrl<0 ){ |
| 2206 | testctrl = aCtrl[i].ctrlCode; |
| 2207 | }else{ |
| 2208 | fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]); |
| @@ -2650,10 +2647,11 @@ | |
| 2650 | static void main_init(struct callback_data *data) { |
| 2651 | memset(data, 0, sizeof(*data)); |
| 2652 | data->mode = MODE_List; |
| 2653 | memcpy(data->separator,"|", 2); |
| 2654 | data->showHeader = 0; |
| 2655 | sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); |
| 2656 | sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); |
| 2657 | sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); |
| 2658 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 2659 | } |
| @@ -2664,10 +2662,15 @@ | |
| 2664 | const char *zInitFile = 0; |
| 2665 | char *zFirstCmd = 0; |
| 2666 | int i; |
| 2667 | int rc = 0; |
| 2668 | |
| 2669 | Argv0 = argv[0]; |
| 2670 | main_init(&data); |
| 2671 | stdin_is_interactive = isatty(0); |
| 2672 | |
| 2673 | /* Make sure we have a valid signal handler early, before anything |
| 2674 |
| --- src/shell.c | |
| +++ src/shell.c | |
| @@ -68,21 +68,21 @@ | |
| 68 | * thus we always assume that we have a console. That can be |
| 69 | * overridden with the -batch command line option. |
| 70 | */ |
| 71 | #define isatty(x) 1 |
| 72 | #endif |
| 73 | |
| 74 | /* True if the timer is enabled */ |
| 75 | static int enableTimer = 0; |
| 76 | |
| 77 | #if !defined(_WIN32) && !defined(WIN32) && !defined(__OS2__) && !defined(__RTP__) && !defined(_WRS_KERNEL) |
| 78 | #include <sys/time.h> |
| 79 | #include <sys/resource.h> |
| 80 | |
| 81 | /* Saved resource information for the beginning of an operation */ |
| 82 | static struct rusage sBegin; |
| 83 | |
| 84 | /* |
| 85 | ** Begin timing an operation |
| 86 | */ |
| 87 | static void beginTimer(void){ |
| 88 | if( enableTimer ){ |
| @@ -122,13 +122,10 @@ | |
| 122 | static FILETIME ftKernelBegin; |
| 123 | static FILETIME ftUserBegin; |
| 124 | typedef BOOL (WINAPI *GETPROCTIMES)(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME, LPFILETIME); |
| 125 | static GETPROCTIMES getProcessTimesAddr = NULL; |
| 126 | |
| 127 | /* |
| 128 | ** Check to see if we have timer support. Return 1 if necessary |
| 129 | ** support found (or found previously). |
| 130 | */ |
| 131 | static int hasTimer(void){ |
| @@ -2197,12 +2194,12 @@ | |
| 2194 | int i, n; |
| 2195 | open_db(p); |
| 2196 | |
| 2197 | /* convert testctrl text option to value. allow any unique prefix |
| 2198 | ** of the option name, or a numerical value. */ |
| 2199 | n = strlen30(azArg[1]); |
| 2200 | for(i=0; i<(int)(sizeof(aCtrl)/sizeof(aCtrl[0])); i++){ |
| 2201 | if( strncmp(azArg[1], aCtrl[i].zCtrlName, n)==0 ){ |
| 2202 | if( testctrl<0 ){ |
| 2203 | testctrl = aCtrl[i].ctrlCode; |
| 2204 | }else{ |
| 2205 | fprintf(stderr, "ambiguous option name: \"%s\"\n", azArg[i]); |
| @@ -2650,10 +2647,11 @@ | |
| 2647 | static void main_init(struct callback_data *data) { |
| 2648 | memset(data, 0, sizeof(*data)); |
| 2649 | data->mode = MODE_List; |
| 2650 | memcpy(data->separator,"|", 2); |
| 2651 | data->showHeader = 0; |
| 2652 | sqlite3_config(SQLITE_CONFIG_URI, 1); |
| 2653 | sqlite3_config(SQLITE_CONFIG_LOG, shellLog, data); |
| 2654 | sqlite3_snprintf(sizeof(mainPrompt), mainPrompt,"sqlite> "); |
| 2655 | sqlite3_snprintf(sizeof(continuePrompt), continuePrompt," ...> "); |
| 2656 | sqlite3_config(SQLITE_CONFIG_SINGLETHREAD); |
| 2657 | } |
| @@ -2664,10 +2662,15 @@ | |
| 2662 | const char *zInitFile = 0; |
| 2663 | char *zFirstCmd = 0; |
| 2664 | int i; |
| 2665 | int rc = 0; |
| 2666 | |
| 2667 | if( strcmp(sqlite3_sourceid(),SQLITE_SOURCE_ID)!=0 ){ |
| 2668 | fprintf(stderr, "SQLite header and source version mismatch\n%s\n%s\n", |
| 2669 | sqlite3_sourceid(), SQLITE_SOURCE_ID); |
| 2670 | exit(1); |
| 2671 | } |
| 2672 | Argv0 = argv[0]; |
| 2673 | main_init(&data); |
| 2674 | stdin_is_interactive = isatty(0); |
| 2675 | |
| 2676 | /* Make sure we have a valid signal handler early, before anything |
| 2677 |
+15
-1
| --- src/shun.c | ||
| +++ src/shun.c | ||
| @@ -81,17 +81,31 @@ | ||
| 81 | 81 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 82 | 82 | @ can pulled in from other respositories.</p> |
| 83 | 83 | } |
| 84 | 84 | } |
| 85 | 85 | if( zUuid && P("add") ){ |
| 86 | + int rid, tagid; | |
| 86 | 87 | login_verify_csrf_secret(); |
| 87 | - db_multi_exec("INSERT OR IGNORE INTO shun VALUES('%s')", zUuid); | |
| 88 | + db_multi_exec( | |
| 89 | + "INSERT OR IGNORE INTO shun(uuid,mtime)" | |
| 90 | + " VALUES('%s', now())", zUuid); | |
| 88 | 91 | @ <p class="shunned">Artifact |
| 89 | 92 | @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> has been |
| 90 | 93 | @ shunned. It will no longer be pushed. |
| 91 | 94 | @ It will be removed from the repository the next time the respository |
| 92 | 95 | @ is rebuilt using the <b>fossil rebuild</b> command-line</p> |
| 96 | + db_multi_exec("DELETE FROM attachment WHERE src=%Q", zUuid); | |
| 97 | + rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); | |
| 98 | + if( rid ){ | |
| 99 | + db_multi_exec("DELETE FROM event WHERE objid=%d", rid); | |
| 100 | + } | |
| 101 | + tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", zUuid); | |
| 102 | + if( tagid ){ | |
| 103 | + db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", zUuid); | |
| 104 | + db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); | |
| 105 | + db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); | |
| 106 | + } | |
| 93 | 107 | } |
| 94 | 108 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 95 | 109 | @ artifact content will be purged from the repository the next time the |
| 96 | 110 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 97 | 111 | @ bottom of this page.</p> |
| 98 | 112 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -81,17 +81,31 @@ | |
| 81 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 82 | @ can pulled in from other respositories.</p> |
| 83 | } |
| 84 | } |
| 85 | if( zUuid && P("add") ){ |
| 86 | login_verify_csrf_secret(); |
| 87 | db_multi_exec("INSERT OR IGNORE INTO shun VALUES('%s')", zUuid); |
| 88 | @ <p class="shunned">Artifact |
| 89 | @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> has been |
| 90 | @ shunned. It will no longer be pushed. |
| 91 | @ It will be removed from the repository the next time the respository |
| 92 | @ is rebuilt using the <b>fossil rebuild</b> command-line</p> |
| 93 | } |
| 94 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 95 | @ artifact content will be purged from the repository the next time the |
| 96 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 97 | @ bottom of this page.</p> |
| 98 |
| --- src/shun.c | |
| +++ src/shun.c | |
| @@ -81,17 +81,31 @@ | |
| 81 | @ <b>fossil rebuild</b> command-line before the artifact content |
| 82 | @ can pulled in from other respositories.</p> |
| 83 | } |
| 84 | } |
| 85 | if( zUuid && P("add") ){ |
| 86 | int rid, tagid; |
| 87 | login_verify_csrf_secret(); |
| 88 | db_multi_exec( |
| 89 | "INSERT OR IGNORE INTO shun(uuid,mtime)" |
| 90 | " VALUES('%s', now())", zUuid); |
| 91 | @ <p class="shunned">Artifact |
| 92 | @ <a href="%s(g.zTop)/artifact/%s(zUuid)">%s(zUuid)</a> has been |
| 93 | @ shunned. It will no longer be pushed. |
| 94 | @ It will be removed from the repository the next time the respository |
| 95 | @ is rebuilt using the <b>fossil rebuild</b> command-line</p> |
| 96 | db_multi_exec("DELETE FROM attachment WHERE src=%Q", zUuid); |
| 97 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid=%Q", zUuid); |
| 98 | if( rid ){ |
| 99 | db_multi_exec("DELETE FROM event WHERE objid=%d", rid); |
| 100 | } |
| 101 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='tkt-%q'", zUuid); |
| 102 | if( tagid ){ |
| 103 | db_multi_exec("DELETE FROM ticket WHERE tkt_uuid=%Q", zUuid); |
| 104 | db_multi_exec("DELETE FROM tag WHERE tagid=%d", tagid); |
| 105 | db_multi_exec("DELETE FROM tagxref WHERE tagid=%d", tagid); |
| 106 | } |
| 107 | } |
| 108 | @ <p>A shunned artifact will not be pushed nor accepted in a pull and the |
| 109 | @ artifact content will be purged from the repository the next time the |
| 110 | @ repository is rebuilt. A list of shunned artifacts can be seen at the |
| 111 | @ bottom of this page.</p> |
| 112 |
+27
-18
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -25,11 +25,12 @@ | ||
| 25 | 25 | /* |
| 26 | 26 | ** A black-and-white theme with the project title in a bar across the top |
| 27 | 27 | ** and no logo image. |
| 28 | 28 | */ |
| 29 | 29 | static const char zBuiltinSkin1[] = |
| 30 | -@ REPLACE INTO config VALUES('css','/* General settings for the entire page */ | |
| 30 | +@ REPLACE INTO config(name,mtime,value) | |
| 31 | +@ VALUES('css',now(),'/* General settings for the entire page */ | |
| 31 | 32 | @ body { |
| 32 | 33 | @ margin: 0ex 1ex; |
| 33 | 34 | @ padding: 0px; |
| 34 | 35 | @ background-color: white; |
| 35 | 36 | @ font-family: sans-serif; |
| @@ -152,11 +153,11 @@ | ||
| 152 | 153 | @ table.label-value th { |
| 153 | 154 | @ vertical-align: top; |
| 154 | 155 | @ text-align: right; |
| 155 | 156 | @ padding: 0.2ex 2ex; |
| 156 | 157 | @ }'); |
| 157 | -@ REPLACE INTO config VALUES('header','<html> | |
| 158 | +@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> | |
| 158 | 159 | @ <head> |
| 159 | 160 | @ <title>$<project_name>: $<title></title> |
| 160 | 161 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 161 | 162 | @ href="$home/timeline.rss"> |
| 162 | 163 | @ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css" |
| @@ -204,11 +205,12 @@ | ||
| 204 | 205 | @ } else { |
| 205 | 206 | @ html "<a href=''$home/login''>Login</a> " |
| 206 | 207 | @ } |
| 207 | 208 | @ </th1></div> |
| 208 | 209 | @ '); |
| 209 | -@ REPLACE INTO config VALUES('footer','<div class="footer"> | |
| 210 | +@ REPLACE INTO config(name,mtime,value) | |
| 211 | +@ VALUES('footer',now(),'<div class="footer"> | |
| 210 | 212 | @ Fossil version $manifest_version $manifest_date |
| 211 | 213 | @ </div> |
| 212 | 214 | @ </body></html> |
| 213 | 215 | @ '); |
| 214 | 216 | ; |
| @@ -216,11 +218,12 @@ | ||
| 216 | 218 | /* |
| 217 | 219 | ** A tan theme with the project title above the user identification |
| 218 | 220 | ** and no logo image. |
| 219 | 221 | */ |
| 220 | 222 | static const char zBuiltinSkin2[] = |
| 221 | -@ REPLACE INTO config VALUES('css','/* General settings for the entire page */ | |
| 223 | +@ REPLACE INTO config(name,mtime,value) | |
| 224 | +@ VALUES('css',now(),'/* General settings for the entire page */ | |
| 222 | 225 | @ body { |
| 223 | 226 | @ margin: 0ex 0ex; |
| 224 | 227 | @ padding: 0px; |
| 225 | 228 | @ background-color: #fef3bc; |
| 226 | 229 | @ font-family: sans-serif; |
| @@ -354,11 +357,11 @@ | ||
| 354 | 357 | @ vertical-align: top; |
| 355 | 358 | @ text-align: right; |
| 356 | 359 | @ padding: 0.2ex 2ex; |
| 357 | 360 | @ } |
| 358 | 361 | @ '); |
| 359 | -@ REPLACE INTO config VALUES('header','<html> | |
| 362 | +@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> | |
| 360 | 363 | @ <head> |
| 361 | 364 | @ <title>$<project_name>: $<title></title> |
| 362 | 365 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 363 | 366 | @ href="$home/timeline.rss"> |
| 364 | 367 | @ <link rel="stylesheet" href="$home/style.css?tan" type="text/css" |
| @@ -405,11 +408,12 @@ | ||
| 405 | 408 | @ } else { |
| 406 | 409 | @ html "<a href=''$home/login''>Login</a> " |
| 407 | 410 | @ } |
| 408 | 411 | @ </th1></div> |
| 409 | 412 | @ '); |
| 410 | -@ REPLACE INTO config VALUES('footer','<div class="footer"> | |
| 413 | +@ REPLACE INTO config(name,mtime,value) | |
| 414 | +@ VALUES('footer',now(),'<div class="footer"> | |
| 411 | 415 | @ Fossil version $manifest_version $manifest_date |
| 412 | 416 | @ </div> |
| 413 | 417 | @ </body></html> |
| 414 | 418 | @ '); |
| 415 | 419 | ; |
| @@ -417,11 +421,12 @@ | ||
| 417 | 421 | /* |
| 418 | 422 | ** Black letters on a white or cream background with the main menu |
| 419 | 423 | ** stuck on the left-hand side. |
| 420 | 424 | */ |
| 421 | 425 | static const char zBuiltinSkin3[] = |
| 422 | -@ REPLACE INTO config VALUES('css','/* General settings for the entire page */ | |
| 426 | +@ REPLACE INTO config(name,mtime,value) | |
| 427 | +@ VALUES('css',now(),'/* General settings for the entire page */ | |
| 423 | 428 | @ body { |
| 424 | 429 | @ margin:0px 0px 0px 0px; |
| 425 | 430 | @ padding:0px; |
| 426 | 431 | @ font-family:verdana, arial, helvetica, "sans serif"; |
| 427 | 432 | @ color:#333; |
| @@ -586,11 +591,11 @@ | ||
| 586 | 591 | @ table.label-value th { |
| 587 | 592 | @ vertical-align: top; |
| 588 | 593 | @ text-align: right; |
| 589 | 594 | @ padding: 0.2ex 2ex; |
| 590 | 595 | @ }'); |
| 591 | -@ REPLACE INTO config VALUES('header','<html> | |
| 596 | +@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> | |
| 592 | 597 | @ <head> |
| 593 | 598 | @ <title>$<project_name>: $<title></title> |
| 594 | 599 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 595 | 600 | @ href="$home/timeline.rss"> |
| 596 | 601 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -640,11 +645,11 @@ | ||
| 640 | 645 | @ html "<li><a href=''$home/login''>Login</a></li>" |
| 641 | 646 | @ } |
| 642 | 647 | @ </th1></ul></div> |
| 643 | 648 | @ <div id="container"> |
| 644 | 649 | @ '); |
| 645 | -@ REPLACE INTO config VALUES('footer','</div> | |
| 650 | +@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div> | |
| 646 | 651 | @ <div class="footer"> |
| 647 | 652 | @ Fossil version $manifest_version $manifest_date |
| 648 | 653 | @ </div> |
| 649 | 654 | @ </body></html> |
| 650 | 655 | @ '); |
| @@ -653,11 +658,12 @@ | ||
| 653 | 658 | |
| 654 | 659 | /* |
| 655 | 660 | ** Gradients and rounded corners. |
| 656 | 661 | */ |
| 657 | 662 | static const char zBuiltinSkin4[] = |
| 658 | -@ REPLACE INTO config VALUES('css','/* General settings for the entire page */ | |
| 663 | +@ REPLACE INTO config(name,mtime,value) | |
| 664 | +@ VALUES('css',now(),'/* General settings for the entire page */ | |
| 659 | 665 | @ html { |
| 660 | 666 | @ min-height: 100%; |
| 661 | 667 | @ } |
| 662 | 668 | @ body { |
| 663 | 669 | @ margin: 0ex 1ex; |
| @@ -880,11 +886,11 @@ | ||
| 880 | 886 | @ } |
| 881 | 887 | @ |
| 882 | 888 | @ textarea { |
| 883 | 889 | @ font-size: 1em; |
| 884 | 890 | @ }'); |
| 885 | -@ REPLACE INTO config VALUES('header','<html> | |
| 891 | +@ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> | |
| 886 | 892 | @ <head> |
| 887 | 893 | @ <title>$<project_name>: $<title></title> |
| 888 | 894 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 889 | 895 | @ href="$home/timeline.rss"> |
| 890 | 896 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -934,11 +940,11 @@ | ||
| 934 | 940 | @ html "<a href=''$home/login''>Login</a>" |
| 935 | 941 | @ } |
| 936 | 942 | @ </th1></ul></div> |
| 937 | 943 | @ <div id="container"> |
| 938 | 944 | @ '); |
| 939 | -@ REPLACE INTO config VALUES('footer','</div> | |
| 945 | +@ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div> | |
| 940 | 946 | @ <div class="footer"> |
| 941 | 947 | @ Fossil version $manifest_version $manifest_date |
| 942 | 948 | @ </div> |
| 943 | 949 | @ </body></html> |
| 944 | 950 | @ '); |
| @@ -984,17 +990,20 @@ | ||
| 984 | 990 | ** Memory to hold the returned string is obtained from malloc. |
| 985 | 991 | */ |
| 986 | 992 | static char *getSkin(int useDefault){ |
| 987 | 993 | Blob val; |
| 988 | 994 | blob_zero(&val); |
| 989 | - blob_appendf(&val, "REPLACE INTO config VALUES('css',%Q);\n", | |
| 995 | + blob_appendf(&val, | |
| 996 | + "REPLACE INTO config(name,value,mtime) VALUES('css',%Q,now());\n", | |
| 990 | 997 | useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS) |
| 991 | 998 | ); |
| 992 | - blob_appendf(&val, "REPLACE INTO config VALUES('header',%Q);\n", | |
| 999 | + blob_appendf(&val, | |
| 1000 | + "REPLACE INTO config(name,value,mtime) VALUES('header',%Q,now());\n", | |
| 993 | 1001 | useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader) |
| 994 | 1002 | ); |
| 995 | - blob_appendf(&val, "REPLACE INTO config VALUES('footer',%Q);\n", | |
| 1003 | + blob_appendf(&val, | |
| 1004 | + "REPLACE INTO config(name,value,mtime) VALUES('footer',%Q,now());\n", | |
| 996 | 1005 | useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter) |
| 997 | 1006 | ); |
| 998 | 1007 | return blob_str(&val); |
| 999 | 1008 | } |
| 1000 | 1009 | |
| @@ -1048,11 +1057,11 @@ | ||
| 1048 | 1057 | if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName) |
| 1049 | 1058 | || strcmp(zName, "Default")==0 ){ |
| 1050 | 1059 | zErr = mprintf("Skin name \"%h\" already exists. " |
| 1051 | 1060 | "Choose a different name.", P("sn")); |
| 1052 | 1061 | }else{ |
| 1053 | - db_multi_exec("INSERT INTO config VALUES(%Q,%Q)", | |
| 1062 | + db_multi_exec("INSERT INTO config(name,value,mtime) VALUES(%Q,%Q,now())", | |
| 1054 | 1063 | zName, zCurrent |
| 1055 | 1064 | ); |
| 1056 | 1065 | } |
| 1057 | 1066 | } |
| 1058 | 1067 | |
| @@ -1069,13 +1078,13 @@ | ||
| 1069 | 1078 | seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" |
| 1070 | 1079 | " AND value=%Q", zCurrent); |
| 1071 | 1080 | } |
| 1072 | 1081 | if( !seen ){ |
| 1073 | 1082 | db_multi_exec( |
| 1074 | - "INSERT INTO config VALUES(" | |
| 1083 | + "INSERT INTO config(name,value,mtime) VALUES(" | |
| 1075 | 1084 | " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," |
| 1076 | - " %Q)", zCurrent | |
| 1085 | + " %Q,now())", zCurrent | |
| 1077 | 1086 | ); |
| 1078 | 1087 | } |
| 1079 | 1088 | seen = 0; |
| 1080 | 1089 | for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){ |
| 1081 | 1090 | if( strcmp(aBuiltinSkin[i].zName, z)==0 ){ |
| 1082 | 1091 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -25,11 +25,12 @@ | |
| 25 | /* |
| 26 | ** A black-and-white theme with the project title in a bar across the top |
| 27 | ** and no logo image. |
| 28 | */ |
| 29 | static const char zBuiltinSkin1[] = |
| 30 | @ REPLACE INTO config VALUES('css','/* General settings for the entire page */ |
| 31 | @ body { |
| 32 | @ margin: 0ex 1ex; |
| 33 | @ padding: 0px; |
| 34 | @ background-color: white; |
| 35 | @ font-family: sans-serif; |
| @@ -152,11 +153,11 @@ | |
| 152 | @ table.label-value th { |
| 153 | @ vertical-align: top; |
| 154 | @ text-align: right; |
| 155 | @ padding: 0.2ex 2ex; |
| 156 | @ }'); |
| 157 | @ REPLACE INTO config VALUES('header','<html> |
| 158 | @ <head> |
| 159 | @ <title>$<project_name>: $<title></title> |
| 160 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 161 | @ href="$home/timeline.rss"> |
| 162 | @ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css" |
| @@ -204,11 +205,12 @@ | |
| 204 | @ } else { |
| 205 | @ html "<a href=''$home/login''>Login</a> " |
| 206 | @ } |
| 207 | @ </th1></div> |
| 208 | @ '); |
| 209 | @ REPLACE INTO config VALUES('footer','<div class="footer"> |
| 210 | @ Fossil version $manifest_version $manifest_date |
| 211 | @ </div> |
| 212 | @ </body></html> |
| 213 | @ '); |
| 214 | ; |
| @@ -216,11 +218,12 @@ | |
| 216 | /* |
| 217 | ** A tan theme with the project title above the user identification |
| 218 | ** and no logo image. |
| 219 | */ |
| 220 | static const char zBuiltinSkin2[] = |
| 221 | @ REPLACE INTO config VALUES('css','/* General settings for the entire page */ |
| 222 | @ body { |
| 223 | @ margin: 0ex 0ex; |
| 224 | @ padding: 0px; |
| 225 | @ background-color: #fef3bc; |
| 226 | @ font-family: sans-serif; |
| @@ -354,11 +357,11 @@ | |
| 354 | @ vertical-align: top; |
| 355 | @ text-align: right; |
| 356 | @ padding: 0.2ex 2ex; |
| 357 | @ } |
| 358 | @ '); |
| 359 | @ REPLACE INTO config VALUES('header','<html> |
| 360 | @ <head> |
| 361 | @ <title>$<project_name>: $<title></title> |
| 362 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 363 | @ href="$home/timeline.rss"> |
| 364 | @ <link rel="stylesheet" href="$home/style.css?tan" type="text/css" |
| @@ -405,11 +408,12 @@ | |
| 405 | @ } else { |
| 406 | @ html "<a href=''$home/login''>Login</a> " |
| 407 | @ } |
| 408 | @ </th1></div> |
| 409 | @ '); |
| 410 | @ REPLACE INTO config VALUES('footer','<div class="footer"> |
| 411 | @ Fossil version $manifest_version $manifest_date |
| 412 | @ </div> |
| 413 | @ </body></html> |
| 414 | @ '); |
| 415 | ; |
| @@ -417,11 +421,12 @@ | |
| 417 | /* |
| 418 | ** Black letters on a white or cream background with the main menu |
| 419 | ** stuck on the left-hand side. |
| 420 | */ |
| 421 | static const char zBuiltinSkin3[] = |
| 422 | @ REPLACE INTO config VALUES('css','/* General settings for the entire page */ |
| 423 | @ body { |
| 424 | @ margin:0px 0px 0px 0px; |
| 425 | @ padding:0px; |
| 426 | @ font-family:verdana, arial, helvetica, "sans serif"; |
| 427 | @ color:#333; |
| @@ -586,11 +591,11 @@ | |
| 586 | @ table.label-value th { |
| 587 | @ vertical-align: top; |
| 588 | @ text-align: right; |
| 589 | @ padding: 0.2ex 2ex; |
| 590 | @ }'); |
| 591 | @ REPLACE INTO config VALUES('header','<html> |
| 592 | @ <head> |
| 593 | @ <title>$<project_name>: $<title></title> |
| 594 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 595 | @ href="$home/timeline.rss"> |
| 596 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -640,11 +645,11 @@ | |
| 640 | @ html "<li><a href=''$home/login''>Login</a></li>" |
| 641 | @ } |
| 642 | @ </th1></ul></div> |
| 643 | @ <div id="container"> |
| 644 | @ '); |
| 645 | @ REPLACE INTO config VALUES('footer','</div> |
| 646 | @ <div class="footer"> |
| 647 | @ Fossil version $manifest_version $manifest_date |
| 648 | @ </div> |
| 649 | @ </body></html> |
| 650 | @ '); |
| @@ -653,11 +658,12 @@ | |
| 653 | |
| 654 | /* |
| 655 | ** Gradients and rounded corners. |
| 656 | */ |
| 657 | static const char zBuiltinSkin4[] = |
| 658 | @ REPLACE INTO config VALUES('css','/* General settings for the entire page */ |
| 659 | @ html { |
| 660 | @ min-height: 100%; |
| 661 | @ } |
| 662 | @ body { |
| 663 | @ margin: 0ex 1ex; |
| @@ -880,11 +886,11 @@ | |
| 880 | @ } |
| 881 | @ |
| 882 | @ textarea { |
| 883 | @ font-size: 1em; |
| 884 | @ }'); |
| 885 | @ REPLACE INTO config VALUES('header','<html> |
| 886 | @ <head> |
| 887 | @ <title>$<project_name>: $<title></title> |
| 888 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 889 | @ href="$home/timeline.rss"> |
| 890 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -934,11 +940,11 @@ | |
| 934 | @ html "<a href=''$home/login''>Login</a>" |
| 935 | @ } |
| 936 | @ </th1></ul></div> |
| 937 | @ <div id="container"> |
| 938 | @ '); |
| 939 | @ REPLACE INTO config VALUES('footer','</div> |
| 940 | @ <div class="footer"> |
| 941 | @ Fossil version $manifest_version $manifest_date |
| 942 | @ </div> |
| 943 | @ </body></html> |
| 944 | @ '); |
| @@ -984,17 +990,20 @@ | |
| 984 | ** Memory to hold the returned string is obtained from malloc. |
| 985 | */ |
| 986 | static char *getSkin(int useDefault){ |
| 987 | Blob val; |
| 988 | blob_zero(&val); |
| 989 | blob_appendf(&val, "REPLACE INTO config VALUES('css',%Q);\n", |
| 990 | useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS) |
| 991 | ); |
| 992 | blob_appendf(&val, "REPLACE INTO config VALUES('header',%Q);\n", |
| 993 | useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader) |
| 994 | ); |
| 995 | blob_appendf(&val, "REPLACE INTO config VALUES('footer',%Q);\n", |
| 996 | useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter) |
| 997 | ); |
| 998 | return blob_str(&val); |
| 999 | } |
| 1000 | |
| @@ -1048,11 +1057,11 @@ | |
| 1048 | if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName) |
| 1049 | || strcmp(zName, "Default")==0 ){ |
| 1050 | zErr = mprintf("Skin name \"%h\" already exists. " |
| 1051 | "Choose a different name.", P("sn")); |
| 1052 | }else{ |
| 1053 | db_multi_exec("INSERT INTO config VALUES(%Q,%Q)", |
| 1054 | zName, zCurrent |
| 1055 | ); |
| 1056 | } |
| 1057 | } |
| 1058 | |
| @@ -1069,13 +1078,13 @@ | |
| 1069 | seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" |
| 1070 | " AND value=%Q", zCurrent); |
| 1071 | } |
| 1072 | if( !seen ){ |
| 1073 | db_multi_exec( |
| 1074 | "INSERT INTO config VALUES(" |
| 1075 | " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," |
| 1076 | " %Q)", zCurrent |
| 1077 | ); |
| 1078 | } |
| 1079 | seen = 0; |
| 1080 | for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){ |
| 1081 | if( strcmp(aBuiltinSkin[i].zName, z)==0 ){ |
| 1082 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -25,11 +25,12 @@ | |
| 25 | /* |
| 26 | ** A black-and-white theme with the project title in a bar across the top |
| 27 | ** and no logo image. |
| 28 | */ |
| 29 | static const char zBuiltinSkin1[] = |
| 30 | @ REPLACE INTO config(name,mtime,value) |
| 31 | @ VALUES('css',now(),'/* General settings for the entire page */ |
| 32 | @ body { |
| 33 | @ margin: 0ex 1ex; |
| 34 | @ padding: 0px; |
| 35 | @ background-color: white; |
| 36 | @ font-family: sans-serif; |
| @@ -152,11 +153,11 @@ | |
| 153 | @ table.label-value th { |
| 154 | @ vertical-align: top; |
| 155 | @ text-align: right; |
| 156 | @ padding: 0.2ex 2ex; |
| 157 | @ }'); |
| 158 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 159 | @ <head> |
| 160 | @ <title>$<project_name>: $<title></title> |
| 161 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 162 | @ href="$home/timeline.rss"> |
| 163 | @ <link rel="stylesheet" href="$home/style.css?blackwhite" type="text/css" |
| @@ -204,11 +205,12 @@ | |
| 205 | @ } else { |
| 206 | @ html "<a href=''$home/login''>Login</a> " |
| 207 | @ } |
| 208 | @ </th1></div> |
| 209 | @ '); |
| 210 | @ REPLACE INTO config(name,mtime,value) |
| 211 | @ VALUES('footer',now(),'<div class="footer"> |
| 212 | @ Fossil version $manifest_version $manifest_date |
| 213 | @ </div> |
| 214 | @ </body></html> |
| 215 | @ '); |
| 216 | ; |
| @@ -216,11 +218,12 @@ | |
| 218 | /* |
| 219 | ** A tan theme with the project title above the user identification |
| 220 | ** and no logo image. |
| 221 | */ |
| 222 | static const char zBuiltinSkin2[] = |
| 223 | @ REPLACE INTO config(name,mtime,value) |
| 224 | @ VALUES('css',now(),'/* General settings for the entire page */ |
| 225 | @ body { |
| 226 | @ margin: 0ex 0ex; |
| 227 | @ padding: 0px; |
| 228 | @ background-color: #fef3bc; |
| 229 | @ font-family: sans-serif; |
| @@ -354,11 +357,11 @@ | |
| 357 | @ vertical-align: top; |
| 358 | @ text-align: right; |
| 359 | @ padding: 0.2ex 2ex; |
| 360 | @ } |
| 361 | @ '); |
| 362 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 363 | @ <head> |
| 364 | @ <title>$<project_name>: $<title></title> |
| 365 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 366 | @ href="$home/timeline.rss"> |
| 367 | @ <link rel="stylesheet" href="$home/style.css?tan" type="text/css" |
| @@ -405,11 +408,12 @@ | |
| 408 | @ } else { |
| 409 | @ html "<a href=''$home/login''>Login</a> " |
| 410 | @ } |
| 411 | @ </th1></div> |
| 412 | @ '); |
| 413 | @ REPLACE INTO config(name,mtime,value) |
| 414 | @ VALUES('footer',now(),'<div class="footer"> |
| 415 | @ Fossil version $manifest_version $manifest_date |
| 416 | @ </div> |
| 417 | @ </body></html> |
| 418 | @ '); |
| 419 | ; |
| @@ -417,11 +421,12 @@ | |
| 421 | /* |
| 422 | ** Black letters on a white or cream background with the main menu |
| 423 | ** stuck on the left-hand side. |
| 424 | */ |
| 425 | static const char zBuiltinSkin3[] = |
| 426 | @ REPLACE INTO config(name,mtime,value) |
| 427 | @ VALUES('css',now(),'/* General settings for the entire page */ |
| 428 | @ body { |
| 429 | @ margin:0px 0px 0px 0px; |
| 430 | @ padding:0px; |
| 431 | @ font-family:verdana, arial, helvetica, "sans serif"; |
| 432 | @ color:#333; |
| @@ -586,11 +591,11 @@ | |
| 591 | @ table.label-value th { |
| 592 | @ vertical-align: top; |
| 593 | @ text-align: right; |
| 594 | @ padding: 0.2ex 2ex; |
| 595 | @ }'); |
| 596 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 597 | @ <head> |
| 598 | @ <title>$<project_name>: $<title></title> |
| 599 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 600 | @ href="$home/timeline.rss"> |
| 601 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -640,11 +645,11 @@ | |
| 645 | @ html "<li><a href=''$home/login''>Login</a></li>" |
| 646 | @ } |
| 647 | @ </th1></ul></div> |
| 648 | @ <div id="container"> |
| 649 | @ '); |
| 650 | @ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div> |
| 651 | @ <div class="footer"> |
| 652 | @ Fossil version $manifest_version $manifest_date |
| 653 | @ </div> |
| 654 | @ </body></html> |
| 655 | @ '); |
| @@ -653,11 +658,12 @@ | |
| 658 | |
| 659 | /* |
| 660 | ** Gradients and rounded corners. |
| 661 | */ |
| 662 | static const char zBuiltinSkin4[] = |
| 663 | @ REPLACE INTO config(name,mtime,value) |
| 664 | @ VALUES('css',now(),'/* General settings for the entire page */ |
| 665 | @ html { |
| 666 | @ min-height: 100%; |
| 667 | @ } |
| 668 | @ body { |
| 669 | @ margin: 0ex 1ex; |
| @@ -880,11 +886,11 @@ | |
| 886 | @ } |
| 887 | @ |
| 888 | @ textarea { |
| 889 | @ font-size: 1em; |
| 890 | @ }'); |
| 891 | @ REPLACE INTO config(name,mtime,value) VALUES('header',now(),'<html> |
| 892 | @ <head> |
| 893 | @ <title>$<project_name>: $<title></title> |
| 894 | @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" |
| 895 | @ href="$home/timeline.rss"> |
| 896 | @ <link rel="stylesheet" href="$home/style.css?black2" type="text/css" |
| @@ -934,11 +940,11 @@ | |
| 940 | @ html "<a href=''$home/login''>Login</a>" |
| 941 | @ } |
| 942 | @ </th1></ul></div> |
| 943 | @ <div id="container"> |
| 944 | @ '); |
| 945 | @ REPLACE INTO config(name,mtime,value) VALUES('footer',now(),'</div> |
| 946 | @ <div class="footer"> |
| 947 | @ Fossil version $manifest_version $manifest_date |
| 948 | @ </div> |
| 949 | @ </body></html> |
| 950 | @ '); |
| @@ -984,17 +990,20 @@ | |
| 990 | ** Memory to hold the returned string is obtained from malloc. |
| 991 | */ |
| 992 | static char *getSkin(int useDefault){ |
| 993 | Blob val; |
| 994 | blob_zero(&val); |
| 995 | blob_appendf(&val, |
| 996 | "REPLACE INTO config(name,value,mtime) VALUES('css',%Q,now());\n", |
| 997 | useDefault ? zDefaultCSS : db_get("css", (char*)zDefaultCSS) |
| 998 | ); |
| 999 | blob_appendf(&val, |
| 1000 | "REPLACE INTO config(name,value,mtime) VALUES('header',%Q,now());\n", |
| 1001 | useDefault ? zDefaultHeader : db_get("header", (char*)zDefaultHeader) |
| 1002 | ); |
| 1003 | blob_appendf(&val, |
| 1004 | "REPLACE INTO config(name,value,mtime) VALUES('footer',%Q,now());\n", |
| 1005 | useDefault ? zDefaultFooter : db_get("footer", (char*)zDefaultFooter) |
| 1006 | ); |
| 1007 | return blob_str(&val); |
| 1008 | } |
| 1009 | |
| @@ -1048,11 +1057,11 @@ | |
| 1057 | if( db_exists("SELECT 1 FROM config WHERE name=%Q", zName) |
| 1058 | || strcmp(zName, "Default")==0 ){ |
| 1059 | zErr = mprintf("Skin name \"%h\" already exists. " |
| 1060 | "Choose a different name.", P("sn")); |
| 1061 | }else{ |
| 1062 | db_multi_exec("INSERT INTO config(name,value,mtime) VALUES(%Q,%Q,now())", |
| 1063 | zName, zCurrent |
| 1064 | ); |
| 1065 | } |
| 1066 | } |
| 1067 | |
| @@ -1069,13 +1078,13 @@ | |
| 1078 | seen = db_exists("SELECT 1 FROM config WHERE name GLOB 'skin:*'" |
| 1079 | " AND value=%Q", zCurrent); |
| 1080 | } |
| 1081 | if( !seen ){ |
| 1082 | db_multi_exec( |
| 1083 | "INSERT INTO config(name,value,mtime) VALUES(" |
| 1084 | " strftime('skin:Backup On %%Y-%%m-%%d %%H:%%M:%%S')," |
| 1085 | " %Q,now())", zCurrent |
| 1086 | ); |
| 1087 | } |
| 1088 | seen = 0; |
| 1089 | for(i=0; i<sizeof(aBuiltinSkin)/sizeof(aBuiltinSkin[0]); i++){ |
| 1090 | if( strcmp(aBuiltinSkin[i].zName, z)==0 ){ |
| 1091 |
+59
| --- src/sqlcmd.c | ||
| +++ src/sqlcmd.c | ||
| @@ -20,10 +20,11 @@ | ||
| 20 | 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | 21 | ** to initialize the code in shell.c. |
| 22 | 22 | */ |
| 23 | 23 | #include "config.h" |
| 24 | 24 | #include "sqlcmd.h" |
| 25 | +#include <zlib.h> | |
| 25 | 26 | |
| 26 | 27 | /* |
| 27 | 28 | ** Implementation of the "content(X)" SQL function. Return the complete |
| 28 | 29 | ** content of artifact identified by X as a blob. |
| 29 | 30 | */ |
| @@ -46,10 +47,64 @@ | ||
| 46 | 47 | sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx), |
| 47 | 48 | SQLITE_TRANSIENT); |
| 48 | 49 | blob_reset(&cx); |
| 49 | 50 | } |
| 50 | 51 | } |
| 52 | + | |
| 53 | +/* | |
| 54 | +** Implementation of the "compress(X)" SQL function. The input X is | |
| 55 | +** compressed using zLib and the output is returned. | |
| 56 | +*/ | |
| 57 | +static void sqlcmd_compress( | |
| 58 | + sqlite3_context *context, | |
| 59 | + int argc, | |
| 60 | + sqlite3_value **argv | |
| 61 | +){ | |
| 62 | + const unsigned char *pIn; | |
| 63 | + unsigned char *pOut; | |
| 64 | + unsigned int nIn; | |
| 65 | + unsigned long int nOut; | |
| 66 | + | |
| 67 | + pIn = sqlite3_value_blob(argv[0]); | |
| 68 | + nIn = sqlite3_value_bytes(argv[0]); | |
| 69 | + nOut = 13 + nIn + (nIn+999)/1000; | |
| 70 | + pOut = sqlite3_malloc( nOut+4 ); | |
| 71 | + pOut[0] = nIn>>24 & 0xff; | |
| 72 | + pOut[1] = nIn>>16 & 0xff; | |
| 73 | + pOut[2] = nIn>>8 & 0xff; | |
| 74 | + pOut[3] = nIn & 0xff; | |
| 75 | + compress(&pOut[4], &nOut, pIn, nIn); | |
| 76 | + sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); | |
| 77 | +} | |
| 78 | + | |
| 79 | +/* | |
| 80 | +** Implementation of the "uncontent(X)" SQL function. The argument X | |
| 81 | +** is a blob which was obtained from compress(Y). The output will be | |
| 82 | +** the value Y. | |
| 83 | +*/ | |
| 84 | +static void sqlcmd_decompress( | |
| 85 | + sqlite3_context *context, | |
| 86 | + int argc, | |
| 87 | + sqlite3_value **argv | |
| 88 | +){ | |
| 89 | + const unsigned char *pIn; | |
| 90 | + unsigned char *pOut; | |
| 91 | + unsigned int nIn; | |
| 92 | + unsigned long int nOut; | |
| 93 | + int rc; | |
| 94 | + | |
| 95 | + pIn = sqlite3_value_blob(argv[0]); | |
| 96 | + nIn = sqlite3_value_bytes(argv[0]); | |
| 97 | + nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3]; | |
| 98 | + pOut = sqlite3_malloc( nOut+1 ); | |
| 99 | + rc = uncompress(pOut, &nOut, &pIn[4], nIn-4); | |
| 100 | + if( rc==Z_OK ){ | |
| 101 | + sqlite3_result_blob(context, pOut, nOut, sqlite3_free); | |
| 102 | + }else{ | |
| 103 | + sqlite3_result_error(context, "input is not zlib compressed", -1); | |
| 104 | + } | |
| 105 | +} | |
| 51 | 106 | |
| 52 | 107 | /* |
| 53 | 108 | ** This is the "automatic extensionn" initializer that runs right after |
| 54 | 109 | ** the connection to the repository database is opened. Set up the |
| 55 | 110 | ** database connection to be more useful to the human operator. |
| @@ -59,10 +114,14 @@ | ||
| 59 | 114 | const char **pzErrMsg, |
| 60 | 115 | const void *notUsed |
| 61 | 116 | ){ |
| 62 | 117 | sqlite3_create_function(db, "content", 1, SQLITE_ANY, 0, |
| 63 | 118 | sqlcmd_content, 0, 0); |
| 119 | + sqlite3_create_function(db, "compress", 1, SQLITE_ANY, 0, | |
| 120 | + sqlcmd_compress, 0, 0); | |
| 121 | + sqlite3_create_function(db, "decompress", 1, SQLITE_ANY, 0, | |
| 122 | + sqlcmd_decompress, 0, 0); | |
| 64 | 123 | return SQLITE_OK; |
| 65 | 124 | } |
| 66 | 125 | |
| 67 | 126 | |
| 68 | 127 | /* |
| 69 | 128 |
| --- src/sqlcmd.c | |
| +++ src/sqlcmd.c | |
| @@ -20,10 +20,11 @@ | |
| 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | ** to initialize the code in shell.c. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #include "sqlcmd.h" |
| 25 | |
| 26 | /* |
| 27 | ** Implementation of the "content(X)" SQL function. Return the complete |
| 28 | ** content of artifact identified by X as a blob. |
| 29 | */ |
| @@ -46,10 +47,64 @@ | |
| 46 | sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx), |
| 47 | SQLITE_TRANSIENT); |
| 48 | blob_reset(&cx); |
| 49 | } |
| 50 | } |
| 51 | |
| 52 | /* |
| 53 | ** This is the "automatic extensionn" initializer that runs right after |
| 54 | ** the connection to the repository database is opened. Set up the |
| 55 | ** database connection to be more useful to the human operator. |
| @@ -59,10 +114,14 @@ | |
| 59 | const char **pzErrMsg, |
| 60 | const void *notUsed |
| 61 | ){ |
| 62 | sqlite3_create_function(db, "content", 1, SQLITE_ANY, 0, |
| 63 | sqlcmd_content, 0, 0); |
| 64 | return SQLITE_OK; |
| 65 | } |
| 66 | |
| 67 | |
| 68 | /* |
| 69 |
| --- src/sqlcmd.c | |
| +++ src/sqlcmd.c | |
| @@ -20,10 +20,11 @@ | |
| 20 | ** is a copy of the "shell.c" code from SQLite. This file contains logic |
| 21 | ** to initialize the code in shell.c. |
| 22 | */ |
| 23 | #include "config.h" |
| 24 | #include "sqlcmd.h" |
| 25 | #include <zlib.h> |
| 26 | |
| 27 | /* |
| 28 | ** Implementation of the "content(X)" SQL function. Return the complete |
| 29 | ** content of artifact identified by X as a blob. |
| 30 | */ |
| @@ -46,10 +47,64 @@ | |
| 47 | sqlite3_result_blob(context, blob_buffer(&cx), blob_size(&cx), |
| 48 | SQLITE_TRANSIENT); |
| 49 | blob_reset(&cx); |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | /* |
| 54 | ** Implementation of the "compress(X)" SQL function. The input X is |
| 55 | ** compressed using zLib and the output is returned. |
| 56 | */ |
| 57 | static void sqlcmd_compress( |
| 58 | sqlite3_context *context, |
| 59 | int argc, |
| 60 | sqlite3_value **argv |
| 61 | ){ |
| 62 | const unsigned char *pIn; |
| 63 | unsigned char *pOut; |
| 64 | unsigned int nIn; |
| 65 | unsigned long int nOut; |
| 66 | |
| 67 | pIn = sqlite3_value_blob(argv[0]); |
| 68 | nIn = sqlite3_value_bytes(argv[0]); |
| 69 | nOut = 13 + nIn + (nIn+999)/1000; |
| 70 | pOut = sqlite3_malloc( nOut+4 ); |
| 71 | pOut[0] = nIn>>24 & 0xff; |
| 72 | pOut[1] = nIn>>16 & 0xff; |
| 73 | pOut[2] = nIn>>8 & 0xff; |
| 74 | pOut[3] = nIn & 0xff; |
| 75 | compress(&pOut[4], &nOut, pIn, nIn); |
| 76 | sqlite3_result_blob(context, pOut, nOut+4, sqlite3_free); |
| 77 | } |
| 78 | |
| 79 | /* |
| 80 | ** Implementation of the "uncontent(X)" SQL function. The argument X |
| 81 | ** is a blob which was obtained from compress(Y). The output will be |
| 82 | ** the value Y. |
| 83 | */ |
| 84 | static void sqlcmd_decompress( |
| 85 | sqlite3_context *context, |
| 86 | int argc, |
| 87 | sqlite3_value **argv |
| 88 | ){ |
| 89 | const unsigned char *pIn; |
| 90 | unsigned char *pOut; |
| 91 | unsigned int nIn; |
| 92 | unsigned long int nOut; |
| 93 | int rc; |
| 94 | |
| 95 | pIn = sqlite3_value_blob(argv[0]); |
| 96 | nIn = sqlite3_value_bytes(argv[0]); |
| 97 | nOut = (pIn[0]<<24) + (pIn[1]<<16) + (pIn[2]<<8) + pIn[3]; |
| 98 | pOut = sqlite3_malloc( nOut+1 ); |
| 99 | rc = uncompress(pOut, &nOut, &pIn[4], nIn-4); |
| 100 | if( rc==Z_OK ){ |
| 101 | sqlite3_result_blob(context, pOut, nOut, sqlite3_free); |
| 102 | }else{ |
| 103 | sqlite3_result_error(context, "input is not zlib compressed", -1); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | /* |
| 108 | ** This is the "automatic extensionn" initializer that runs right after |
| 109 | ** the connection to the repository database is opened. Set up the |
| 110 | ** database connection to be more useful to the human operator. |
| @@ -59,10 +114,14 @@ | |
| 114 | const char **pzErrMsg, |
| 115 | const void *notUsed |
| 116 | ){ |
| 117 | sqlite3_create_function(db, "content", 1, SQLITE_ANY, 0, |
| 118 | sqlcmd_content, 0, 0); |
| 119 | sqlite3_create_function(db, "compress", 1, SQLITE_ANY, 0, |
| 120 | sqlcmd_compress, 0, 0); |
| 121 | sqlite3_create_function(db, "decompress", 1, SQLITE_ANY, 0, |
| 122 | sqlcmd_decompress, 0, 0); |
| 123 | return SQLITE_OK; |
| 124 | } |
| 125 | |
| 126 | |
| 127 | /* |
| 128 |
+1584
-416
| --- src/sqlite3.c | ||
| +++ src/sqlite3.c | ||
| @@ -1,8 +1,8 @@ | ||
| 1 | 1 | /****************************************************************************** |
| 2 | 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | -** version 3.7.6. By combining all the individual C code files into this | |
| 3 | +** version 3.7.7. By combining all the individual C code files into this | |
| 4 | 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | 8 | ** translation unit. |
| @@ -648,13 +648,13 @@ | ||
| 648 | 648 | ** |
| 649 | 649 | ** See also: [sqlite3_libversion()], |
| 650 | 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | 652 | */ |
| 653 | -#define SQLITE_VERSION "3.7.6" | |
| 654 | -#define SQLITE_VERSION_NUMBER 3007006 | |
| 655 | -#define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" | |
| 653 | +#define SQLITE_VERSION "3.7.7" | |
| 654 | +#define SQLITE_VERSION_NUMBER 3007007 | |
| 655 | +#define SQLITE_SOURCE_ID "2011-05-20 01:50:01 2018d4e108872f2436df046636401b89cfde589d" | |
| 656 | 656 | |
| 657 | 657 | /* |
| 658 | 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | 660 | ** |
| @@ -916,11 +916,12 @@ | ||
| 916 | 916 | ** Many SQLite functions return an integer result code from the set shown |
| 917 | 917 | ** here in order to indicates success or failure. |
| 918 | 918 | ** |
| 919 | 919 | ** New error codes may be added in future versions of SQLite. |
| 920 | 920 | ** |
| 921 | -** See also: [SQLITE_IOERR_READ | extended result codes] | |
| 921 | +** See also: [SQLITE_IOERR_READ | extended result codes], | |
| 922 | +** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. | |
| 922 | 923 | */ |
| 923 | 924 | #define SQLITE_OK 0 /* Successful result */ |
| 924 | 925 | /* beginning-of-error-codes */ |
| 925 | 926 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 926 | 927 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -993,28 +994,31 @@ | ||
| 993 | 994 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 994 | 995 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 995 | 996 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 996 | 997 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 997 | 998 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 999 | +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) | |
| 1000 | +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) | |
| 998 | 1001 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 999 | 1002 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 1000 | 1003 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 1004 | +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) | |
| 1001 | 1005 | |
| 1002 | 1006 | /* |
| 1003 | 1007 | ** CAPI3REF: Flags For File Open Operations |
| 1004 | 1008 | ** |
| 1005 | 1009 | ** These bit values are intended for use in the |
| 1006 | 1010 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 1007 | -** in the 4th parameter to the xOpen method of the | |
| 1008 | -** [sqlite3_vfs] object. | |
| 1011 | +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | |
| 1009 | 1012 | */ |
| 1010 | 1013 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 1011 | 1014 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 1012 | 1015 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 1013 | 1016 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 1014 | 1017 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 1015 | 1018 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 1019 | +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ | |
| 1016 | 1020 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 1017 | 1021 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 1018 | 1022 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 1019 | 1023 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 1020 | 1024 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -1121,21 +1125,22 @@ | ||
| 1121 | 1125 | }; |
| 1122 | 1126 | |
| 1123 | 1127 | /* |
| 1124 | 1128 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 1125 | 1129 | ** |
| 1126 | -** Every file opened by the [sqlite3_vfs] xOpen method populates an | |
| 1130 | +** Every file opened by the [sqlite3_vfs.xOpen] method populates an | |
| 1127 | 1131 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 1128 | 1132 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 1129 | 1133 | ** This object defines the methods used to perform various operations |
| 1130 | 1134 | ** against the open file represented by the [sqlite3_file] object. |
| 1131 | 1135 | ** |
| 1132 | -** If the xOpen method sets the sqlite3_file.pMethods element | |
| 1136 | +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element | |
| 1133 | 1137 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 1134 | -** may be invoked even if the xOpen reported that it failed. The | |
| 1135 | -** only way to prevent a call to xClose following a failed xOpen | |
| 1136 | -** is for the xOpen to set the sqlite3_file.pMethods element to NULL. | |
| 1138 | +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The | |
| 1139 | +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] | |
| 1140 | +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element | |
| 1141 | +** to NULL. | |
| 1137 | 1142 | ** |
| 1138 | 1143 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 1139 | 1144 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 1140 | 1145 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 1141 | 1146 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -1300,10 +1305,11 @@ | ||
| 1300 | 1305 | */ |
| 1301 | 1306 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 1302 | 1307 | |
| 1303 | 1308 | /* |
| 1304 | 1309 | ** CAPI3REF: OS Interface Object |
| 1310 | +** KEYWORDS: VFS VFSes | |
| 1305 | 1311 | ** |
| 1306 | 1312 | ** An instance of the sqlite3_vfs object defines the interface between |
| 1307 | 1313 | ** the SQLite core and the underlying operating system. The "vfs" |
| 1308 | 1314 | ** in the name of the object stands for "virtual file system". |
| 1309 | 1315 | ** |
| @@ -1332,10 +1338,11 @@ | ||
| 1332 | 1338 | ** object once the object has been registered. |
| 1333 | 1339 | ** |
| 1334 | 1340 | ** The zName field holds the name of the VFS module. The name must |
| 1335 | 1341 | ** be unique across all VFS modules. |
| 1336 | 1342 | ** |
| 1343 | +** [[sqlite3_vfs.xOpen]] | |
| 1337 | 1344 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 1338 | 1345 | ** is either a NULL pointer or string obtained |
| 1339 | 1346 | ** from xFullPathname() with an optional suffix added. |
| 1340 | 1347 | ** ^If a suffix is added to the zFilename parameter, it will |
| 1341 | 1348 | ** consist of a single "-" character followed by no more than |
| @@ -1409,10 +1416,11 @@ | ||
| 1409 | 1416 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 1410 | 1417 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 1411 | 1418 | ** element will be valid after xOpen returns regardless of the success |
| 1412 | 1419 | ** or failure of the xOpen call. |
| 1413 | 1420 | ** |
| 1421 | +** [[sqlite3_vfs.xAccess]] | |
| 1414 | 1422 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 1415 | 1423 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 1416 | 1424 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 1417 | 1425 | ** to test whether a file is at least readable. The file can be a |
| 1418 | 1426 | ** directory. |
| @@ -1655,13 +1663,13 @@ | ||
| 1655 | 1663 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1656 | 1664 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1657 | 1665 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1658 | 1666 | ** |
| 1659 | 1667 | ** The first argument to sqlite3_config() is an integer |
| 1660 | -** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines | |
| 1668 | +** [configuration option] that determines | |
| 1661 | 1669 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1662 | -** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] | |
| 1670 | +** vary depending on the [configuration option] | |
| 1663 | 1671 | ** in the first argument. |
| 1664 | 1672 | ** |
| 1665 | 1673 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1666 | 1674 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1667 | 1675 | ** then this routine returns a non-zero [error code]. |
| @@ -1767,10 +1775,11 @@ | ||
| 1767 | 1775 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1768 | 1776 | }; |
| 1769 | 1777 | |
| 1770 | 1778 | /* |
| 1771 | 1779 | ** CAPI3REF: Configuration Options |
| 1780 | +** KEYWORDS: {configuration option} | |
| 1772 | 1781 | ** |
| 1773 | 1782 | ** These constants are the available integer configuration options that |
| 1774 | 1783 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1775 | 1784 | ** |
| 1776 | 1785 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1779,11 +1788,11 @@ | ||
| 1779 | 1788 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1780 | 1789 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1781 | 1790 | ** is invoked. |
| 1782 | 1791 | ** |
| 1783 | 1792 | ** <dl> |
| 1784 | -** <dt>SQLITE_CONFIG_SINGLETHREAD</dt> | |
| 1793 | +** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt> | |
| 1785 | 1794 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1786 | 1795 | ** [threading mode] to Single-thread. In other words, it disables |
| 1787 | 1796 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1788 | 1797 | ** by a single thread. ^If SQLite is compiled with |
| 1789 | 1798 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1790,11 +1799,11 @@ | ||
| 1790 | 1799 | ** it is not possible to change the [threading mode] from its default |
| 1791 | 1800 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1792 | 1801 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1793 | 1802 | ** configuration option.</dd> |
| 1794 | 1803 | ** |
| 1795 | -** <dt>SQLITE_CONFIG_MULTITHREAD</dt> | |
| 1804 | +** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt> | |
| 1796 | 1805 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1797 | 1806 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1798 | 1807 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1799 | 1808 | ** The application is responsible for serializing access to |
| 1800 | 1809 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1804,11 +1813,11 @@ | ||
| 1804 | 1813 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1805 | 1814 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1806 | 1815 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1807 | 1816 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1808 | 1817 | ** |
| 1809 | -** <dt>SQLITE_CONFIG_SERIALIZED</dt> | |
| 1818 | +** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt> | |
| 1810 | 1819 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1811 | 1820 | ** [threading mode] to Serialized. In other words, this option enables |
| 1812 | 1821 | ** all mutexes including the recursive |
| 1813 | 1822 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1814 | 1823 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1820,27 +1829,27 @@ | ||
| 1820 | 1829 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1821 | 1830 | ** it is not possible to set the Serialized [threading mode] and |
| 1822 | 1831 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1823 | 1832 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1824 | 1833 | ** |
| 1825 | -** <dt>SQLITE_CONFIG_MALLOC</dt> | |
| 1834 | +** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> | |
| 1826 | 1835 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1827 | 1836 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1828 | 1837 | ** alternative low-level memory allocation routines to be used in place of |
| 1829 | 1838 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1830 | 1839 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1831 | 1840 | ** before the [sqlite3_config()] call returns.</dd> |
| 1832 | 1841 | ** |
| 1833 | -** <dt>SQLITE_CONFIG_GETMALLOC</dt> | |
| 1842 | +** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt> | |
| 1834 | 1843 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1835 | 1844 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1836 | 1845 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1837 | 1846 | ** This option can be used to overload the default memory allocation |
| 1838 | 1847 | ** routines with a wrapper that simulations memory allocation failure or |
| 1839 | 1848 | ** tracks memory usage, for example. </dd> |
| 1840 | 1849 | ** |
| 1841 | -** <dt>SQLITE_CONFIG_MEMSTATUS</dt> | |
| 1850 | +** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> | |
| 1842 | 1851 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1843 | 1852 | ** boolean, which enables or disables the collection of memory allocation |
| 1844 | 1853 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1845 | 1854 | ** following SQLite interfaces become non-operational: |
| 1846 | 1855 | ** <ul> |
| @@ -1852,11 +1861,11 @@ | ||
| 1852 | 1861 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1853 | 1862 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1854 | 1863 | ** allocation statistics are disabled by default. |
| 1855 | 1864 | ** </dd> |
| 1856 | 1865 | ** |
| 1857 | -** <dt>SQLITE_CONFIG_SCRATCH</dt> | |
| 1866 | +** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> | |
| 1858 | 1867 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1859 | 1868 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1860 | 1869 | ** aligned memory buffer from which the scratch allocations will be |
| 1861 | 1870 | ** drawn, the size of each scratch allocation (sz), |
| 1862 | 1871 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1868,11 +1877,11 @@ | ||
| 1868 | 1877 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1869 | 1878 | ** times the database page size. ^If SQLite needs needs additional |
| 1870 | 1879 | ** scratch memory beyond what is provided by this configuration option, then |
| 1871 | 1880 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1872 | 1881 | ** |
| 1873 | -** <dt>SQLITE_CONFIG_PAGECACHE</dt> | |
| 1882 | +** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> | |
| 1874 | 1883 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1875 | 1884 | ** the database page cache with the default page cache implemenation. |
| 1876 | 1885 | ** This configuration should not be used if an application-define page |
| 1877 | 1886 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1878 | 1887 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1889,11 +1898,11 @@ | ||
| 1889 | 1898 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1890 | 1899 | ** The pointer in the first argument must |
| 1891 | 1900 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1892 | 1901 | ** will be undefined.</dd> |
| 1893 | 1902 | ** |
| 1894 | -** <dt>SQLITE_CONFIG_HEAP</dt> | |
| 1903 | +** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> | |
| 1895 | 1904 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1896 | 1905 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1897 | 1906 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1898 | 1907 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1899 | 1908 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1906,11 +1915,11 @@ | ||
| 1906 | 1915 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1907 | 1916 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1908 | 1917 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1909 | 1918 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1910 | 1919 | ** |
| 1911 | -** <dt>SQLITE_CONFIG_MUTEX</dt> | |
| 1920 | +** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> | |
| 1912 | 1921 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1913 | 1922 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1914 | 1923 | ** alternative low-level mutex routines to be used in place |
| 1915 | 1924 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1916 | 1925 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1918,11 +1927,11 @@ | ||
| 1918 | 1927 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1919 | 1928 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1920 | 1929 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1921 | 1930 | ** return [SQLITE_ERROR].</dd> |
| 1922 | 1931 | ** |
| 1923 | -** <dt>SQLITE_CONFIG_GETMUTEX</dt> | |
| 1932 | +** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt> | |
| 1924 | 1933 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1925 | 1934 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1926 | 1935 | ** [sqlite3_mutex_methods] |
| 1927 | 1936 | ** structure is filled with the currently defined mutex routines.)^ |
| 1928 | 1937 | ** This option can be used to overload the default mutex allocation |
| @@ -1931,32 +1940,32 @@ | ||
| 1931 | 1940 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1932 | 1941 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1933 | 1942 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1934 | 1943 | ** return [SQLITE_ERROR].</dd> |
| 1935 | 1944 | ** |
| 1936 | -** <dt>SQLITE_CONFIG_LOOKASIDE</dt> | |
| 1945 | +** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt> | |
| 1937 | 1946 | ** <dd> ^(This option takes two arguments that determine the default |
| 1938 | 1947 | ** memory allocation for the lookaside memory allocator on each |
| 1939 | 1948 | ** [database connection]. The first argument is the |
| 1940 | 1949 | ** size of each lookaside buffer slot and the second is the number of |
| 1941 | 1950 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1942 | 1951 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1943 | 1952 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1944 | 1953 | ** configuration on individual connections.)^ </dd> |
| 1945 | 1954 | ** |
| 1946 | -** <dt>SQLITE_CONFIG_PCACHE</dt> | |
| 1955 | +** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt> | |
| 1947 | 1956 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1948 | 1957 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1949 | 1958 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1950 | 1959 | ** object and uses it for page cache memory allocations.</dd> |
| 1951 | 1960 | ** |
| 1952 | -** <dt>SQLITE_CONFIG_GETPCACHE</dt> | |
| 1961 | +** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt> | |
| 1953 | 1962 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1954 | 1963 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1955 | 1964 | ** page cache implementation into that object.)^ </dd> |
| 1956 | 1965 | ** |
| 1957 | -** <dt>SQLITE_CONFIG_LOG</dt> | |
| 1966 | +** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> | |
| 1958 | 1967 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1959 | 1968 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1960 | 1969 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1961 | 1970 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1962 | 1971 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1970,10 +1979,22 @@ | ||
| 1970 | 1979 | ** The SQLite logging interface is not reentrant; the logger function |
| 1971 | 1980 | ** supplied by the application must not invoke any SQLite interface. |
| 1972 | 1981 | ** In a multi-threaded application, the application-defined logger |
| 1973 | 1982 | ** function must be threadsafe. </dd> |
| 1974 | 1983 | ** |
| 1984 | +** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI | |
| 1985 | +** <dd> This option takes a single argument of type int. If non-zero, then | |
| 1986 | +** URI handling is globally enabled. If the parameter is zero, then URI handling | |
| 1987 | +** is globally disabled. If URI handling is globally enabled, all filenames | |
| 1988 | +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or | |
| 1989 | +** specified as part of [ATTACH] commands are interpreted as URIs, regardless | |
| 1990 | +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database | |
| 1991 | +** connection is opened. If it is globally disabled, filenames are | |
| 1992 | +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the | |
| 1993 | +** database connection is opened. By default, URI handling is globally | |
| 1994 | +** disabled. The default value may be changed by compiling with the | |
| 1995 | +** [SQLITE_USE_URI] symbol defined. | |
| 1975 | 1996 | ** </dl> |
| 1976 | 1997 | */ |
| 1977 | 1998 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1978 | 1999 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 1979 | 2000 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1988,10 +2009,11 @@ | ||
| 1988 | 2009 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 1989 | 2010 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 1990 | 2011 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 1991 | 2012 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 1992 | 2013 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 2014 | +#define SQLITE_CONFIG_URI 17 /* int */ | |
| 1993 | 2015 | |
| 1994 | 2016 | /* |
| 1995 | 2017 | ** CAPI3REF: Database Connection Configuration Options |
| 1996 | 2018 | ** |
| 1997 | 2019 | ** These constants are the available integer configuration options that |
| @@ -2073,17 +2095,21 @@ | ||
| 2073 | 2095 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 2074 | 2096 | ** is another alias for the rowid. |
| 2075 | 2097 | ** |
| 2076 | 2098 | ** ^This routine returns the [rowid] of the most recent |
| 2077 | 2099 | ** successful [INSERT] into the database from the [database connection] |
| 2078 | -** in the first argument. ^If no successful [INSERT]s | |
| 2100 | +** in the first argument. ^As of SQLite version 3.7.7, this routines | |
| 2101 | +** records the last insert rowid of both ordinary tables and [virtual tables]. | |
| 2102 | +** ^If no successful [INSERT]s | |
| 2079 | 2103 | ** have ever occurred on that database connection, zero is returned. |
| 2080 | 2104 | ** |
| 2081 | -** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted | |
| 2082 | -** row is returned by this routine as long as the trigger is running. | |
| 2083 | -** But once the trigger terminates, the value returned by this routine | |
| 2084 | -** reverts to the last value inserted before the trigger fired.)^ | |
| 2105 | +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] | |
| 2106 | +** method, then this routine will return the [rowid] of the inserted | |
| 2107 | +** row as long as the trigger or virtual table method is running. | |
| 2108 | +** But once the trigger or virtual table method ends, the value returned | |
| 2109 | +** by this routine reverts to what it was before the trigger or virtual | |
| 2110 | +** table method began.)^ | |
| 2085 | 2111 | ** |
| 2086 | 2112 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 2087 | 2113 | ** successful [INSERT] and does not change the value returned by this |
| 2088 | 2114 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 2089 | 2115 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2742,10 +2768,13 @@ | ||
| 2742 | 2768 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2743 | 2769 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2744 | 2770 | ** to signal SQLite whether or not the action is permitted. See the |
| 2745 | 2771 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2746 | 2772 | ** information. |
| 2773 | +** | |
| 2774 | +** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] | |
| 2775 | +** from the [sqlite3_vtab_on_conflict()] interface. | |
| 2747 | 2776 | */ |
| 2748 | 2777 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2749 | 2778 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2750 | 2779 | |
| 2751 | 2780 | /* |
| @@ -2864,11 +2893,11 @@ | ||
| 2864 | 2893 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2865 | 2894 | |
| 2866 | 2895 | /* |
| 2867 | 2896 | ** CAPI3REF: Opening A New Database Connection |
| 2868 | 2897 | ** |
| 2869 | -** ^These routines open an SQLite database file whose name is given by the | |
| 2898 | +** ^These routines open an SQLite database file as specified by the | |
| 2870 | 2899 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2871 | 2900 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2872 | 2901 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2873 | 2902 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2874 | 2903 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2891,11 +2920,11 @@ | ||
| 2891 | 2920 | ** except that it accepts two additional parameters for additional control |
| 2892 | 2921 | ** over the new database connection. ^(The flags parameter to |
| 2893 | 2922 | ** sqlite3_open_v2() can take one of |
| 2894 | 2923 | ** the following three values, optionally combined with the |
| 2895 | 2924 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2896 | -** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ | |
| 2925 | +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ | |
| 2897 | 2926 | ** |
| 2898 | 2927 | ** <dl> |
| 2899 | 2928 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2900 | 2929 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2901 | 2930 | ** already exist, an error is returned.</dd>)^ |
| @@ -2910,13 +2939,12 @@ | ||
| 2910 | 2939 | ** it does not already exist. This is the behavior that is always used for |
| 2911 | 2940 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2912 | 2941 | ** </dl> |
| 2913 | 2942 | ** |
| 2914 | 2943 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2915 | -** combinations shown above or one of the combinations shown above combined | |
| 2916 | -** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], | |
| 2917 | -** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, | |
| 2944 | +** combinations shown above optionally combined with other | |
| 2945 | +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] | |
| 2918 | 2946 | ** then the behavior is undefined. |
| 2919 | 2947 | ** |
| 2920 | 2948 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2921 | 2949 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2922 | 2950 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2926,10 +2954,15 @@ | ||
| 2926 | 2954 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2927 | 2955 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2928 | 2956 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2929 | 2957 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2930 | 2958 | ** participate in [shared cache mode] even if it is enabled. |
| 2959 | +** | |
| 2960 | +** ^The fourth parameter to sqlite3_open_v2() is the name of the | |
| 2961 | +** [sqlite3_vfs] object that defines the operating system interface that | |
| 2962 | +** the new database connection should use. ^If the fourth parameter is | |
| 2963 | +** a NULL pointer then the default [sqlite3_vfs] object is used. | |
| 2931 | 2964 | ** |
| 2932 | 2965 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2933 | 2966 | ** is created for the connection. ^This in-memory database will vanish when |
| 2934 | 2967 | ** the database connection is closed. Future versions of SQLite might |
| 2935 | 2968 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2939,14 +2972,115 @@ | ||
| 2939 | 2972 | ** |
| 2940 | 2973 | ** ^If the filename is an empty string, then a private, temporary |
| 2941 | 2974 | ** on-disk database will be created. ^This private database will be |
| 2942 | 2975 | ** automatically deleted as soon as the database connection is closed. |
| 2943 | 2976 | ** |
| 2944 | -** ^The fourth parameter to sqlite3_open_v2() is the name of the | |
| 2945 | -** [sqlite3_vfs] object that defines the operating system interface that | |
| 2946 | -** the new database connection should use. ^If the fourth parameter is | |
| 2947 | -** a NULL pointer then the default [sqlite3_vfs] object is used. | |
| 2977 | +** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3> | |
| 2978 | +** | |
| 2979 | +** ^If [URI filename] interpretation is enabled, and the filename argument | |
| 2980 | +** begins with "file:", then the filename is interpreted as a URI. ^URI | |
| 2981 | +** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is | |
| 2982 | +** is set in the fourth argument to sqlite3_open_v2(), or if it has | |
| 2983 | +** been enabled globally using the [SQLITE_CONFIG_URI] option with the | |
| 2984 | +** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. | |
| 2985 | +** As of SQLite version 3.7.7, URI filename interpretation is turned off | |
| 2986 | +** by default, but future releases of SQLite might enable URI filename | |
| 2987 | +** intepretation by default. See "[URI filenames]" for additional | |
| 2988 | +** information. | |
| 2989 | +** | |
| 2990 | +** URI filenames are parsed according to RFC 3986. ^If the URI contains an | |
| 2991 | +** authority, then it must be either an empty string or the string | |
| 2992 | +** "localhost". ^If the authority is not an empty string or "localhost", an | |
| 2993 | +** error is returned to the caller. ^The fragment component of a URI, if | |
| 2994 | +** present, is ignored. | |
| 2995 | +** | |
| 2996 | +** ^SQLite uses the path component of the URI as the name of the disk file | |
| 2997 | +** which contains the database. ^If the path begins with a '/' character, | |
| 2998 | +** then it is interpreted as an absolute path. ^If the path does not begin | |
| 2999 | +** with a '/' (meaning that the authority section is omitted from the URI) | |
| 3000 | +** then the path is interpreted as a relative path. | |
| 3001 | +** ^On windows, the first component of an absolute path | |
| 3002 | +** is a drive specification (e.g. "C:"). | |
| 3003 | +** | |
| 3004 | +** [[core URI query parameters]] | |
| 3005 | +** The query component of a URI may contain parameters that are interpreted | |
| 3006 | +** either by SQLite itself, or by a [VFS | custom VFS implementation]. | |
| 3007 | +** SQLite interprets the following three query parameters: | |
| 3008 | +** | |
| 3009 | +** <ul> | |
| 3010 | +** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of | |
| 3011 | +** a VFS object that provides the operating system interface that should | |
| 3012 | +** be used to access the database file on disk. ^If this option is set to | |
| 3013 | +** an empty string the default VFS object is used. ^Specifying an unknown | |
| 3014 | +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is | |
| 3015 | +** present, then the VFS specified by the option takes precedence over | |
| 3016 | +** the value passed as the fourth parameter to sqlite3_open_v2(). | |
| 3017 | +** | |
| 3018 | +** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or | |
| 3019 | +** "rwc". Attempting to set it to any other value is an error)^. | |
| 3020 | +** ^If "ro" is specified, then the database is opened for read-only | |
| 3021 | +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the | |
| 3022 | +** third argument to sqlite3_prepare_v2(). ^If the mode option is set to | |
| 3023 | +** "rw", then the database is opened for read-write (but not create) | |
| 3024 | +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had | |
| 3025 | +** been set. ^Value "rwc" is equivalent to setting both | |
| 3026 | +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is | |
| 3027 | +** used, it is an error to specify a value for the mode parameter that is | |
| 3028 | +** less restrictive than that specified by the flags passed as the third | |
| 3029 | +** parameter. | |
| 3030 | +** | |
| 3031 | +** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or | |
| 3032 | +** "private". ^Setting it to "shared" is equivalent to setting the | |
| 3033 | +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to | |
| 3034 | +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is | |
| 3035 | +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. | |
| 3036 | +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in | |
| 3037 | +** a URI filename, its value overrides any behaviour requested by setting | |
| 3038 | +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. | |
| 3039 | +** </ul> | |
| 3040 | +** | |
| 3041 | +** ^Specifying an unknown parameter in the query component of a URI is not an | |
| 3042 | +** error. Future versions of SQLite might understand additional query | |
| 3043 | +** parameters. See "[query parameters with special meaning to SQLite]" for | |
| 3044 | +** additional information. | |
| 3045 | +** | |
| 3046 | +** [[URI filename examples]] <h3>URI filename examples</h3> | |
| 3047 | +** | |
| 3048 | +** <table border="1" align=center cellpadding=5> | |
| 3049 | +** <tr><th> URI filenames <th> Results | |
| 3050 | +** <tr><td> file:data.db <td> | |
| 3051 | +** Open the file "data.db" in the current directory. | |
| 3052 | +** <tr><td> file:/home/fred/data.db<br> | |
| 3053 | +** file:///home/fred/data.db <br> | |
| 3054 | +** file://localhost/home/fred/data.db <br> <td> | |
| 3055 | +** Open the database file "/home/fred/data.db". | |
| 3056 | +** <tr><td> file://darkstar/home/fred/data.db <td> | |
| 3057 | +** An error. "darkstar" is not a recognized authority. | |
| 3058 | +** <tr><td style="white-space:nowrap"> | |
| 3059 | +** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db | |
| 3060 | +** <td> Windows only: Open the file "data.db" on fred's desktop on drive | |
| 3061 | +** C:. Note that the %20 escaping in this example is not strictly | |
| 3062 | +** necessary - space characters can be used literally | |
| 3063 | +** in URI filenames. | |
| 3064 | +** <tr><td> file:data.db?mode=ro&cache=private <td> | |
| 3065 | +** Open file "data.db" in the current directory for read-only access. | |
| 3066 | +** Regardless of whether or not shared-cache mode is enabled by | |
| 3067 | +** default, use a private cache. | |
| 3068 | +** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td> | |
| 3069 | +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". | |
| 3070 | +** <tr><td> file:data.db?mode=readonly <td> | |
| 3071 | +** An error. "readonly" is not a valid option for the "mode" parameter. | |
| 3072 | +** </table> | |
| 3073 | +** | |
| 3074 | +** ^URI hexadecimal escape sequences (%HH) are supported within the path and | |
| 3075 | +** query components of a URI. A hexadecimal escape sequence consists of a | |
| 3076 | +** percent sign - "%" - followed by exactly two hexadecimal digits | |
| 3077 | +** specifying an octet value. ^Before the path or query components of a | |
| 3078 | +** URI filename are interpreted, they are encoded using UTF-8 and all | |
| 3079 | +** hexadecimal escape sequences replaced by a single byte containing the | |
| 3080 | +** corresponding octet. If this process generates an invalid UTF-8 encoding, | |
| 3081 | +** the results are undefined. | |
| 2948 | 3082 | ** |
| 2949 | 3083 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 2950 | 3084 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 2951 | 3085 | ** codepage is currently defined. Filenames containing international |
| 2952 | 3086 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2964,10 +3098,30 @@ | ||
| 2964 | 3098 | const char *filename, /* Database filename (UTF-8) */ |
| 2965 | 3099 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 2966 | 3100 | int flags, /* Flags */ |
| 2967 | 3101 | const char *zVfs /* Name of VFS module to use */ |
| 2968 | 3102 | ); |
| 3103 | + | |
| 3104 | +/* | |
| 3105 | +** CAPI3REF: Obtain Values For URI Parameters | |
| 3106 | +** | |
| 3107 | +** This is a utility routine, useful to VFS implementations, that checks | |
| 3108 | +** to see if a database file was a URI that contained a specific query | |
| 3109 | +** parameter, and if so obtains the value of the query parameter. | |
| 3110 | +** | |
| 3111 | +** The zFilename argument is the filename pointer passed into the xOpen() | |
| 3112 | +** method of a VFS implementation. The zParam argument is the name of the | |
| 3113 | +** query parameter we seek. This routine returns the value of the zParam | |
| 3114 | +** parameter if it exists. If the parameter does not exist, this routine | |
| 3115 | +** returns a NULL pointer. | |
| 3116 | +** | |
| 3117 | +** If the zFilename argument to this function is not a pointer that SQLite | |
| 3118 | +** passed into the xOpen VFS method, then the behavior of this routine | |
| 3119 | +** is undefined and probably undesirable. | |
| 3120 | +*/ | |
| 3121 | +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); | |
| 3122 | + | |
| 2969 | 3123 | |
| 2970 | 3124 | /* |
| 2971 | 3125 | ** CAPI3REF: Error Codes And Messages |
| 2972 | 3126 | ** |
| 2973 | 3127 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -3080,47 +3234,49 @@ | ||
| 3080 | 3234 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 3081 | 3235 | ** The synopsis of the meanings of the various limits is shown below. |
| 3082 | 3236 | ** Additional information is available at [limits | Limits in SQLite]. |
| 3083 | 3237 | ** |
| 3084 | 3238 | ** <dl> |
| 3085 | -** ^(<dt>SQLITE_LIMIT_LENGTH</dt> | |
| 3239 | +** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> | |
| 3086 | 3240 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 3087 | 3241 | ** |
| 3088 | -** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> | |
| 3242 | +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> | |
| 3089 | 3243 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 3090 | 3244 | ** |
| 3091 | -** ^(<dt>SQLITE_LIMIT_COLUMN</dt> | |
| 3245 | +** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt> | |
| 3092 | 3246 | ** <dd>The maximum number of columns in a table definition or in the |
| 3093 | 3247 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 3094 | 3248 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 3095 | 3249 | ** |
| 3096 | -** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> | |
| 3250 | +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> | |
| 3097 | 3251 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 3098 | 3252 | ** |
| 3099 | -** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> | |
| 3253 | +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> | |
| 3100 | 3254 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 3101 | 3255 | ** |
| 3102 | -** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> | |
| 3256 | +** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> | |
| 3103 | 3257 | ** <dd>The maximum number of instructions in a virtual machine program |
| 3104 | 3258 | ** used to implement an SQL statement. This limit is not currently |
| 3105 | 3259 | ** enforced, though that might be added in some future release of |
| 3106 | 3260 | ** SQLite.</dd>)^ |
| 3107 | 3261 | ** |
| 3108 | -** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> | |
| 3262 | +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> | |
| 3109 | 3263 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 3110 | 3264 | ** |
| 3111 | -** ^(<dt>SQLITE_LIMIT_ATTACHED</dt> | |
| 3265 | +** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt> | |
| 3112 | 3266 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 3113 | 3267 | ** |
| 3268 | +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] | |
| 3114 | 3269 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 3115 | 3270 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 3116 | 3271 | ** [GLOB] operators.</dd>)^ |
| 3117 | 3272 | ** |
| 3273 | +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] | |
| 3118 | 3274 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 3119 | 3275 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 3120 | 3276 | ** |
| 3121 | -** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> | |
| 3277 | +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> | |
| 3122 | 3278 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 3123 | 3279 | ** </dl> |
| 3124 | 3280 | */ |
| 3125 | 3281 | #define SQLITE_LIMIT_LENGTH 0 |
| 3126 | 3282 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -5151,10 +5307,15 @@ | ||
| 5151 | 5307 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 5152 | 5308 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 5153 | 5309 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 5154 | 5310 | void **ppArg); |
| 5155 | 5311 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 5312 | + /* The methods above are in version 1 of the sqlite_module object. Those | |
| 5313 | + ** below are for version 2 and greater. */ | |
| 5314 | + int (*xSavepoint)(sqlite3_vtab *pVTab, int); | |
| 5315 | + int (*xRelease)(sqlite3_vtab *pVTab, int); | |
| 5316 | + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); | |
| 5156 | 5317 | }; |
| 5157 | 5318 | |
| 5158 | 5319 | /* |
| 5159 | 5320 | ** CAPI3REF: Virtual Table Indexing Information |
| 5160 | 5321 | ** KEYWORDS: sqlite3_index_info |
| @@ -5965,11 +6126,11 @@ | ||
| 5965 | 6126 | ** |
| 5966 | 6127 | ** ^This interface is used to retrieve runtime status information |
| 5967 | 6128 | ** about the performance of SQLite, and optionally to reset various |
| 5968 | 6129 | ** highwater marks. ^The first argument is an integer code for |
| 5969 | 6130 | ** the specific parameter to measure. ^(Recognized integer codes |
| 5970 | -** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ | |
| 6131 | +** are of the form [status parameters | SQLITE_STATUS_...].)^ | |
| 5971 | 6132 | ** ^The current value of the parameter is returned into *pCurrent. |
| 5972 | 6133 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 5973 | 6134 | ** resetFlag is true, then the highest record value is reset after |
| 5974 | 6135 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 5975 | 6136 | ** value. For those parameters |
| @@ -5992,82 +6153,84 @@ | ||
| 5992 | 6153 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 5993 | 6154 | |
| 5994 | 6155 | |
| 5995 | 6156 | /* |
| 5996 | 6157 | ** CAPI3REF: Status Parameters |
| 6158 | +** KEYWORDS: {status parameters} | |
| 5997 | 6159 | ** |
| 5998 | 6160 | ** These integer constants designate various run-time status parameters |
| 5999 | 6161 | ** that can be returned by [sqlite3_status()]. |
| 6000 | 6162 | ** |
| 6001 | 6163 | ** <dl> |
| 6002 | -** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> | |
| 6164 | +** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> | |
| 6003 | 6165 | ** <dd>This parameter is the current amount of memory checked out |
| 6004 | 6166 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 6005 | 6167 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 6006 | 6168 | ** and internal memory usage by the SQLite library. Scratch memory |
| 6007 | 6169 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 6008 | 6170 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 6009 | 6171 | ** this parameter. The amount returned is the sum of the allocation |
| 6010 | 6172 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 6011 | 6173 | ** |
| 6012 | -** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> | |
| 6174 | +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> | |
| 6013 | 6175 | ** <dd>This parameter records the largest memory allocation request |
| 6014 | 6176 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 6015 | 6177 | ** internal equivalents). Only the value returned in the |
| 6016 | 6178 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6017 | 6179 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6018 | 6180 | ** |
| 6019 | -** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> | |
| 6181 | +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> | |
| 6020 | 6182 | ** <dd>This parameter records the number of separate memory allocations |
| 6021 | 6183 | ** currently checked out.</dd>)^ |
| 6022 | 6184 | ** |
| 6023 | -** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> | |
| 6185 | +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> | |
| 6024 | 6186 | ** <dd>This parameter returns the number of pages used out of the |
| 6025 | 6187 | ** [pagecache memory allocator] that was configured using |
| 6026 | 6188 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 6027 | 6189 | ** value returned is in pages, not in bytes.</dd>)^ |
| 6028 | 6190 | ** |
| 6191 | +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] | |
| 6029 | 6192 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 6030 | 6193 | ** <dd>This parameter returns the number of bytes of page cache |
| 6031 | 6194 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 6032 | 6195 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 6033 | 6196 | ** returned value includes allocations that overflowed because they |
| 6034 | 6197 | ** where too large (they were larger than the "sz" parameter to |
| 6035 | 6198 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 6036 | 6199 | ** no space was left in the page cache.</dd>)^ |
| 6037 | 6200 | ** |
| 6038 | -** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> | |
| 6201 | +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> | |
| 6039 | 6202 | ** <dd>This parameter records the largest memory allocation request |
| 6040 | 6203 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 6041 | 6204 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6042 | 6205 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6043 | 6206 | ** |
| 6044 | -** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> | |
| 6207 | +** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> | |
| 6045 | 6208 | ** <dd>This parameter returns the number of allocations used out of the |
| 6046 | 6209 | ** [scratch memory allocator] configured using |
| 6047 | 6210 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 6048 | 6211 | ** in bytes. Since a single thread may only have one scratch allocation |
| 6049 | 6212 | ** outstanding at time, this parameter also reports the number of threads |
| 6050 | 6213 | ** using scratch memory at the same time.</dd>)^ |
| 6051 | 6214 | ** |
| 6052 | -** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> | |
| 6215 | +** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> | |
| 6053 | 6216 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 6054 | 6217 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 6055 | 6218 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 6056 | 6219 | ** returned include overflows because the requested allocation was too |
| 6057 | 6220 | ** larger (that is, because the requested allocation was larger than the |
| 6058 | 6221 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 6059 | 6222 | ** slots were available. |
| 6060 | 6223 | ** </dd>)^ |
| 6061 | 6224 | ** |
| 6062 | -** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> | |
| 6225 | +** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> | |
| 6063 | 6226 | ** <dd>This parameter records the largest memory allocation request |
| 6064 | 6227 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 6065 | 6228 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6066 | 6229 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6067 | 6230 | ** |
| 6068 | -** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> | |
| 6231 | +** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> | |
| 6069 | 6232 | ** <dd>This parameter records the deepest parser stack. It is only |
| 6070 | 6233 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 6071 | 6234 | ** </dl> |
| 6072 | 6235 | ** |
| 6073 | 6236 | ** New status parameters may be added from time to time. |
| @@ -6088,13 +6251,13 @@ | ||
| 6088 | 6251 | ** |
| 6089 | 6252 | ** ^This interface is used to retrieve runtime status information |
| 6090 | 6253 | ** about a single [database connection]. ^The first argument is the |
| 6091 | 6254 | ** database connection object to be interrogated. ^The second argument |
| 6092 | 6255 | ** is an integer constant, taken from the set of |
| 6093 | -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that | |
| 6256 | +** [SQLITE_DBSTATUS options], that | |
| 6094 | 6257 | ** determines the parameter to interrogate. The set of |
| 6095 | -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely | |
| 6258 | +** [SQLITE_DBSTATUS options] is likely | |
| 6096 | 6259 | ** to grow in future releases of SQLite. |
| 6097 | 6260 | ** |
| 6098 | 6261 | ** ^The current value of the requested parameter is written into *pCur |
| 6099 | 6262 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 6100 | 6263 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -6107,10 +6270,11 @@ | ||
| 6107 | 6270 | */ |
| 6108 | 6271 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 6109 | 6272 | |
| 6110 | 6273 | /* |
| 6111 | 6274 | ** CAPI3REF: Status Parameters for database connections |
| 6275 | +** KEYWORDS: {SQLITE_DBSTATUS options} | |
| 6112 | 6276 | ** |
| 6113 | 6277 | ** These constants are the available integer "verbs" that can be passed as |
| 6114 | 6278 | ** the second argument to the [sqlite3_db_status()] interface. |
| 6115 | 6279 | ** |
| 6116 | 6280 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -6118,48 +6282,50 @@ | ||
| 6118 | 6282 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 6119 | 6283 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 6120 | 6284 | ** if a discontinued or unsupported verb is invoked. |
| 6121 | 6285 | ** |
| 6122 | 6286 | ** <dl> |
| 6123 | -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> | |
| 6287 | +** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> | |
| 6124 | 6288 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 6125 | 6289 | ** checked out.</dd>)^ |
| 6126 | 6290 | ** |
| 6127 | -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> | |
| 6291 | +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> | |
| 6128 | 6292 | ** <dd>This parameter returns the number malloc attempts that were |
| 6129 | 6293 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 6130 | 6294 | ** the current value is always zero.)^ |
| 6131 | 6295 | ** |
| 6296 | +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] | |
| 6132 | 6297 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 6133 | 6298 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6134 | 6299 | ** been satisfied using lookaside memory but failed due to the amount of |
| 6135 | 6300 | ** memory requested being larger than the lookaside slot size. |
| 6136 | 6301 | ** Only the high-water value is meaningful; |
| 6137 | 6302 | ** the current value is always zero.)^ |
| 6138 | 6303 | ** |
| 6304 | +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] | |
| 6139 | 6305 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 6140 | 6306 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6141 | 6307 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 6142 | 6308 | ** memory already being in use. |
| 6143 | 6309 | ** Only the high-water value is meaningful; |
| 6144 | 6310 | ** the current value is always zero.)^ |
| 6145 | 6311 | ** |
| 6146 | -** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> | |
| 6312 | +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> | |
| 6147 | 6313 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6148 | 6314 | ** memory used by all pager caches associated with the database connection.)^ |
| 6149 | 6315 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 6150 | 6316 | ** |
| 6151 | -** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> | |
| 6317 | +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> | |
| 6152 | 6318 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6153 | 6319 | ** memory used to store the schema for all databases associated |
| 6154 | 6320 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 6155 | 6321 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 6156 | 6322 | ** schema memory is shared with other database connections due to |
| 6157 | 6323 | ** [shared cache mode] being enabled. |
| 6158 | 6324 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 6159 | 6325 | ** |
| 6160 | -** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> | |
| 6326 | +** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> | |
| 6161 | 6327 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6162 | 6328 | ** and lookaside memory used by all prepared statements associated with |
| 6163 | 6329 | ** the database connection.)^ |
| 6164 | 6330 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 6165 | 6331 | ** </dd> |
| @@ -6177,11 +6343,11 @@ | ||
| 6177 | 6343 | |
| 6178 | 6344 | /* |
| 6179 | 6345 | ** CAPI3REF: Prepared Statement Status |
| 6180 | 6346 | ** |
| 6181 | 6347 | ** ^(Each prepared statement maintains various |
| 6182 | -** [SQLITE_STMTSTATUS_SORT | counters] that measure the number | |
| 6348 | +** [SQLITE_STMTSTATUS counters] that measure the number | |
| 6183 | 6349 | ** of times it has performed specific operations.)^ These counters can |
| 6184 | 6350 | ** be used to monitor the performance characteristics of the prepared |
| 6185 | 6351 | ** statements. For example, if the number of table steps greatly exceeds |
| 6186 | 6352 | ** the number of table searches or result rows, that would tend to indicate |
| 6187 | 6353 | ** that the prepared statement is using a full table scan rather than |
| @@ -6188,11 +6354,11 @@ | ||
| 6188 | 6354 | ** an index. |
| 6189 | 6355 | ** |
| 6190 | 6356 | ** ^(This interface is used to retrieve and reset counter values from |
| 6191 | 6357 | ** a [prepared statement]. The first argument is the prepared statement |
| 6192 | 6358 | ** object to be interrogated. The second argument |
| 6193 | -** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] | |
| 6359 | +** is an integer code for a specific [SQLITE_STMTSTATUS counter] | |
| 6194 | 6360 | ** to be interrogated.)^ |
| 6195 | 6361 | ** ^The current value of the requested counter is returned. |
| 6196 | 6362 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 6197 | 6363 | ** interface call returns. |
| 6198 | 6364 | ** |
| @@ -6200,28 +6366,29 @@ | ||
| 6200 | 6366 | */ |
| 6201 | 6367 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 6202 | 6368 | |
| 6203 | 6369 | /* |
| 6204 | 6370 | ** CAPI3REF: Status Parameters for prepared statements |
| 6371 | +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} | |
| 6205 | 6372 | ** |
| 6206 | 6373 | ** These preprocessor macros define integer codes that name counter |
| 6207 | 6374 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 6208 | 6375 | ** The meanings of the various counters are as follows: |
| 6209 | 6376 | ** |
| 6210 | 6377 | ** <dl> |
| 6211 | -** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> | |
| 6378 | +** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> | |
| 6212 | 6379 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 6213 | 6380 | ** a table as part of a full table scan. Large numbers for this counter |
| 6214 | 6381 | ** may indicate opportunities for performance improvement through |
| 6215 | 6382 | ** careful use of indices.</dd> |
| 6216 | 6383 | ** |
| 6217 | -** <dt>SQLITE_STMTSTATUS_SORT</dt> | |
| 6384 | +** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt> | |
| 6218 | 6385 | ** <dd>^This is the number of sort operations that have occurred. |
| 6219 | 6386 | ** A non-zero value in this counter may indicate an opportunity to |
| 6220 | 6387 | ** improvement performance through careful use of indices.</dd> |
| 6221 | 6388 | ** |
| 6222 | -** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> | |
| 6389 | +** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> | |
| 6223 | 6390 | ** <dd>^This is the number of rows inserted into transient indices that |
| 6224 | 6391 | ** were created automatically in order to help joins run faster. |
| 6225 | 6392 | ** A non-zero value in this counter may indicate an opportunity to |
| 6226 | 6393 | ** improvement performance by adding permanent indices that do not |
| 6227 | 6394 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -6268,10 +6435,11 @@ | ||
| 6268 | 6435 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 6269 | 6436 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 6270 | 6437 | ** the application may discard the parameter after the call to |
| 6271 | 6438 | ** [sqlite3_config()] returns.)^ |
| 6272 | 6439 | ** |
| 6440 | +** [[the xInit() page cache method]] | |
| 6273 | 6441 | ** ^(The xInit() method is called once for each effective |
| 6274 | 6442 | ** call to [sqlite3_initialize()])^ |
| 6275 | 6443 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 6276 | 6444 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 6277 | 6445 | ** The intent of the xInit() method is to set up global data structures |
| @@ -6278,10 +6446,11 @@ | ||
| 6278 | 6446 | ** required by the custom page cache implementation. |
| 6279 | 6447 | ** ^(If the xInit() method is NULL, then the |
| 6280 | 6448 | ** built-in default page cache is used instead of the application defined |
| 6281 | 6449 | ** page cache.)^ |
| 6282 | 6450 | ** |
| 6451 | +** [[the xShutdown() page cache method]] | |
| 6283 | 6452 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 6284 | 6453 | ** It can be used to clean up |
| 6285 | 6454 | ** any outstanding resources before process shutdown, if required. |
| 6286 | 6455 | ** ^The xShutdown() method may be NULL. |
| 6287 | 6456 | ** |
| @@ -6292,10 +6461,11 @@ | ||
| 6292 | 6461 | ** in multithreaded applications. |
| 6293 | 6462 | ** |
| 6294 | 6463 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 6295 | 6464 | ** call to xShutdown(). |
| 6296 | 6465 | ** |
| 6466 | +** [[the xCreate() page cache methods]] | |
| 6297 | 6467 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 6298 | 6468 | ** SQLite will typically create one cache instance for each open database file, |
| 6299 | 6469 | ** though this is not guaranteed. ^The |
| 6300 | 6470 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 6301 | 6471 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -6316,20 +6486,23 @@ | ||
| 6316 | 6486 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 6317 | 6487 | ** false will always have the "discard" flag set to true. |
| 6318 | 6488 | ** ^Hence, a cache created with bPurgeable false will |
| 6319 | 6489 | ** never contain any unpinned pages. |
| 6320 | 6490 | ** |
| 6491 | +** [[the xCachesize() page cache method]] | |
| 6321 | 6492 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 6322 | 6493 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 6323 | 6494 | ** instance passed as the first argument. This is the value configured using |
| 6324 | 6495 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 6325 | 6496 | ** parameter, the implementation is not required to do anything with this |
| 6326 | 6497 | ** value; it is advisory only. |
| 6327 | 6498 | ** |
| 6499 | +** [[the xPagecount() page cache methods]] | |
| 6328 | 6500 | ** The xPagecount() method must return the number of pages currently |
| 6329 | 6501 | ** stored in the cache, both pinned and unpinned. |
| 6330 | 6502 | ** |
| 6503 | +** [[the xFetch() page cache methods]] | |
| 6331 | 6504 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 6332 | 6505 | ** the page, or a NULL pointer. |
| 6333 | 6506 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 6334 | 6507 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 6335 | 6508 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -6354,10 +6527,11 @@ | ||
| 6354 | 6527 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 6355 | 6528 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 6356 | 6529 | ** attempt to unpin one or more cache pages by spilling the content of |
| 6357 | 6530 | ** pinned pages to disk and synching the operating system disk cache. |
| 6358 | 6531 | ** |
| 6532 | +** [[the xUnpin() page cache method]] | |
| 6359 | 6533 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 6360 | 6534 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 6361 | 6535 | ** then the page must be evicted from the cache. |
| 6362 | 6536 | ** ^If the discard parameter is |
| 6363 | 6537 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -6366,10 +6540,11 @@ | ||
| 6366 | 6540 | ** |
| 6367 | 6541 | ** The cache must not perform any reference counting. A single |
| 6368 | 6542 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 6369 | 6543 | ** to xFetch(). |
| 6370 | 6544 | ** |
| 6545 | +** [[the xRekey() page cache methods]] | |
| 6371 | 6546 | ** The xRekey() method is used to change the key value associated with the |
| 6372 | 6547 | ** page passed as the second argument. If the cache |
| 6373 | 6548 | ** previously contains an entry associated with newKey, it must be |
| 6374 | 6549 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 6375 | 6550 | ** to be pinned. |
| @@ -6378,10 +6553,11 @@ | ||
| 6378 | 6553 | ** existing cache entries with page numbers (keys) greater than or equal |
| 6379 | 6554 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 6380 | 6555 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 6381 | 6556 | ** they can be safely discarded. |
| 6382 | 6557 | ** |
| 6558 | +** [[the xDestroy() page cache method]] | |
| 6383 | 6559 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 6384 | 6560 | ** All resources associated with the specified cache should be freed. ^After |
| 6385 | 6561 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 6386 | 6562 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 6387 | 6563 | ** functions. |
| @@ -6440,11 +6616,11 @@ | ||
| 6440 | 6616 | ** associated with the backup operation. |
| 6441 | 6617 | ** </ol>)^ |
| 6442 | 6618 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 6443 | 6619 | ** successful call to sqlite3_backup_init(). |
| 6444 | 6620 | ** |
| 6445 | -** <b>sqlite3_backup_init()</b> | |
| 6621 | +** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b> | |
| 6446 | 6622 | ** |
| 6447 | 6623 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 6448 | 6624 | ** [database connection] associated with the destination database |
| 6449 | 6625 | ** and the database name, respectively. |
| 6450 | 6626 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -6467,11 +6643,11 @@ | ||
| 6467 | 6643 | ** [sqlite3_backup] object. |
| 6468 | 6644 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 6469 | 6645 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 6470 | 6646 | ** operation. |
| 6471 | 6647 | ** |
| 6472 | -** <b>sqlite3_backup_step()</b> | |
| 6648 | +** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b> | |
| 6473 | 6649 | ** |
| 6474 | 6650 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 6475 | 6651 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 6476 | 6652 | ** ^If N is negative, all remaining source pages are copied. |
| 6477 | 6653 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -6524,11 +6700,11 @@ | ||
| 6524 | 6700 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 6525 | 6701 | ** database is modified by the using the same database connection as is used |
| 6526 | 6702 | ** by the backup operation, then the backup database is automatically |
| 6527 | 6703 | ** updated at the same time. |
| 6528 | 6704 | ** |
| 6529 | -** <b>sqlite3_backup_finish()</b> | |
| 6705 | +** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b> | |
| 6530 | 6706 | ** |
| 6531 | 6707 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 6532 | 6708 | ** application wishes to abandon the backup operation, the application |
| 6533 | 6709 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 6534 | 6710 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6547,11 +6723,12 @@ | ||
| 6547 | 6723 | ** |
| 6548 | 6724 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6549 | 6725 | ** is not a permanent error and does not affect the return value of |
| 6550 | 6726 | ** sqlite3_backup_finish(). |
| 6551 | 6727 | ** |
| 6552 | -** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b> | |
| 6728 | +** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] | |
| 6729 | +** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> | |
| 6553 | 6730 | ** |
| 6554 | 6731 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6555 | 6732 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6556 | 6733 | ** up and the total number of pages in the source database file. |
| 6557 | 6734 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6932,10 +7109,97 @@ | ||
| 6932 | 7109 | ** each of these values. |
| 6933 | 7110 | */ |
| 6934 | 7111 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 6935 | 7112 | #define SQLITE_CHECKPOINT_FULL 1 |
| 6936 | 7113 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 7114 | + | |
| 7115 | +/* | |
| 7116 | +** CAPI3REF: Virtual Table Interface Configuration | |
| 7117 | +** | |
| 7118 | +** This function may be called by either the [xConnect] or [xCreate] method | |
| 7119 | +** of a [virtual table] implementation to configure | |
| 7120 | +** various facets of the virtual table interface. | |
| 7121 | +** | |
| 7122 | +** If this interface is invoked outside the context of an xConnect or | |
| 7123 | +** xCreate virtual table method then the behavior is undefined. | |
| 7124 | +** | |
| 7125 | +** At present, there is only one option that may be configured using | |
| 7126 | +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options | |
| 7127 | +** may be added in the future. | |
| 7128 | +*/ | |
| 7129 | +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); | |
| 7130 | + | |
| 7131 | +/* | |
| 7132 | +** CAPI3REF: Virtual Table Configuration Options | |
| 7133 | +** | |
| 7134 | +** These macros define the various options to the | |
| 7135 | +** [sqlite3_vtab_config()] interface that [virtual table] implementations | |
| 7136 | +** can use to customize and optimize their behavior. | |
| 7137 | +** | |
| 7138 | +** <dl> | |
| 7139 | +** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT | |
| 7140 | +** <dd>Calls of the form | |
| 7141 | +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, | |
| 7142 | +** where X is an integer. If X is zero, then the [virtual table] whose | |
| 7143 | +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not | |
| 7144 | +** support constraints. In this configuration (which is the default) if | |
| 7145 | +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire | |
| 7146 | +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been | |
| 7147 | +** specified as part of the users SQL statement, regardless of the actual | |
| 7148 | +** ON CONFLICT mode specified. | |
| 7149 | +** | |
| 7150 | +** If X is non-zero, then the virtual table implementation guarantees | |
| 7151 | +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before | |
| 7152 | +** any modifications to internal or persistent data structures have been made. | |
| 7153 | +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite | |
| 7154 | +** is able to roll back a statement or database transaction, and abandon | |
| 7155 | +** or continue processing the current SQL statement as appropriate. | |
| 7156 | +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns | |
| 7157 | +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode | |
| 7158 | +** had been ABORT. | |
| 7159 | +** | |
| 7160 | +** Virtual table implementations that are required to handle OR REPLACE | |
| 7161 | +** must do so within the [xUpdate] method. If a call to the | |
| 7162 | +** [sqlite3_vtab_on_conflict()] function indicates that the current ON | |
| 7163 | +** CONFLICT policy is REPLACE, the virtual table implementation should | |
| 7164 | +** silently replace the appropriate rows within the xUpdate callback and | |
| 7165 | +** return SQLITE_OK. Or, if this is not possible, it may return | |
| 7166 | +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT | |
| 7167 | +** constraint handling. | |
| 7168 | +** </dl> | |
| 7169 | +*/ | |
| 7170 | +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 | |
| 7171 | + | |
| 7172 | +/* | |
| 7173 | +** CAPI3REF: Determine The Virtual Table Conflict Policy | |
| 7174 | +** | |
| 7175 | +** This function may only be called from within a call to the [xUpdate] method | |
| 7176 | +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The | |
| 7177 | +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], | |
| 7178 | +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode | |
| 7179 | +** of the SQL statement that triggered the call to the [xUpdate] method of the | |
| 7180 | +** [virtual table]. | |
| 7181 | +*/ | |
| 7182 | +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); | |
| 7183 | + | |
| 7184 | +/* | |
| 7185 | +** CAPI3REF: Conflict resolution modes | |
| 7186 | +** | |
| 7187 | +** These constants are returned by [sqlite3_vtab_on_conflict()] to | |
| 7188 | +** inform a [virtual table] implementation what the [ON CONFLICT] mode | |
| 7189 | +** is for the SQL statement being evaluated. | |
| 7190 | +** | |
| 7191 | +** Note that the [SQLITE_IGNORE] constant is also used as a potential | |
| 7192 | +** return value from the [sqlite3_set_authorizer()] callback and that | |
| 7193 | +** [SQLITE_ABORT] is also a [result code]. | |
| 7194 | +*/ | |
| 7195 | +#define SQLITE_ROLLBACK 1 | |
| 7196 | +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ | |
| 7197 | +#define SQLITE_FAIL 3 | |
| 7198 | +/* #define SQLITE_ABORT 4 // Also an error code */ | |
| 7199 | +#define SQLITE_REPLACE 5 | |
| 7200 | + | |
| 6937 | 7201 | |
| 6938 | 7202 | |
| 6939 | 7203 | /* |
| 6940 | 7204 | ** Undo the hack that converts floating point types to integer for |
| 6941 | 7205 | ** builds on processors without floating point support. |
| @@ -7599,10 +7863,11 @@ | ||
| 7599 | 7863 | typedef struct Trigger Trigger; |
| 7600 | 7864 | typedef struct TriggerPrg TriggerPrg; |
| 7601 | 7865 | typedef struct TriggerStep TriggerStep; |
| 7602 | 7866 | typedef struct UnpackedRecord UnpackedRecord; |
| 7603 | 7867 | typedef struct VTable VTable; |
| 7868 | +typedef struct VtabCtx VtabCtx; | |
| 7604 | 7869 | typedef struct Walker Walker; |
| 7605 | 7870 | typedef struct WherePlan WherePlan; |
| 7606 | 7871 | typedef struct WhereInfo WhereInfo; |
| 7607 | 7872 | typedef struct WhereLevel WhereLevel; |
| 7608 | 7873 | |
| @@ -7655,10 +7920,11 @@ | ||
| 7655 | 7920 | typedef struct BtCursor BtCursor; |
| 7656 | 7921 | typedef struct BtShared BtShared; |
| 7657 | 7922 | |
| 7658 | 7923 | |
| 7659 | 7924 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 7925 | + sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ | |
| 7660 | 7926 | const char *zFilename, /* Name of database file to open */ |
| 7661 | 7927 | sqlite3 *db, /* Associated database connection */ |
| 7662 | 7928 | Btree **ppBtree, /* Return open Btree* here */ |
| 7663 | 7929 | int flags, /* Flags */ |
| 7664 | 7930 | int vfsFlags /* Flags passed through to VFS open */ |
| @@ -9134,19 +9400,20 @@ | ||
| 9134 | 9400 | struct sqlite3 { |
| 9135 | 9401 | sqlite3_vfs *pVfs; /* OS Interface */ |
| 9136 | 9402 | int nDb; /* Number of backends currently in use */ |
| 9137 | 9403 | Db *aDb; /* All backends */ |
| 9138 | 9404 | int flags; /* Miscellaneous flags. See below */ |
| 9139 | - int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ | |
| 9405 | + unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ | |
| 9140 | 9406 | int errCode; /* Most recent error code (SQLITE_*) */ |
| 9141 | 9407 | int errMask; /* & result codes with this before returning */ |
| 9142 | 9408 | u8 autoCommit; /* The auto-commit flag. */ |
| 9143 | 9409 | u8 temp_store; /* 1: file 2: memory 0: default */ |
| 9144 | 9410 | u8 mallocFailed; /* True if we have seen a malloc failure */ |
| 9145 | 9411 | u8 dfltLockMode; /* Default locking-mode for attached dbs */ |
| 9146 | 9412 | signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ |
| 9147 | 9413 | u8 suppressErr; /* Do not issue error messages if true */ |
| 9414 | + u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ | |
| 9148 | 9415 | int nextPagesize; /* Pagesize after VACUUM if >0 */ |
| 9149 | 9416 | int nTable; /* Number of tables in the database */ |
| 9150 | 9417 | CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ |
| 9151 | 9418 | i64 lastRowid; /* ROWID of most recent insert (see above) */ |
| 9152 | 9419 | u32 magic; /* Magic number for detect library misuse */ |
| @@ -9201,11 +9468,11 @@ | ||
| 9201 | 9468 | void *pProgressArg; /* Argument to the progress callback */ |
| 9202 | 9469 | int nProgressOps; /* Number of opcodes for progress callback */ |
| 9203 | 9470 | #endif |
| 9204 | 9471 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 9205 | 9472 | Hash aModule; /* populated by sqlite3_create_module() */ |
| 9206 | - Table *pVTab; /* vtab with active Connect/Create method */ | |
| 9473 | + VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ | |
| 9207 | 9474 | VTable **aVTrans; /* Virtual tables with open transactions */ |
| 9208 | 9475 | int nVTrans; /* Allocated size of aVTrans */ |
| 9209 | 9476 | VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ |
| 9210 | 9477 | #endif |
| 9211 | 9478 | FuncDefHash aFunc; /* Hash table of connection functions */ |
| @@ -9564,10 +9831,11 @@ | ||
| 9564 | 9831 | struct VTable { |
| 9565 | 9832 | sqlite3 *db; /* Database connection associated with this table */ |
| 9566 | 9833 | Module *pMod; /* Pointer to module implementation */ |
| 9567 | 9834 | sqlite3_vtab *pVtab; /* Pointer to vtab instance */ |
| 9568 | 9835 | int nRef; /* Number of pointers to this structure */ |
| 9836 | + u8 bConstraint; /* True if constraints are supported */ | |
| 9569 | 9837 | VTable *pNext; /* Next in linked list (see above) */ |
| 9570 | 9838 | }; |
| 9571 | 9839 | |
| 9572 | 9840 | /* |
| 9573 | 9841 | ** Each SQL table is represented in memory by an instance of the |
| @@ -10752,10 +11020,11 @@ | ||
| 10752 | 11020 | */ |
| 10753 | 11021 | struct Sqlite3Config { |
| 10754 | 11022 | int bMemstat; /* True to enable memory status */ |
| 10755 | 11023 | int bCoreMutex; /* True to enable core mutexing */ |
| 10756 | 11024 | int bFullMutex; /* True to enable full mutexing */ |
| 11025 | + int bOpenUri; /* True to interpret filenames as URIs */ | |
| 10757 | 11026 | int mxStrlen; /* Maximum string length */ |
| 10758 | 11027 | int szLookaside; /* Default lookaside buffer size */ |
| 10759 | 11028 | int nLookaside; /* Default lookaside buffer count */ |
| 10760 | 11029 | sqlite3_mem_methods m; /* Low-level memory allocation interface */ |
| 10761 | 11030 | sqlite3_mutex_methods mutex; /* Low-level mutex interface */ |
| @@ -11001,10 +11270,12 @@ | ||
| 11001 | 11270 | SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); |
| 11002 | 11271 | SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); |
| 11003 | 11272 | SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); |
| 11004 | 11273 | SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); |
| 11005 | 11274 | SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*); |
| 11275 | +SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, | |
| 11276 | + sqlite3_vfs**,char**,char **); | |
| 11006 | 11277 | |
| 11007 | 11278 | SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); |
| 11008 | 11279 | SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); |
| 11009 | 11280 | SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); |
| 11010 | 11281 | SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); |
| @@ -11251,10 +11522,11 @@ | ||
| 11251 | 11522 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 11252 | 11523 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 11253 | 11524 | SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); |
| 11254 | 11525 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 11255 | 11526 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 11527 | +SQLITE_PRIVATE u8 sqlite3HexToInt(int h); | |
| 11256 | 11528 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 11257 | 11529 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 11258 | 11530 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| 11259 | 11531 | SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); |
| 11260 | 11532 | SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); |
| @@ -11266,10 +11538,16 @@ | ||
| 11266 | 11538 | SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); |
| 11267 | 11539 | SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); |
| 11268 | 11540 | SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); |
| 11269 | 11541 | SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); |
| 11270 | 11542 | SQLITE_PRIVATE int sqlite3AbsInt32(int); |
| 11543 | +#ifdef SQLITE_ENABLE_8_3_NAMES | |
| 11544 | +SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); | |
| 11545 | +#else | |
| 11546 | +# define sqlite3FileSuffix3(X,Y) | |
| 11547 | +#endif | |
| 11548 | +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z); | |
| 11271 | 11549 | |
| 11272 | 11550 | SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); |
| 11273 | 11551 | SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); |
| 11274 | 11552 | SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, |
| 11275 | 11553 | void(*)(void*)); |
| @@ -11375,18 +11653,20 @@ | ||
| 11375 | 11653 | # define sqlite3VtabCommit(X) |
| 11376 | 11654 | # define sqlite3VtabInSync(db) 0 |
| 11377 | 11655 | # define sqlite3VtabLock(X) |
| 11378 | 11656 | # define sqlite3VtabUnlock(X) |
| 11379 | 11657 | # define sqlite3VtabUnlockList(X) |
| 11658 | +# define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK | |
| 11380 | 11659 | #else |
| 11381 | 11660 | SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); |
| 11382 | 11661 | SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, char **); |
| 11383 | 11662 | SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); |
| 11384 | 11663 | SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); |
| 11385 | 11664 | SQLITE_PRIVATE void sqlite3VtabLock(VTable *); |
| 11386 | 11665 | SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); |
| 11387 | 11666 | SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); |
| 11667 | +SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); | |
| 11388 | 11668 | # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) |
| 11389 | 11669 | #endif |
| 11390 | 11670 | SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); |
| 11391 | 11671 | SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); |
| 11392 | 11672 | SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); |
| @@ -11689,20 +11969,23 @@ | ||
| 11689 | 11969 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ |
| 11690 | 11970 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ |
| 11691 | 11971 | }; |
| 11692 | 11972 | #endif |
| 11693 | 11973 | |
| 11694 | - | |
| 11974 | +#ifndef SQLITE_USE_URI | |
| 11975 | +# define SQLITE_USE_URI 0 | |
| 11976 | +#endif | |
| 11695 | 11977 | |
| 11696 | 11978 | /* |
| 11697 | 11979 | ** The following singleton contains the global configuration for |
| 11698 | 11980 | ** the SQLite library. |
| 11699 | 11981 | */ |
| 11700 | 11982 | SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { |
| 11701 | 11983 | SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ |
| 11702 | 11984 | 1, /* bCoreMutex */ |
| 11703 | 11985 | SQLITE_THREADSAFE==1, /* bFullMutex */ |
| 11986 | + SQLITE_USE_URI, /* bOpenUri */ | |
| 11704 | 11987 | 0x7ffffffe, /* mxStrlen */ |
| 11705 | 11988 | 100, /* szLookaside */ |
| 11706 | 11989 | 500, /* nLookaside */ |
| 11707 | 11990 | {0,0,0,0,0,0,0,0}, /* m */ |
| 11708 | 11991 | {0,0,0,0,0,0,0,0,0}, /* mutex */ |
| @@ -17948,11 +18231,11 @@ | ||
| 17948 | 18231 | assert( sqlite3_mutex_held(mem0.mutex) ); |
| 17949 | 18232 | nFull = sqlite3GlobalConfig.m.xRoundup(n); |
| 17950 | 18233 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); |
| 17951 | 18234 | if( mem0.alarmCallback!=0 ){ |
| 17952 | 18235 | int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); |
| 17953 | - if( nUsed+nFull >= mem0.alarmThreshold ){ | |
| 18236 | + if( nUsed >= mem0.alarmThreshold - nFull ){ | |
| 17954 | 18237 | mem0.nearlyFull = 1; |
| 17955 | 18238 | sqlite3MallocAlarm(nFull); |
| 17956 | 18239 | }else{ |
| 17957 | 18240 | mem0.nearlyFull = 0; |
| 17958 | 18241 | } |
| @@ -18189,11 +18472,11 @@ | ||
| 18189 | 18472 | |
| 18190 | 18473 | /* |
| 18191 | 18474 | ** Change the size of an existing memory allocation |
| 18192 | 18475 | */ |
| 18193 | 18476 | SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ |
| 18194 | - int nOld, nNew; | |
| 18477 | + int nOld, nNew, nDiff; | |
| 18195 | 18478 | void *pNew; |
| 18196 | 18479 | if( pOld==0 ){ |
| 18197 | 18480 | return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ |
| 18198 | 18481 | } |
| 18199 | 18482 | if( nBytes<=0 ){ |
| @@ -18212,13 +18495,14 @@ | ||
| 18212 | 18495 | if( nOld==nNew ){ |
| 18213 | 18496 | pNew = pOld; |
| 18214 | 18497 | }else if( sqlite3GlobalConfig.bMemstat ){ |
| 18215 | 18498 | sqlite3_mutex_enter(mem0.mutex); |
| 18216 | 18499 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); |
| 18217 | - if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= | |
| 18218 | - mem0.alarmThreshold ){ | |
| 18219 | - sqlite3MallocAlarm(nNew-nOld); | |
| 18500 | + nDiff = nNew - nOld; | |
| 18501 | + if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= | |
| 18502 | + mem0.alarmThreshold-nDiff ){ | |
| 18503 | + sqlite3MallocAlarm(nDiff); | |
| 18220 | 18504 | } |
| 18221 | 18505 | assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); |
| 18222 | 18506 | assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); |
| 18223 | 18507 | pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
| 18224 | 18508 | if( pNew==0 && mem0.alarmCallback ){ |
| @@ -21180,27 +21464,25 @@ | ||
| 21180 | 21464 | p[3] = (u8)v; |
| 21181 | 21465 | } |
| 21182 | 21466 | |
| 21183 | 21467 | |
| 21184 | 21468 | |
| 21185 | -#if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) | |
| 21186 | 21469 | /* |
| 21187 | 21470 | ** Translate a single byte of Hex into an integer. |
| 21188 | 21471 | ** This routine only works if h really is a valid hexadecimal |
| 21189 | 21472 | ** character: 0..9a..fA..F |
| 21190 | 21473 | */ |
| 21191 | -static u8 hexToInt(int h){ | |
| 21474 | +SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ | |
| 21192 | 21475 | assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); |
| 21193 | 21476 | #ifdef SQLITE_ASCII |
| 21194 | 21477 | h += 9*(1&(h>>6)); |
| 21195 | 21478 | #endif |
| 21196 | 21479 | #ifdef SQLITE_EBCDIC |
| 21197 | 21480 | h += 9*(1&~(h>>4)); |
| 21198 | 21481 | #endif |
| 21199 | 21482 | return (u8)(h & 0xf); |
| 21200 | 21483 | } |
| 21201 | -#endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ | |
| 21202 | 21484 | |
| 21203 | 21485 | #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) |
| 21204 | 21486 | /* |
| 21205 | 21487 | ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary |
| 21206 | 21488 | ** value. Return a pointer to its binary value. Space to hold the |
| @@ -21213,11 +21495,11 @@ | ||
| 21213 | 21495 | |
| 21214 | 21496 | zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1); |
| 21215 | 21497 | n--; |
| 21216 | 21498 | if( zBlob ){ |
| 21217 | 21499 | for(i=0; i<n; i+=2){ |
| 21218 | - zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); | |
| 21500 | + zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]); | |
| 21219 | 21501 | } |
| 21220 | 21502 | zBlob[i/2] = 0; |
| 21221 | 21503 | } |
| 21222 | 21504 | return zBlob; |
| 21223 | 21505 | } |
| @@ -21345,10 +21627,36 @@ | ||
| 21345 | 21627 | SQLITE_PRIVATE int sqlite3AbsInt32(int x){ |
| 21346 | 21628 | if( x>=0 ) return x; |
| 21347 | 21629 | if( x==(int)0x80000000 ) return 0x7fffffff; |
| 21348 | 21630 | return -x; |
| 21349 | 21631 | } |
| 21632 | + | |
| 21633 | +#ifdef SQLITE_ENABLE_8_3_NAMES | |
| 21634 | +/* | |
| 21635 | +** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database | |
| 21636 | +** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and | |
| 21637 | +** if filename in z[] has a suffix (a.k.a. "extension") that is longer than | |
| 21638 | +** three characters, then shorten the suffix on z[] to be the last three | |
| 21639 | +** characters of the original suffix. | |
| 21640 | +** | |
| 21641 | +** Examples: | |
| 21642 | +** | |
| 21643 | +** test.db-journal => test.nal | |
| 21644 | +** test.db-wal => test.wal | |
| 21645 | +** test.db-shm => test.shm | |
| 21646 | +*/ | |
| 21647 | +SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ | |
| 21648 | + const char *zOk; | |
| 21649 | + zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); | |
| 21650 | + if( zOk && sqlite3GetBoolean(zOk) ){ | |
| 21651 | + int i, sz; | |
| 21652 | + sz = sqlite3Strlen30(z); | |
| 21653 | + for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} | |
| 21654 | + if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4); | |
| 21655 | + } | |
| 21656 | +} | |
| 21657 | +#endif | |
| 21350 | 21658 | |
| 21351 | 21659 | /************** End of util.c ************************************************/ |
| 21352 | 21660 | /************** Begin file hash.c ********************************************/ |
| 21353 | 21661 | /* |
| 21354 | 21662 | ** 2001 September 22 |
| @@ -24398,10 +24706,22 @@ | ||
| 24398 | 24706 | #if SQLITE_THREADSAFE |
| 24399 | 24707 | #define threadid pthread_self() |
| 24400 | 24708 | #else |
| 24401 | 24709 | #define threadid 0 |
| 24402 | 24710 | #endif |
| 24711 | + | |
| 24712 | +/* | |
| 24713 | +** Different Unix systems declare open() in different ways. Same use | |
| 24714 | +** open(const char*,int,mode_t). Others use open(const char*,int,...). | |
| 24715 | +** The difference is important when using a pointer to the function. | |
| 24716 | +** | |
| 24717 | +** The safest way to deal with the problem is to always use this wrapper | |
| 24718 | +** which always has the same well-defined interface. | |
| 24719 | +*/ | |
| 24720 | +static int posixOpen(const char *zFile, int flags, int mode){ | |
| 24721 | + return open(zFile, flags, mode); | |
| 24722 | +} | |
| 24403 | 24723 | |
| 24404 | 24724 | /* |
| 24405 | 24725 | ** Many system calls are accessed through pointer-to-functions so that |
| 24406 | 24726 | ** they may be overridden at runtime to facilitate fault injection during |
| 24407 | 24727 | ** testing and sandboxing. The following array holds the names and pointers |
| @@ -24410,11 +24730,11 @@ | ||
| 24410 | 24730 | static struct unix_syscall { |
| 24411 | 24731 | const char *zName; /* Name of the sytem call */ |
| 24412 | 24732 | sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ |
| 24413 | 24733 | sqlite3_syscall_ptr pDefault; /* Default value */ |
| 24414 | 24734 | } aSyscall[] = { |
| 24415 | - { "open", (sqlite3_syscall_ptr)open, 0 }, | |
| 24735 | + { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, | |
| 24416 | 24736 | #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) |
| 24417 | 24737 | |
| 24418 | 24738 | { "close", (sqlite3_syscall_ptr)close, 0 }, |
| 24419 | 24739 | #define osClose ((int(*)(int))aSyscall[1].pCurrent) |
| 24420 | 24740 | |
| @@ -24448,11 +24768,11 @@ | ||
| 24448 | 24768 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 24449 | 24769 | |
| 24450 | 24770 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 24451 | 24771 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 24452 | 24772 | |
| 24453 | -#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) | |
| 24773 | +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE | |
| 24454 | 24774 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 24455 | 24775 | #else |
| 24456 | 24776 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 24457 | 24777 | #endif |
| 24458 | 24778 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -24465,11 +24785,11 @@ | ||
| 24465 | 24785 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 24466 | 24786 | |
| 24467 | 24787 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 24468 | 24788 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 24469 | 24789 | |
| 24470 | -#if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) | |
| 24790 | +#if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE | |
| 24471 | 24791 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 24472 | 24792 | #else |
| 24473 | 24793 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 24474 | 24794 | #endif |
| 24475 | 24795 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -24483,12 +24803,14 @@ | ||
| 24483 | 24803 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 24484 | 24804 | aSyscall[13].pCurrent) |
| 24485 | 24805 | |
| 24486 | 24806 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 24487 | 24807 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 24808 | +#else | |
| 24809 | + { "fchmod", (sqlite3_syscall_ptr)0, 0 }, | |
| 24810 | +#endif | |
| 24488 | 24811 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 24489 | -#endif | |
| 24490 | 24812 | |
| 24491 | 24813 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 24492 | 24814 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 24493 | 24815 | #else |
| 24494 | 24816 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -25049,11 +25371,11 @@ | ||
| 25049 | 25371 | unixShmNode *pShmNode; /* Shared memory associated with this inode */ |
| 25050 | 25372 | int nLock; /* Number of outstanding file locks */ |
| 25051 | 25373 | UnixUnusedFd *pUnused; /* Unused file descriptors to close */ |
| 25052 | 25374 | unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ |
| 25053 | 25375 | unixInodeInfo *pPrev; /* .... doubly linked */ |
| 25054 | -#if defined(SQLITE_ENABLE_LOCKING_STYLE) | |
| 25376 | +#if SQLITE_ENABLE_LOCKING_STYLE | |
| 25055 | 25377 | unsigned long long sharedByte; /* for AFP simulated shared lock */ |
| 25056 | 25378 | #endif |
| 25057 | 25379 | #if OS_VXWORKS |
| 25058 | 25380 | sem_t *pSem; /* Named POSIX semaphore */ |
| 25059 | 25381 | char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ |
| @@ -27206,11 +27528,11 @@ | ||
| 27206 | 27528 | } |
| 27207 | 27529 | SimulateIOError(( wrote=(-1), amt=1 )); |
| 27208 | 27530 | SimulateDiskfullError(( wrote=0, amt=1 )); |
| 27209 | 27531 | |
| 27210 | 27532 | if( amt>0 ){ |
| 27211 | - if( wrote<0 ){ | |
| 27533 | + if( wrote<0 && pFile->lastErrno!=ENOSPC ){ | |
| 27212 | 27534 | /* lastErrno set by seekAndWrite */ |
| 27213 | 27535 | return SQLITE_IOERR_WRITE; |
| 27214 | 27536 | }else{ |
| 27215 | 27537 | pFile->lastErrno = 0; /* not a system error */ |
| 27216 | 27538 | return SQLITE_FULL; |
| @@ -27873,10 +28195,11 @@ | ||
| 27873 | 28195 | sqlite3_snprintf(nShmFilename, zShmFilename, |
| 27874 | 28196 | SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", |
| 27875 | 28197 | (u32)sStat.st_ino, (u32)sStat.st_dev); |
| 27876 | 28198 | #else |
| 27877 | 28199 | sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); |
| 28200 | + sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); | |
| 27878 | 28201 | #endif |
| 27879 | 28202 | pShmNode->h = -1; |
| 27880 | 28203 | pDbFd->pInode->pShmNode = pShmNode; |
| 27881 | 28204 | pShmNode->pInode = pDbFd->pInode; |
| 27882 | 28205 | pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| @@ -28031,11 +28354,11 @@ | ||
| 28031 | 28354 | if( pShmNode->h>=0 ){ |
| 28032 | 28355 | pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, |
| 28033 | 28356 | MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion |
| 28034 | 28357 | ); |
| 28035 | 28358 | if( pMem==MAP_FAILED ){ |
| 28036 | - rc = SQLITE_IOERR; | |
| 28359 | + rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); | |
| 28037 | 28360 | goto shmpage_out; |
| 28038 | 28361 | } |
| 28039 | 28362 | }else{ |
| 28040 | 28363 | pMem = sqlite3_malloc(szRegion); |
| 28041 | 28364 | if( pMem==0 ){ |
| @@ -28906,17 +29229,23 @@ | ||
| 28906 | 29229 | ** Finally, if the file being opened is a WAL or regular journal file, then |
| 28907 | 29230 | ** this function queries the file-system for the permissions on the |
| 28908 | 29231 | ** corresponding database file and sets *pMode to this value. Whenever |
| 28909 | 29232 | ** possible, WAL and journal files are created using the same permissions |
| 28910 | 29233 | ** as the associated database file. |
| 29234 | +** | |
| 29235 | +** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the | |
| 29236 | +** original filename is unavailable. But 8_3_NAMES is only used for | |
| 29237 | +** FAT filesystems and permissions do not matter there, so just use | |
| 29238 | +** the default permissions. | |
| 28911 | 29239 | */ |
| 28912 | 29240 | static int findCreateFileMode( |
| 28913 | 29241 | const char *zPath, /* Path of file (possibly) being created */ |
| 28914 | 29242 | int flags, /* Flags passed as 4th argument to xOpen() */ |
| 28915 | 29243 | mode_t *pMode /* OUT: Permissions to open file with */ |
| 28916 | 29244 | ){ |
| 28917 | 29245 | int rc = SQLITE_OK; /* Return Code */ |
| 29246 | + *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; | |
| 28918 | 29247 | if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
| 28919 | 29248 | char zDb[MAX_PATHNAME+1]; /* Database file path */ |
| 28920 | 29249 | int nDb; /* Number of valid bytes in zDb */ |
| 28921 | 29250 | struct stat sStat; /* Output of stat() on database file */ |
| 28922 | 29251 | |
| @@ -28924,19 +29253,19 @@ | ||
| 28924 | 29253 | ** the path to the associated database file from zPath. This block handles |
| 28925 | 29254 | ** the following naming conventions: |
| 28926 | 29255 | ** |
| 28927 | 29256 | ** "<path to db>-journal" |
| 28928 | 29257 | ** "<path to db>-wal" |
| 28929 | - ** "<path to db>-journal-NNNN" | |
| 28930 | - ** "<path to db>-wal-NNNN" | |
| 29258 | + ** "<path to db>-journalNN" | |
| 29259 | + ** "<path to db>-walNN" | |
| 28931 | 29260 | ** |
| 28932 | - ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are | |
| 29261 | + ** where NN is a 4 digit decimal number. The NN naming schemes are | |
| 28933 | 29262 | ** used by the test_multiplex.c module. |
| 28934 | 29263 | */ |
| 28935 | 29264 | nDb = sqlite3Strlen30(zPath) - 1; |
| 28936 | - while( nDb>0 && zPath[nDb]!='l' ) nDb--; | |
| 28937 | - nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7); | |
| 29265 | + while( nDb>0 && zPath[nDb]!='-' ) nDb--; | |
| 29266 | + if( nDb==0 ) return SQLITE_OK; | |
| 28938 | 29267 | memcpy(zDb, zPath, nDb); |
| 28939 | 29268 | zDb[nDb] = '\0'; |
| 28940 | 29269 | |
| 28941 | 29270 | if( 0==stat(zDb, &sStat) ){ |
| 28942 | 29271 | *pMode = sStat.st_mode & 0777; |
| @@ -28943,12 +29272,10 @@ | ||
| 28943 | 29272 | }else{ |
| 28944 | 29273 | rc = SQLITE_IOERR_FSTAT; |
| 28945 | 29274 | } |
| 28946 | 29275 | }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
| 28947 | 29276 | *pMode = 0600; |
| 28948 | - }else{ | |
| 28949 | - *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; | |
| 28950 | 29277 | } |
| 28951 | 29278 | return rc; |
| 28952 | 29279 | } |
| 28953 | 29280 | |
| 28954 | 29281 | /* |
| @@ -30801,10 +31128,14 @@ | ||
| 30801 | 31128 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 30802 | 31129 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| 30803 | 31130 | #endif |
| 30804 | 31131 | }; |
| 30805 | 31132 | unsigned int i; /* Loop counter */ |
| 31133 | + | |
| 31134 | + /* Double-check that the aSyscall[] array has been constructed | |
| 31135 | + ** correctly. See ticket [bb3a86e890c8e96ab] */ | |
| 31136 | + assert( ArraySize(aSyscall)==16 ); | |
| 30806 | 31137 | |
| 30807 | 31138 | /* Register all VFSes defined in the aVfs[] array */ |
| 30808 | 31139 | for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ |
| 30809 | 31140 | sqlite3_vfs_register(&aVfs[i], i==0); |
| 30810 | 31141 | } |
| @@ -31147,10 +31478,11 @@ | ||
| 31147 | 31478 | HANDLE hShared; /* Shared memory segment used for locking */ |
| 31148 | 31479 | winceLock local; /* Locks obtained by this instance of winFile */ |
| 31149 | 31480 | winceLock *shared; /* Global shared lock memory for the file */ |
| 31150 | 31481 | #endif |
| 31151 | 31482 | }; |
| 31483 | + | |
| 31152 | 31484 | |
| 31153 | 31485 | /* |
| 31154 | 31486 | ** Forward prototypes. |
| 31155 | 31487 | */ |
| 31156 | 31488 | static int getSectorSize( |
| @@ -31315,11 +31647,11 @@ | ||
| 31315 | 31647 | |
| 31316 | 31648 | /* |
| 31317 | 31649 | ** Convert UTF-8 to multibyte character string. Space to hold the |
| 31318 | 31650 | ** returned string is obtained from malloc(). |
| 31319 | 31651 | */ |
| 31320 | -static char *utf8ToMbcs(const char *zFilename){ | |
| 31652 | +SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ | |
| 31321 | 31653 | char *zFilenameMbcs; |
| 31322 | 31654 | WCHAR *zTmpWide; |
| 31323 | 31655 | |
| 31324 | 31656 | zTmpWide = utf8ToUnicode(zFilename); |
| 31325 | 31657 | if( zTmpWide==0 ){ |
| @@ -31328,10 +31660,113 @@ | ||
| 31328 | 31660 | zFilenameMbcs = unicodeToMbcs(zTmpWide); |
| 31329 | 31661 | free(zTmpWide); |
| 31330 | 31662 | return zFilenameMbcs; |
| 31331 | 31663 | } |
| 31332 | 31664 | |
| 31665 | + | |
| 31666 | +/* | |
| 31667 | +** The return value of getLastErrorMsg | |
| 31668 | +** is zero if the error message fits in the buffer, or non-zero | |
| 31669 | +** otherwise (if the message was truncated). | |
| 31670 | +*/ | |
| 31671 | +static int getLastErrorMsg(int nBuf, char *zBuf){ | |
| 31672 | + /* FormatMessage returns 0 on failure. Otherwise it | |
| 31673 | + ** returns the number of TCHARs written to the output | |
| 31674 | + ** buffer, excluding the terminating null char. | |
| 31675 | + */ | |
| 31676 | + DWORD error = GetLastError(); | |
| 31677 | + DWORD dwLen = 0; | |
| 31678 | + char *zOut = 0; | |
| 31679 | + | |
| 31680 | + if( isNT() ){ | |
| 31681 | + WCHAR *zTempWide = NULL; | |
| 31682 | + dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 31683 | + NULL, | |
| 31684 | + error, | |
| 31685 | + 0, | |
| 31686 | + (LPWSTR) &zTempWide, | |
| 31687 | + 0, | |
| 31688 | + 0); | |
| 31689 | + if( dwLen > 0 ){ | |
| 31690 | + /* allocate a buffer and convert to UTF8 */ | |
| 31691 | + zOut = unicodeToUtf8(zTempWide); | |
| 31692 | + /* free the system buffer allocated by FormatMessage */ | |
| 31693 | + LocalFree(zTempWide); | |
| 31694 | + } | |
| 31695 | +/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. | |
| 31696 | +** Since the ASCII version of these Windows API do not exist for WINCE, | |
| 31697 | +** it's important to not reference them for WINCE builds. | |
| 31698 | +*/ | |
| 31699 | +#if SQLITE_OS_WINCE==0 | |
| 31700 | + }else{ | |
| 31701 | + char *zTemp = NULL; | |
| 31702 | + dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 31703 | + NULL, | |
| 31704 | + error, | |
| 31705 | + 0, | |
| 31706 | + (LPSTR) &zTemp, | |
| 31707 | + 0, | |
| 31708 | + 0); | |
| 31709 | + if( dwLen > 0 ){ | |
| 31710 | + /* allocate a buffer and convert to UTF8 */ | |
| 31711 | + zOut = sqlite3_win32_mbcs_to_utf8(zTemp); | |
| 31712 | + /* free the system buffer allocated by FormatMessage */ | |
| 31713 | + LocalFree(zTemp); | |
| 31714 | + } | |
| 31715 | +#endif | |
| 31716 | + } | |
| 31717 | + if( 0 == dwLen ){ | |
| 31718 | + sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); | |
| 31719 | + }else{ | |
| 31720 | + /* copy a maximum of nBuf chars to output buffer */ | |
| 31721 | + sqlite3_snprintf(nBuf, zBuf, "%s", zOut); | |
| 31722 | + /* free the UTF8 buffer */ | |
| 31723 | + free(zOut); | |
| 31724 | + } | |
| 31725 | + return 0; | |
| 31726 | +} | |
| 31727 | + | |
| 31728 | +/* | |
| 31729 | +** | |
| 31730 | +** This function - winLogErrorAtLine() - is only ever called via the macro | |
| 31731 | +** winLogError(). | |
| 31732 | +** | |
| 31733 | +** This routine is invoked after an error occurs in an OS function. | |
| 31734 | +** It logs a message using sqlite3_log() containing the current value of | |
| 31735 | +** error code and, if possible, the human-readable equivalent from | |
| 31736 | +** FormatMessage. | |
| 31737 | +** | |
| 31738 | +** The first argument passed to the macro should be the error code that | |
| 31739 | +** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). | |
| 31740 | +** The two subsequent arguments should be the name of the OS function that | |
| 31741 | +** failed and the the associated file-system path, if any. | |
| 31742 | +*/ | |
| 31743 | +#define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__) | |
| 31744 | +static int winLogErrorAtLine( | |
| 31745 | + int errcode, /* SQLite error code */ | |
| 31746 | + const char *zFunc, /* Name of OS function that failed */ | |
| 31747 | + const char *zPath, /* File path associated with error */ | |
| 31748 | + int iLine /* Source line number where error occurred */ | |
| 31749 | +){ | |
| 31750 | + char zMsg[500]; /* Human readable error text */ | |
| 31751 | + int i; /* Loop counter */ | |
| 31752 | + DWORD iErrno = GetLastError(); /* Error code */ | |
| 31753 | + | |
| 31754 | + zMsg[0] = 0; | |
| 31755 | + getLastErrorMsg(sizeof(zMsg), zMsg); | |
| 31756 | + assert( errcode!=SQLITE_OK ); | |
| 31757 | + if( zPath==0 ) zPath = ""; | |
| 31758 | + for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} | |
| 31759 | + zMsg[i] = 0; | |
| 31760 | + sqlite3_log(errcode, | |
| 31761 | + "os_win.c:%d: (%d) %s(%s) - %s", | |
| 31762 | + iLine, iErrno, zFunc, zPath, zMsg | |
| 31763 | + ); | |
| 31764 | + | |
| 31765 | + return errcode; | |
| 31766 | +} | |
| 31767 | + | |
| 31333 | 31768 | #if SQLITE_OS_WINCE |
| 31334 | 31769 | /************************************************************************* |
| 31335 | 31770 | ** This section contains code for WinCE only. |
| 31336 | 31771 | */ |
| 31337 | 31772 | /* |
| @@ -31404,10 +31839,11 @@ | ||
| 31404 | 31839 | |
| 31405 | 31840 | /* Create/open the named mutex */ |
| 31406 | 31841 | pFile->hMutex = CreateMutexW(NULL, FALSE, zName); |
| 31407 | 31842 | if (!pFile->hMutex){ |
| 31408 | 31843 | pFile->lastErrno = GetLastError(); |
| 31844 | + winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename); | |
| 31409 | 31845 | free(zName); |
| 31410 | 31846 | return FALSE; |
| 31411 | 31847 | } |
| 31412 | 31848 | |
| 31413 | 31849 | /* Acquire the mutex before continuing */ |
| @@ -31435,10 +31871,11 @@ | ||
| 31435 | 31871 | pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, |
| 31436 | 31872 | FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); |
| 31437 | 31873 | /* If mapping failed, close the shared memory handle and erase it */ |
| 31438 | 31874 | if (!pFile->shared){ |
| 31439 | 31875 | pFile->lastErrno = GetLastError(); |
| 31876 | + winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename); | |
| 31440 | 31877 | CloseHandle(pFile->hShared); |
| 31441 | 31878 | pFile->hShared = NULL; |
| 31442 | 31879 | } |
| 31443 | 31880 | } |
| 31444 | 31881 | |
| @@ -31680,10 +32117,11 @@ | ||
| 31680 | 32117 | ** GetLastError(). |
| 31681 | 32118 | */ |
| 31682 | 32119 | dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
| 31683 | 32120 | if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ |
| 31684 | 32121 | pFile->lastErrno = GetLastError(); |
| 32122 | + winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath); | |
| 31685 | 32123 | return 1; |
| 31686 | 32124 | } |
| 31687 | 32125 | |
| 31688 | 32126 | return 0; |
| 31689 | 32127 | } |
| @@ -31725,11 +32163,12 @@ | ||
| 31725 | 32163 | free(pFile->zDeleteOnClose); |
| 31726 | 32164 | } |
| 31727 | 32165 | #endif |
| 31728 | 32166 | OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed")); |
| 31729 | 32167 | OpenCounter(-1); |
| 31730 | - return rc ? SQLITE_OK : SQLITE_IOERR; | |
| 32168 | + return rc ? SQLITE_OK | |
| 32169 | + : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath); | |
| 31731 | 32170 | } |
| 31732 | 32171 | |
| 31733 | 32172 | /* |
| 31734 | 32173 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| 31735 | 32174 | ** bytes were read successfully and SQLITE_IOERR if anything goes |
| @@ -31751,11 +32190,11 @@ | ||
| 31751 | 32190 | if( seekWinFile(pFile, offset) ){ |
| 31752 | 32191 | return SQLITE_FULL; |
| 31753 | 32192 | } |
| 31754 | 32193 | if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ |
| 31755 | 32194 | pFile->lastErrno = GetLastError(); |
| 31756 | - return SQLITE_IOERR_READ; | |
| 32195 | + return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); | |
| 31757 | 32196 | } |
| 31758 | 32197 | if( nRead<(DWORD)amt ){ |
| 31759 | 32198 | /* Unread parts of the buffer must be zero-filled */ |
| 31760 | 32199 | memset(&((char*)pBuf)[nRead], 0, amt-nRead); |
| 31761 | 32200 | return SQLITE_IOERR_SHORT_READ; |
| @@ -31802,11 +32241,11 @@ | ||
| 31802 | 32241 | |
| 31803 | 32242 | if( rc ){ |
| 31804 | 32243 | if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){ |
| 31805 | 32244 | return SQLITE_FULL; |
| 31806 | 32245 | } |
| 31807 | - return SQLITE_IOERR_WRITE; | |
| 32246 | + return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); | |
| 31808 | 32247 | } |
| 31809 | 32248 | return SQLITE_OK; |
| 31810 | 32249 | } |
| 31811 | 32250 | |
| 31812 | 32251 | /* |
| @@ -31830,14 +32269,14 @@ | ||
| 31830 | 32269 | nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
| 31831 | 32270 | } |
| 31832 | 32271 | |
| 31833 | 32272 | /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ |
| 31834 | 32273 | if( seekWinFile(pFile, nByte) ){ |
| 31835 | - rc = SQLITE_IOERR_TRUNCATE; | |
| 32274 | + rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath); | |
| 31836 | 32275 | }else if( 0==SetEndOfFile(pFile->h) ){ |
| 31837 | 32276 | pFile->lastErrno = GetLastError(); |
| 31838 | - rc = SQLITE_IOERR_TRUNCATE; | |
| 32277 | + rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath); | |
| 31839 | 32278 | } |
| 31840 | 32279 | |
| 31841 | 32280 | OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok")); |
| 31842 | 32281 | return rc; |
| 31843 | 32282 | } |
| @@ -31855,10 +32294,11 @@ | ||
| 31855 | 32294 | ** Make sure all writes to a particular file are committed to disk. |
| 31856 | 32295 | */ |
| 31857 | 32296 | static int winSync(sqlite3_file *id, int flags){ |
| 31858 | 32297 | #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG) |
| 31859 | 32298 | winFile *pFile = (winFile*)id; |
| 32299 | + BOOL rc; | |
| 31860 | 32300 | #else |
| 31861 | 32301 | UNUSED_PARAMETER(id); |
| 31862 | 32302 | #endif |
| 31863 | 32303 | |
| 31864 | 32304 | assert( pFile ); |
| @@ -31867,36 +32307,37 @@ | ||
| 31867 | 32307 | || (flags&0x0F)==SQLITE_SYNC_FULL |
| 31868 | 32308 | ); |
| 31869 | 32309 | |
| 31870 | 32310 | OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype)); |
| 31871 | 32311 | |
| 32312 | + /* Unix cannot, but some systems may return SQLITE_FULL from here. This | |
| 32313 | + ** line is to test that doing so does not cause any problems. | |
| 32314 | + */ | |
| 32315 | + SimulateDiskfullError( return SQLITE_FULL ); | |
| 32316 | + | |
| 31872 | 32317 | #ifndef SQLITE_TEST |
| 31873 | 32318 | UNUSED_PARAMETER(flags); |
| 31874 | 32319 | #else |
| 31875 | - if( flags & SQLITE_SYNC_FULL ){ | |
| 32320 | + if( (flags&0x0F)==SQLITE_SYNC_FULL ){ | |
| 31876 | 32321 | sqlite3_fullsync_count++; |
| 31877 | 32322 | } |
| 31878 | 32323 | sqlite3_sync_count++; |
| 31879 | 32324 | #endif |
| 31880 | 32325 | |
| 31881 | - /* Unix cannot, but some systems may return SQLITE_FULL from here. This | |
| 31882 | - ** line is to test that doing so does not cause any problems. | |
| 31883 | - */ | |
| 31884 | - SimulateDiskfullError( return SQLITE_FULL ); | |
| 31885 | - SimulateIOError( return SQLITE_IOERR; ); | |
| 31886 | - | |
| 31887 | 32326 | /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a |
| 31888 | 32327 | ** no-op |
| 31889 | 32328 | */ |
| 31890 | 32329 | #ifdef SQLITE_NO_SYNC |
| 31891 | 32330 | return SQLITE_OK; |
| 31892 | 32331 | #else |
| 31893 | - if( FlushFileBuffers(pFile->h) ){ | |
| 32332 | + rc = FlushFileBuffers(pFile->h); | |
| 32333 | + SimulateIOError( rc=FALSE ); | |
| 32334 | + if( rc ){ | |
| 31894 | 32335 | return SQLITE_OK; |
| 31895 | 32336 | }else{ |
| 31896 | 32337 | pFile->lastErrno = GetLastError(); |
| 31897 | - return SQLITE_IOERR; | |
| 32338 | + return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath); | |
| 31898 | 32339 | } |
| 31899 | 32340 | #endif |
| 31900 | 32341 | } |
| 31901 | 32342 | |
| 31902 | 32343 | /* |
| @@ -31913,11 +32354,11 @@ | ||
| 31913 | 32354 | lowerBits = GetFileSize(pFile->h, &upperBits); |
| 31914 | 32355 | if( (lowerBits == INVALID_FILE_SIZE) |
| 31915 | 32356 | && ((error = GetLastError()) != NO_ERROR) ) |
| 31916 | 32357 | { |
| 31917 | 32358 | pFile->lastErrno = error; |
| 31918 | - return SQLITE_IOERR_FSTAT; | |
| 32359 | + return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath); | |
| 31919 | 32360 | } |
| 31920 | 32361 | *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; |
| 31921 | 32362 | return SQLITE_OK; |
| 31922 | 32363 | } |
| 31923 | 32364 | |
| @@ -31952,10 +32393,11 @@ | ||
| 31952 | 32393 | res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
| 31953 | 32394 | #endif |
| 31954 | 32395 | } |
| 31955 | 32396 | if( res == 0 ){ |
| 31956 | 32397 | pFile->lastErrno = GetLastError(); |
| 32398 | + /* No need to log a failure to lock */ | |
| 31957 | 32399 | } |
| 31958 | 32400 | return res; |
| 31959 | 32401 | } |
| 31960 | 32402 | |
| 31961 | 32403 | /* |
| @@ -31970,12 +32412,13 @@ | ||
| 31970 | 32412 | #if SQLITE_OS_WINCE==0 |
| 31971 | 32413 | }else{ |
| 31972 | 32414 | res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); |
| 31973 | 32415 | #endif |
| 31974 | 32416 | } |
| 31975 | - if( res == 0 ){ | |
| 32417 | + if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){ | |
| 31976 | 32418 | pFile->lastErrno = GetLastError(); |
| 32419 | + winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath); | |
| 31977 | 32420 | } |
| 31978 | 32421 | return res; |
| 31979 | 32422 | } |
| 31980 | 32423 | |
| 31981 | 32424 | /* |
| @@ -32172,11 +32615,11 @@ | ||
| 32172 | 32615 | if( type>=EXCLUSIVE_LOCK ){ |
| 32173 | 32616 | UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
| 32174 | 32617 | if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ |
| 32175 | 32618 | /* This should never happen. We should always be able to |
| 32176 | 32619 | ** reacquire the read lock */ |
| 32177 | - rc = SQLITE_IOERR_UNLOCK; | |
| 32620 | + rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath); | |
| 32178 | 32621 | } |
| 32179 | 32622 | } |
| 32180 | 32623 | if( type>=RESERVED_LOCK ){ |
| 32181 | 32624 | UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
| 32182 | 32625 | } |
| @@ -32487,10 +32930,11 @@ | ||
| 32487 | 32930 | return SQLITE_NOMEM; |
| 32488 | 32931 | } |
| 32489 | 32932 | memset(pNew, 0, sizeof(*pNew)); |
| 32490 | 32933 | pNew->zFilename = (char*)&pNew[1]; |
| 32491 | 32934 | sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); |
| 32935 | + sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); | |
| 32492 | 32936 | |
| 32493 | 32937 | /* Look to see if there is an existing winShmNode that can be used. |
| 32494 | 32938 | ** If no matching winShmNode currently exists, create a new one. |
| 32495 | 32939 | */ |
| 32496 | 32940 | winShmEnterMutex(); |
| @@ -32529,11 +32973,11 @@ | ||
| 32529 | 32973 | ** If not, truncate the file to zero length. |
| 32530 | 32974 | */ |
| 32531 | 32975 | if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ |
| 32532 | 32976 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); |
| 32533 | 32977 | if( rc!=SQLITE_OK ){ |
| 32534 | - rc = SQLITE_IOERR_SHMOPEN; | |
| 32978 | + rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath); | |
| 32535 | 32979 | } |
| 32536 | 32980 | } |
| 32537 | 32981 | if( rc==SQLITE_OK ){ |
| 32538 | 32982 | winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); |
| 32539 | 32983 | rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); |
| @@ -32788,11 +33232,11 @@ | ||
| 32788 | 33232 | ** Check to see if it has been allocated (i.e. if the wal-index file is |
| 32789 | 33233 | ** large enough to contain the requested region). |
| 32790 | 33234 | */ |
| 32791 | 33235 | rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); |
| 32792 | 33236 | if( rc!=SQLITE_OK ){ |
| 32793 | - rc = SQLITE_IOERR_SHMSIZE; | |
| 33237 | + rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath); | |
| 32794 | 33238 | goto shmpage_out; |
| 32795 | 33239 | } |
| 32796 | 33240 | |
| 32797 | 33241 | if( sz<nByte ){ |
| 32798 | 33242 | /* The requested memory region does not exist. If isWrite is set to |
| @@ -32802,11 +33246,11 @@ | ||
| 32802 | 33246 | ** the requested memory region. |
| 32803 | 33247 | */ |
| 32804 | 33248 | if( !isWrite ) goto shmpage_out; |
| 32805 | 33249 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); |
| 32806 | 33250 | if( rc!=SQLITE_OK ){ |
| 32807 | - rc = SQLITE_IOERR_SHMSIZE; | |
| 33251 | + rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath); | |
| 32808 | 33252 | goto shmpage_out; |
| 32809 | 33253 | } |
| 32810 | 33254 | } |
| 32811 | 33255 | |
| 32812 | 33256 | /* Map the requested memory region into this processes address space. */ |
| @@ -32839,11 +33283,11 @@ | ||
| 32839 | 33283 | (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, |
| 32840 | 33284 | pMap ? "ok" : "failed")); |
| 32841 | 33285 | } |
| 32842 | 33286 | if( !pMap ){ |
| 32843 | 33287 | pShmNode->lastErrno = GetLastError(); |
| 32844 | - rc = SQLITE_IOERR; | |
| 33288 | + rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath); | |
| 32845 | 33289 | if( hMap ) CloseHandle(hMap); |
| 32846 | 33290 | goto shmpage_out; |
| 32847 | 33291 | } |
| 32848 | 33292 | |
| 32849 | 33293 | pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; |
| @@ -32921,11 +33365,11 @@ | ||
| 32921 | 33365 | zConverted = utf8ToUnicode(zFilename); |
| 32922 | 33366 | /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. |
| 32923 | 33367 | */ |
| 32924 | 33368 | #if SQLITE_OS_WINCE==0 |
| 32925 | 33369 | }else{ |
| 32926 | - zConverted = utf8ToMbcs(zFilename); | |
| 33370 | + zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); | |
| 32927 | 33371 | #endif |
| 32928 | 33372 | } |
| 32929 | 33373 | /* caller will handle out of memory */ |
| 32930 | 33374 | return zConverted; |
| 32931 | 33375 | } |
| @@ -33001,72 +33445,10 @@ | ||
| 33001 | 33445 | |
| 33002 | 33446 | OSTRACE(("TEMP FILENAME: %s\n", zBuf)); |
| 33003 | 33447 | return SQLITE_OK; |
| 33004 | 33448 | } |
| 33005 | 33449 | |
| 33006 | -/* | |
| 33007 | -** The return value of getLastErrorMsg | |
| 33008 | -** is zero if the error message fits in the buffer, or non-zero | |
| 33009 | -** otherwise (if the message was truncated). | |
| 33010 | -*/ | |
| 33011 | -static int getLastErrorMsg(int nBuf, char *zBuf){ | |
| 33012 | - /* FormatMessage returns 0 on failure. Otherwise it | |
| 33013 | - ** returns the number of TCHARs written to the output | |
| 33014 | - ** buffer, excluding the terminating null char. | |
| 33015 | - */ | |
| 33016 | - DWORD error = GetLastError(); | |
| 33017 | - DWORD dwLen = 0; | |
| 33018 | - char *zOut = 0; | |
| 33019 | - | |
| 33020 | - if( isNT() ){ | |
| 33021 | - WCHAR *zTempWide = NULL; | |
| 33022 | - dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 33023 | - NULL, | |
| 33024 | - error, | |
| 33025 | - 0, | |
| 33026 | - (LPWSTR) &zTempWide, | |
| 33027 | - 0, | |
| 33028 | - 0); | |
| 33029 | - if( dwLen > 0 ){ | |
| 33030 | - /* allocate a buffer and convert to UTF8 */ | |
| 33031 | - zOut = unicodeToUtf8(zTempWide); | |
| 33032 | - /* free the system buffer allocated by FormatMessage */ | |
| 33033 | - LocalFree(zTempWide); | |
| 33034 | - } | |
| 33035 | -/* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. | |
| 33036 | -** Since the ASCII version of these Windows API do not exist for WINCE, | |
| 33037 | -** it's important to not reference them for WINCE builds. | |
| 33038 | -*/ | |
| 33039 | -#if SQLITE_OS_WINCE==0 | |
| 33040 | - }else{ | |
| 33041 | - char *zTemp = NULL; | |
| 33042 | - dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, | |
| 33043 | - NULL, | |
| 33044 | - error, | |
| 33045 | - 0, | |
| 33046 | - (LPSTR) &zTemp, | |
| 33047 | - 0, | |
| 33048 | - 0); | |
| 33049 | - if( dwLen > 0 ){ | |
| 33050 | - /* allocate a buffer and convert to UTF8 */ | |
| 33051 | - zOut = sqlite3_win32_mbcs_to_utf8(zTemp); | |
| 33052 | - /* free the system buffer allocated by FormatMessage */ | |
| 33053 | - LocalFree(zTemp); | |
| 33054 | - } | |
| 33055 | -#endif | |
| 33056 | - } | |
| 33057 | - if( 0 == dwLen ){ | |
| 33058 | - sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); | |
| 33059 | - }else{ | |
| 33060 | - /* copy a maximum of nBuf chars to output buffer */ | |
| 33061 | - sqlite3_snprintf(nBuf, zBuf, "%s", zOut); | |
| 33062 | - /* free the UTF8 buffer */ | |
| 33063 | - free(zOut); | |
| 33064 | - } | |
| 33065 | - return 0; | |
| 33066 | -} | |
| 33067 | - | |
| 33068 | 33450 | /* |
| 33069 | 33451 | ** Open a file. |
| 33070 | 33452 | */ |
| 33071 | 33453 | static int winOpen( |
| 33072 | 33454 | sqlite3_vfs *pVfs, /* Not used */ |
| @@ -33234,10 +33616,11 @@ | ||
| 33234 | 33616 | h, zName, dwDesiredAccess, |
| 33235 | 33617 | h==INVALID_HANDLE_VALUE ? "failed" : "ok")); |
| 33236 | 33618 | |
| 33237 | 33619 | if( h==INVALID_HANDLE_VALUE ){ |
| 33238 | 33620 | pFile->lastErrno = GetLastError(); |
| 33621 | + winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name); | |
| 33239 | 33622 | free(zConverted); |
| 33240 | 33623 | if( isReadWrite ){ |
| 33241 | 33624 | return winOpen(pVfs, zName, id, |
| 33242 | 33625 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); |
| 33243 | 33626 | }else{ |
| @@ -33337,11 +33720,12 @@ | ||
| 33337 | 33720 | OSTRACE(("DELETE \"%s\" %s\n", zFilename, |
| 33338 | 33721 | ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ? |
| 33339 | 33722 | "ok" : "failed" )); |
| 33340 | 33723 | |
| 33341 | 33724 | return ( (rc == INVALID_FILE_ATTRIBUTES) |
| 33342 | - && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE; | |
| 33725 | + && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : | |
| 33726 | + winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); | |
| 33343 | 33727 | } |
| 33344 | 33728 | |
| 33345 | 33729 | /* |
| 33346 | 33730 | ** Check the existance and status of a file. |
| 33347 | 33731 | */ |
| @@ -33377,10 +33761,11 @@ | ||
| 33377 | 33761 | }else{ |
| 33378 | 33762 | attr = sAttrData.dwFileAttributes; |
| 33379 | 33763 | } |
| 33380 | 33764 | }else{ |
| 33381 | 33765 | if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ |
| 33766 | + winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename); | |
| 33382 | 33767 | free(zConverted); |
| 33383 | 33768 | return SQLITE_IOERR_ACCESS; |
| 33384 | 33769 | }else{ |
| 33385 | 33770 | attr = INVALID_FILE_ATTRIBUTES; |
| 33386 | 33771 | } |
| @@ -33440,10 +33825,17 @@ | ||
| 33440 | 33825 | |
| 33441 | 33826 | #if !SQLITE_OS_WINCE && !defined(__CYGWIN__) |
| 33442 | 33827 | int nByte; |
| 33443 | 33828 | void *zConverted; |
| 33444 | 33829 | char *zOut; |
| 33830 | + | |
| 33831 | + /* If this path name begins with "/X:", where "X" is any alphabetic | |
| 33832 | + ** character, discard the initial "/" from the pathname. | |
| 33833 | + */ | |
| 33834 | + if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){ | |
| 33835 | + zRelative++; | |
| 33836 | + } | |
| 33445 | 33837 | |
| 33446 | 33838 | /* It's odd to simulate an io-error here, but really this is just |
| 33447 | 33839 | ** using the io-error infrastructure to test that SQLite handles this |
| 33448 | 33840 | ** function failing. This function could fail if, for example, the |
| 33449 | 33841 | ** current working directory has been unlinked. |
| @@ -36252,10 +36644,11 @@ | ||
| 36252 | 36644 | #define _WAL_H_ |
| 36253 | 36645 | |
| 36254 | 36646 | |
| 36255 | 36647 | #ifdef SQLITE_OMIT_WAL |
| 36256 | 36648 | # define sqlite3WalOpen(x,y,z) 0 |
| 36649 | +# define sqlite3WalLimit(x,y) | |
| 36257 | 36650 | # define sqlite3WalClose(w,x,y,z) 0 |
| 36258 | 36651 | # define sqlite3WalBeginReadTransaction(y,z) 0 |
| 36259 | 36652 | # define sqlite3WalEndReadTransaction(z) |
| 36260 | 36653 | # define sqlite3WalRead(v,w,x,y,z) 0 |
| 36261 | 36654 | # define sqlite3WalDbsize(y) 0 |
| @@ -36277,13 +36670,16 @@ | ||
| 36277 | 36670 | ** There is one object of this type for each pager. |
| 36278 | 36671 | */ |
| 36279 | 36672 | typedef struct Wal Wal; |
| 36280 | 36673 | |
| 36281 | 36674 | /* Open and close a connection to a write-ahead log. */ |
| 36282 | -SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**); | |
| 36675 | +SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); | |
| 36283 | 36676 | SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); |
| 36284 | 36677 | |
| 36678 | +/* Set the limiting size of a WAL file. */ | |
| 36679 | +SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); | |
| 36680 | + | |
| 36285 | 36681 | /* Used by readers to open (lock) and close (unlock) a snapshot. A |
| 36286 | 36682 | ** snapshot is like a read-transaction. It is the state of the database |
| 36287 | 36683 | ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and |
| 36288 | 36684 | ** preserves the current state even if the other threads or processes |
| 36289 | 36685 | ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the |
| @@ -40628,10 +41024,12 @@ | ||
| 40628 | 41024 | int nPathname = 0; /* Number of bytes in zPathname */ |
| 40629 | 41025 | int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ |
| 40630 | 41026 | int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */ |
| 40631 | 41027 | int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ |
| 40632 | 41028 | u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ |
| 41029 | + const char *zUri = 0; /* URI args to copy */ | |
| 41030 | + int nUri = 0; /* Number of bytes of URI args at *zUri */ | |
| 40633 | 41031 | |
| 40634 | 41032 | /* Figure out how much space is required for each journal file-handle |
| 40635 | 41033 | ** (there are two of them, the main journal and the sub-journal). This |
| 40636 | 41034 | ** is the maximum space required for an in-memory journal file handle |
| 40637 | 41035 | ** and a regular journal file-handle. Note that a "regular journal-handle" |
| @@ -40658,18 +41056,25 @@ | ||
| 40658 | 41056 | /* Compute and store the full pathname in an allocated buffer pointed |
| 40659 | 41057 | ** to by zPathname, length nPathname. Or, if this is a temporary file, |
| 40660 | 41058 | ** leave both nPathname and zPathname set to 0. |
| 40661 | 41059 | */ |
| 40662 | 41060 | if( zFilename && zFilename[0] ){ |
| 41061 | + const char *z; | |
| 40663 | 41062 | nPathname = pVfs->mxPathname+1; |
| 40664 | 41063 | zPathname = sqlite3Malloc(nPathname*2); |
| 40665 | 41064 | if( zPathname==0 ){ |
| 40666 | 41065 | return SQLITE_NOMEM; |
| 40667 | 41066 | } |
| 40668 | 41067 | zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ |
| 40669 | 41068 | rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); |
| 40670 | 41069 | nPathname = sqlite3Strlen30(zPathname); |
| 41070 | + z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; | |
| 41071 | + while( *z ){ | |
| 41072 | + z += sqlite3Strlen30(z)+1; | |
| 41073 | + z += sqlite3Strlen30(z)+1; | |
| 41074 | + } | |
| 41075 | + nUri = &z[1] - zUri; | |
| 40671 | 41076 | if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ |
| 40672 | 41077 | /* This branch is taken when the journal path required by |
| 40673 | 41078 | ** the database being opened will be more than pVfs->mxPathname |
| 40674 | 41079 | ** bytes in length. This means the database cannot be opened, |
| 40675 | 41080 | ** as it will not be possible to open the journal file or even |
| @@ -40698,11 +41103,11 @@ | ||
| 40698 | 41103 | pPtr = (u8 *)sqlite3MallocZero( |
| 40699 | 41104 | ROUND8(sizeof(*pPager)) + /* Pager structure */ |
| 40700 | 41105 | ROUND8(pcacheSize) + /* PCache object */ |
| 40701 | 41106 | ROUND8(pVfs->szOsFile) + /* The main db file */ |
| 40702 | 41107 | journalFileSize * 2 + /* The two journal files */ |
| 40703 | - nPathname + 1 + /* zFilename */ | |
| 41108 | + nPathname + 1 + nUri + /* zFilename */ | |
| 40704 | 41109 | nPathname + 8 + 1 /* zJournal */ |
| 40705 | 41110 | #ifndef SQLITE_OMIT_WAL |
| 40706 | 41111 | + nPathname + 4 + 1 /* zWal */ |
| 40707 | 41112 | #endif |
| 40708 | 41113 | ); |
| @@ -40720,18 +41125,21 @@ | ||
| 40720 | 41125 | assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); |
| 40721 | 41126 | |
| 40722 | 41127 | /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ |
| 40723 | 41128 | if( zPathname ){ |
| 40724 | 41129 | assert( nPathname>0 ); |
| 40725 | - pPager->zJournal = (char*)(pPtr += nPathname + 1); | |
| 41130 | + pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); | |
| 40726 | 41131 | memcpy(pPager->zFilename, zPathname, nPathname); |
| 41132 | + memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); | |
| 40727 | 41133 | memcpy(pPager->zJournal, zPathname, nPathname); |
| 40728 | 41134 | memcpy(&pPager->zJournal[nPathname], "-journal", 8); |
| 41135 | + sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); | |
| 40729 | 41136 | #ifndef SQLITE_OMIT_WAL |
| 40730 | 41137 | pPager->zWal = &pPager->zJournal[nPathname+8+1]; |
| 40731 | 41138 | memcpy(pPager->zWal, zPathname, nPathname); |
| 40732 | 41139 | memcpy(&pPager->zWal[nPathname], "-wal", 4); |
| 41140 | + sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); | |
| 40733 | 41141 | #endif |
| 40734 | 41142 | sqlite3_free(zPathname); |
| 40735 | 41143 | } |
| 40736 | 41144 | pPager->pVfs = pVfs; |
| 40737 | 41145 | pPager->vfsFlags = vfsFlags; |
| @@ -42064,15 +42472,25 @@ | ||
| 42064 | 42472 | */ |
| 42065 | 42473 | sqlite3BackupRestart(pPager->pBackup); |
| 42066 | 42474 | }else{ |
| 42067 | 42475 | if( pagerUseWal(pPager) ){ |
| 42068 | 42476 | PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); |
| 42069 | - if( pList ){ | |
| 42477 | + PgHdr *pPageOne = 0; | |
| 42478 | + if( pList==0 ){ | |
| 42479 | + /* Must have at least one page for the WAL commit flag. | |
| 42480 | + ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ | |
| 42481 | + rc = sqlite3PagerGet(pPager, 1, &pPageOne); | |
| 42482 | + pList = pPageOne; | |
| 42483 | + pList->pDirty = 0; | |
| 42484 | + } | |
| 42485 | + assert( rc==SQLITE_OK ); | |
| 42486 | + if( ALWAYS(pList) ){ | |
| 42070 | 42487 | rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, |
| 42071 | 42488 | (pPager->fullSync ? pPager->syncFlags : 0) |
| 42072 | 42489 | ); |
| 42073 | 42490 | } |
| 42491 | + sqlite3PagerUnref(pPageOne); | |
| 42074 | 42492 | if( rc==SQLITE_OK ){ |
| 42075 | 42493 | sqlite3PcacheCleanAll(pPager->pPCache); |
| 42076 | 42494 | } |
| 42077 | 42495 | }else{ |
| 42078 | 42496 | /* The following block updates the change-counter. Exactly how it |
| @@ -42926,10 +43344,11 @@ | ||
| 42926 | 43344 | ** An attempt to set a limit smaller than -1 is a no-op. |
| 42927 | 43345 | */ |
| 42928 | 43346 | SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ |
| 42929 | 43347 | if( iLimit>=-1 ){ |
| 42930 | 43348 | pPager->journalSizeLimit = iLimit; |
| 43349 | + sqlite3WalLimit(pPager->pWal, iLimit); | |
| 42931 | 43350 | } |
| 42932 | 43351 | return pPager->journalSizeLimit; |
| 42933 | 43352 | } |
| 42934 | 43353 | |
| 42935 | 43354 | /* |
| @@ -43017,11 +43436,12 @@ | ||
| 43017 | 43436 | /* Open the connection to the log file. If this operation fails, |
| 43018 | 43437 | ** (e.g. due to malloc() failure), return an error code. |
| 43019 | 43438 | */ |
| 43020 | 43439 | if( rc==SQLITE_OK ){ |
| 43021 | 43440 | rc = sqlite3WalOpen(pPager->pVfs, |
| 43022 | - pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal | |
| 43441 | + pPager->fd, pPager->zWal, pPager->exclusiveMode, | |
| 43442 | + pPager->journalSizeLimit, &pPager->pWal | |
| 43023 | 43443 | ); |
| 43024 | 43444 | } |
| 43025 | 43445 | |
| 43026 | 43446 | return rc; |
| 43027 | 43447 | } |
| @@ -43549,10 +43969,11 @@ | ||
| 43549 | 43969 | struct Wal { |
| 43550 | 43970 | sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ |
| 43551 | 43971 | sqlite3_file *pDbFd; /* File handle for the database file */ |
| 43552 | 43972 | sqlite3_file *pWalFd; /* File handle for WAL file */ |
| 43553 | 43973 | u32 iCallback; /* Value to pass to log callback (or 0) */ |
| 43974 | + i64 mxWalSize; /* Truncate WAL to this size upon reset */ | |
| 43554 | 43975 | int nWiData; /* Size of array apWiData */ |
| 43555 | 43976 | volatile u32 **apWiData; /* Pointer to wal-index content in memory */ |
| 43556 | 43977 | u32 szPage; /* Database page size */ |
| 43557 | 43978 | i16 readLock; /* Which read lock is being held. -1 for none */ |
| 43558 | 43979 | u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */ |
| @@ -44371,10 +44792,11 @@ | ||
| 44371 | 44792 | SQLITE_PRIVATE int sqlite3WalOpen( |
| 44372 | 44793 | sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ |
| 44373 | 44794 | sqlite3_file *pDbFd, /* The open database file */ |
| 44374 | 44795 | const char *zWalName, /* Name of the WAL file */ |
| 44375 | 44796 | int bNoShm, /* True to run in heap-memory mode */ |
| 44797 | + i64 mxWalSize, /* Truncate WAL to this size on reset */ | |
| 44376 | 44798 | Wal **ppWal /* OUT: Allocated Wal handle */ |
| 44377 | 44799 | ){ |
| 44378 | 44800 | int rc; /* Return Code */ |
| 44379 | 44801 | Wal *pRet; /* Object to allocate and return */ |
| 44380 | 44802 | int flags; /* Flags passed to OsOpen() */ |
| @@ -44403,10 +44825,11 @@ | ||
| 44403 | 44825 | |
| 44404 | 44826 | pRet->pVfs = pVfs; |
| 44405 | 44827 | pRet->pWalFd = (sqlite3_file *)&pRet[1]; |
| 44406 | 44828 | pRet->pDbFd = pDbFd; |
| 44407 | 44829 | pRet->readLock = -1; |
| 44830 | + pRet->mxWalSize = mxWalSize; | |
| 44408 | 44831 | pRet->zWalName = zWalName; |
| 44409 | 44832 | pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); |
| 44410 | 44833 | |
| 44411 | 44834 | /* Open file handle on the write-ahead log file. */ |
| 44412 | 44835 | flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); |
| @@ -44423,10 +44846,17 @@ | ||
| 44423 | 44846 | *ppWal = pRet; |
| 44424 | 44847 | WALTRACE(("WAL%d: opened\n", pRet)); |
| 44425 | 44848 | } |
| 44426 | 44849 | return rc; |
| 44427 | 44850 | } |
| 44851 | + | |
| 44852 | +/* | |
| 44853 | +** Change the size to which the WAL file is trucated on each reset. | |
| 44854 | +*/ | |
| 44855 | +SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){ | |
| 44856 | + if( pWal ) pWal->mxWalSize = iLimit; | |
| 44857 | +} | |
| 44428 | 44858 | |
| 44429 | 44859 | /* |
| 44430 | 44860 | ** Find the smallest page number out of all pages held in the WAL that |
| 44431 | 44861 | ** has not been returned by any prior invocation of this method on the |
| 44432 | 44862 | ** same WalIterator object. Write into *piFrame the frame index where |
| @@ -45659,10 +46089,26 @@ | ||
| 45659 | 46089 | ** safe and means there is no special case for sqlite3WalUndo() |
| 45660 | 46090 | ** to handle if this transaction is rolled back. |
| 45661 | 46091 | */ |
| 45662 | 46092 | int i; /* Loop counter */ |
| 45663 | 46093 | u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ |
| 46094 | + | |
| 46095 | + /* Limit the size of WAL file if the journal_size_limit PRAGMA is | |
| 46096 | + ** set to a non-negative value. Log errors encountered | |
| 46097 | + ** during the truncation attempt. */ | |
| 46098 | + if( pWal->mxWalSize>=0 ){ | |
| 46099 | + i64 sz; | |
| 46100 | + int rx; | |
| 46101 | + rx = sqlite3OsFileSize(pWal->pWalFd, &sz); | |
| 46102 | + if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){ | |
| 46103 | + rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize); | |
| 46104 | + } | |
| 46105 | + if( rx ){ | |
| 46106 | + sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); | |
| 46107 | + } | |
| 46108 | + } | |
| 46109 | + | |
| 45664 | 46110 | pWal->nCkpt++; |
| 45665 | 46111 | pWal->hdr.mxFrame = 0; |
| 45666 | 46112 | sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); |
| 45667 | 46113 | aSalt[1] = salt1; |
| 45668 | 46114 | walIndexWriteHdr(pWal); |
| @@ -47764,10 +48210,11 @@ | ||
| 47764 | 48210 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 47765 | 48211 | if( offset<0 ){ |
| 47766 | 48212 | *pRC = SQLITE_CORRUPT_BKPT; |
| 47767 | 48213 | goto ptrmap_exit; |
| 47768 | 48214 | } |
| 48215 | + assert( offset <= (int)pBt->usableSize-5 ); | |
| 47769 | 48216 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 47770 | 48217 | |
| 47771 | 48218 | if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ |
| 47772 | 48219 | TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); |
| 47773 | 48220 | *pRC= rc = sqlite3PagerWrite(pDbPage); |
| @@ -47803,10 +48250,15 @@ | ||
| 47803 | 48250 | return rc; |
| 47804 | 48251 | } |
| 47805 | 48252 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 47806 | 48253 | |
| 47807 | 48254 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 48255 | + if( offset<0 ){ | |
| 48256 | + sqlite3PagerUnref(pDbPage); | |
| 48257 | + return SQLITE_CORRUPT_BKPT; | |
| 48258 | + } | |
| 48259 | + assert( offset <= (int)pBt->usableSize-5 ); | |
| 47808 | 48260 | assert( pEType!=0 ); |
| 47809 | 48261 | *pEType = pPtrmap[offset]; |
| 47810 | 48262 | if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); |
| 47811 | 48263 | |
| 47812 | 48264 | sqlite3PagerUnref(pDbPage); |
| @@ -48664,17 +49116,17 @@ | ||
| 48664 | 49116 | ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared |
| 48665 | 49117 | ** objects in the same database connection since doing so will lead |
| 48666 | 49118 | ** to problems with locking. |
| 48667 | 49119 | */ |
| 48668 | 49120 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 49121 | + sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ | |
| 48669 | 49122 | const char *zFilename, /* Name of the file containing the BTree database */ |
| 48670 | 49123 | sqlite3 *db, /* Associated database handle */ |
| 48671 | 49124 | Btree **ppBtree, /* Pointer to new Btree object written here */ |
| 48672 | 49125 | int flags, /* Options */ |
| 48673 | 49126 | int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ |
| 48674 | 49127 | ){ |
| 48675 | - sqlite3_vfs *pVfs; /* The VFS to use for this btree */ | |
| 48676 | 49128 | BtShared *pBt = 0; /* Shared part of btree structure */ |
| 48677 | 49129 | Btree *p; /* Handle to return */ |
| 48678 | 49130 | sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ |
| 48679 | 49131 | int rc = SQLITE_OK; /* Result code from this function */ |
| 48680 | 49132 | u8 nReserve; /* Byte of unused space on each page */ |
| @@ -48692,10 +49144,11 @@ | ||
| 48692 | 49144 | const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) |
| 48693 | 49145 | || (isTempDb && sqlite3TempInMemory(db)); |
| 48694 | 49146 | #endif |
| 48695 | 49147 | |
| 48696 | 49148 | assert( db!=0 ); |
| 49149 | + assert( pVfs!=0 ); | |
| 48697 | 49150 | assert( sqlite3_mutex_held(db->mutex) ); |
| 48698 | 49151 | assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ |
| 48699 | 49152 | |
| 48700 | 49153 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ |
| 48701 | 49154 | assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); |
| @@ -48710,11 +49163,10 @@ | ||
| 48710 | 49163 | flags |= BTREE_MEMORY; |
| 48711 | 49164 | } |
| 48712 | 49165 | if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ |
| 48713 | 49166 | vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; |
| 48714 | 49167 | } |
| 48715 | - pVfs = db->pVfs; | |
| 48716 | 49168 | p = sqlite3MallocZero(sizeof(Btree)); |
| 48717 | 49169 | if( !p ){ |
| 48718 | 49170 | return SQLITE_NOMEM; |
| 48719 | 49171 | } |
| 48720 | 49172 | p->inTrans = TRANS_NONE; |
| @@ -58781,10 +59233,11 @@ | ||
| 58781 | 59233 | sqlite3_randomness(sizeof(iRandom), &iRandom); |
| 58782 | 59234 | zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff); |
| 58783 | 59235 | if( !zMaster ){ |
| 58784 | 59236 | return SQLITE_NOMEM; |
| 58785 | 59237 | } |
| 59238 | + sqlite3FileSuffix3(zMainFile, zMaster); | |
| 58786 | 59239 | rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); |
| 58787 | 59240 | }while( rc==SQLITE_OK && res ); |
| 58788 | 59241 | if( rc==SQLITE_OK ){ |
| 58789 | 59242 | /* Open the master journal. */ |
| 58790 | 59243 | rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, |
| @@ -58994,10 +59447,19 @@ | ||
| 58994 | 59447 | } |
| 58995 | 59448 | } |
| 58996 | 59449 | } |
| 58997 | 59450 | db->nStatement--; |
| 58998 | 59451 | p->iStatement = 0; |
| 59452 | + | |
| 59453 | + if( rc==SQLITE_OK ){ | |
| 59454 | + if( eOp==SAVEPOINT_ROLLBACK ){ | |
| 59455 | + rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); | |
| 59456 | + } | |
| 59457 | + if( rc==SQLITE_OK ){ | |
| 59458 | + rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); | |
| 59459 | + } | |
| 59460 | + } | |
| 58999 | 59461 | |
| 59000 | 59462 | /* If the statement transaction is being rolled back, also restore the |
| 59001 | 59463 | ** database handles deferred constraint counter to the value it had when |
| 59002 | 59464 | ** the statement transaction was opened. */ |
| 59003 | 59465 | if( eOp==SAVEPOINT_ROLLBACK ){ |
| @@ -59911,11 +60373,11 @@ | ||
| 59911 | 60373 | /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ |
| 59912 | 60374 | VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ |
| 59913 | 60375 | |
| 59914 | 60376 | /* Compilers may complain that mem1.u.i is potentially uninitialized. |
| 59915 | 60377 | ** We could initialize it, as shown here, to silence those complaints. |
| 59916 | - ** But in fact, mem1.u.i will never actually be used initialized, and doing | |
| 60378 | + ** But in fact, mem1.u.i will never actually be used uninitialized, and doing | |
| 59917 | 60379 | ** the unnecessary initialization has a measurable negative performance |
| 59918 | 60380 | ** impact, since this routine is a very high runner. And so, we choose |
| 59919 | 60381 | ** to ignore the compiler warnings and leave this variable uninitialized. |
| 59920 | 60382 | */ |
| 59921 | 60383 | /* mem1.u.i = 0; // not needed, here to silence compiler warning */ |
| @@ -62326,10 +62788,11 @@ | ||
| 62326 | 62788 | Mem *pIn2 = 0; /* 2nd input operand */ |
| 62327 | 62789 | Mem *pIn3 = 0; /* 3rd input operand */ |
| 62328 | 62790 | Mem *pOut = 0; /* Output operand */ |
| 62329 | 62791 | int iCompare = 0; /* Result of last OP_Compare operation */ |
| 62330 | 62792 | int *aPermute = 0; /* Permutation of columns for OP_Compare */ |
| 62793 | + i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ | |
| 62331 | 62794 | #ifdef VDBE_PROFILE |
| 62332 | 62795 | u64 start; /* CPU clock count at start of opcode */ |
| 62333 | 62796 | int origPc; /* Program counter at start of opcode */ |
| 62334 | 62797 | #endif |
| 62335 | 62798 | /******************************************************************** |
| @@ -63004,10 +63467,11 @@ | ||
| 63004 | 63467 | VdbeFrame *pFrame = p->pFrame; |
| 63005 | 63468 | p->pFrame = pFrame->pParent; |
| 63006 | 63469 | p->nFrame--; |
| 63007 | 63470 | sqlite3VdbeSetChanges(db, p->nChange); |
| 63008 | 63471 | pc = sqlite3VdbeFrameRestore(pFrame); |
| 63472 | + lastRowid = db->lastRowid; | |
| 63009 | 63473 | if( pOp->p2==OE_Ignore ){ |
| 63010 | 63474 | /* Instruction pc is the OP_Program that invoked the sub-program |
| 63011 | 63475 | ** currently being halted. If the p2 instruction of this OP_Halt |
| 63012 | 63476 | ** instruction is set to OE_Ignore, then the sub-program is throwing |
| 63013 | 63477 | ** an IGNORE exception. In this case jump to the address specified |
| @@ -63576,11 +64040,13 @@ | ||
| 63576 | 64040 | assert( pOp>aOp ); |
| 63577 | 64041 | assert( pOp[-1].p4type==P4_COLLSEQ ); |
| 63578 | 64042 | assert( pOp[-1].opcode==OP_CollSeq ); |
| 63579 | 64043 | u.ag.ctx.pColl = pOp[-1].p4.pColl; |
| 63580 | 64044 | } |
| 64045 | + db->lastRowid = lastRowid; | |
| 63581 | 64046 | (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */ |
| 64047 | + lastRowid = db->lastRowid; | |
| 63582 | 64048 | if( db->mallocFailed ){ |
| 63583 | 64049 | /* Even though a malloc() has failed, the implementation of the |
| 63584 | 64050 | ** user function may have called an sqlite3_result_XXX() function |
| 63585 | 64051 | ** to return a value. The following call releases any resources |
| 63586 | 64052 | ** associated with such a value. |
| @@ -64783,10 +65249,18 @@ | ||
| 64783 | 65249 | "SQL statements in progress"); |
| 64784 | 65250 | rc = SQLITE_BUSY; |
| 64785 | 65251 | }else{ |
| 64786 | 65252 | u.aq.nName = sqlite3Strlen30(u.aq.zName); |
| 64787 | 65253 | |
| 65254 | + /* This call is Ok even if this savepoint is actually a transaction | |
| 65255 | + ** savepoint (and therefore should not prompt xSavepoint()) callbacks. | |
| 65256 | + ** If this is a transaction savepoint being opened, it is guaranteed | |
| 65257 | + ** that the db->aVTrans[] array is empty. */ | |
| 65258 | + assert( db->autoCommit==0 || db->nVTrans==0 ); | |
| 65259 | + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); | |
| 65260 | + if( rc!=SQLITE_OK ) goto abort_due_to_error; | |
| 65261 | + | |
| 64788 | 65262 | /* Create a new savepoint structure. */ |
| 64789 | 65263 | u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1); |
| 64790 | 65264 | if( u.aq.pNew ){ |
| 64791 | 65265 | u.aq.pNew->zName = (char *)&u.aq.pNew[1]; |
| 64792 | 65266 | memcpy(u.aq.pNew->zName, u.aq.zName, u.aq.nName+1); |
| @@ -64889,10 +65363,15 @@ | ||
| 64889 | 65363 | db->nSavepoint--; |
| 64890 | 65364 | } |
| 64891 | 65365 | }else{ |
| 64892 | 65366 | db->nDeferredCons = u.aq.pSavepoint->nDeferredCons; |
| 64893 | 65367 | } |
| 65368 | + | |
| 65369 | + if( !isTransaction ){ | |
| 65370 | + rc = sqlite3VtabSavepoint(db, u.aq.p1, u.aq.iSavepoint); | |
| 65371 | + if( rc!=SQLITE_OK ) goto abort_due_to_error; | |
| 65372 | + } | |
| 64894 | 65373 | } |
| 64895 | 65374 | } |
| 64896 | 65375 | |
| 64897 | 65376 | break; |
| 64898 | 65377 | } |
| @@ -65028,11 +65507,15 @@ | ||
| 65028 | 65507 | if( p->iStatement==0 ){ |
| 65029 | 65508 | assert( db->nStatement>=0 && db->nSavepoint>=0 ); |
| 65030 | 65509 | db->nStatement++; |
| 65031 | 65510 | p->iStatement = db->nSavepoint + db->nStatement; |
| 65032 | 65511 | } |
| 65033 | - rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement); | |
| 65512 | + | |
| 65513 | + rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); | |
| 65514 | + if( rc==SQLITE_OK ){ | |
| 65515 | + rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement); | |
| 65516 | + } | |
| 65034 | 65517 | |
| 65035 | 65518 | /* Store the current value of the database handles deferred constraint |
| 65036 | 65519 | ** counter. If the statement transaction needs to be rolled back, |
| 65037 | 65520 | ** the value of this counter needs to be restored too. */ |
| 65038 | 65521 | p->nStmtDefCons = db->nDeferredCons; |
| @@ -65349,11 +65832,11 @@ | ||
| 65349 | 65832 | |
| 65350 | 65833 | assert( pOp->p1>=0 ); |
| 65351 | 65834 | u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); |
| 65352 | 65835 | if( u.ax.pCx==0 ) goto no_mem; |
| 65353 | 65836 | u.ax.pCx->nullRow = 1; |
| 65354 | - rc = sqlite3BtreeOpen(0, db, &u.ax.pCx->pBt, | |
| 65837 | + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ax.pCx->pBt, | |
| 65355 | 65838 | BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); |
| 65356 | 65839 | if( rc==SQLITE_OK ){ |
| 65357 | 65840 | rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1); |
| 65358 | 65841 | } |
| 65359 | 65842 | if( rc==SQLITE_OK ){ |
| @@ -66023,11 +66506,11 @@ | ||
| 66023 | 66506 | ** engine starts picking positive candidate ROWIDs at random until |
| 66024 | 66507 | ** it finds one that is not previously used. */ |
| 66025 | 66508 | assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is |
| 66026 | 66509 | ** an AUTOINCREMENT table. */ |
| 66027 | 66510 | /* on the first attempt, simply do one more than previous */ |
| 66028 | - u.be.v = db->lastRowid; | |
| 66511 | + u.be.v = lastRowid; | |
| 66029 | 66512 | u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ |
| 66030 | 66513 | u.be.v++; /* ensure non-zero */ |
| 66031 | 66514 | u.be.cnt = 0; |
| 66032 | 66515 | while( ((rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v, |
| 66033 | 66516 | 0, &u.be.res))==SQLITE_OK) |
| @@ -66135,11 +66618,11 @@ | ||
| 66135 | 66618 | assert( pOp->opcode==OP_InsertInt ); |
| 66136 | 66619 | u.bf.iKey = pOp->p3; |
| 66137 | 66620 | } |
| 66138 | 66621 | |
| 66139 | 66622 | if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
| 66140 | - if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = u.bf.iKey; | |
| 66623 | + if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bf.iKey; | |
| 66141 | 66624 | if( u.bf.pData->flags & MEM_Null ){ |
| 66142 | 66625 | u.bf.pData->z = 0; |
| 66143 | 66626 | u.bf.pData->n = 0; |
| 66144 | 66627 | }else{ |
| 66145 | 66628 | assert( u.bf.pData->flags & (MEM_Blob|MEM_Str) ); |
| @@ -67261,11 +67744,11 @@ | ||
| 67261 | 67744 | assert( pc==u.by.pFrame->pc ); |
| 67262 | 67745 | } |
| 67263 | 67746 | |
| 67264 | 67747 | p->nFrame++; |
| 67265 | 67748 | u.by.pFrame->pParent = p->pFrame; |
| 67266 | - u.by.pFrame->lastRowid = db->lastRowid; | |
| 67749 | + u.by.pFrame->lastRowid = lastRowid; | |
| 67267 | 67750 | u.by.pFrame->nChange = p->nChange; |
| 67268 | 67751 | p->nChange = 0; |
| 67269 | 67752 | p->pFrame = u.by.pFrame; |
| 67270 | 67753 | p->aMem = aMem = &VdbeFrameMem(u.by.pFrame)[-1]; |
| 67271 | 67754 | p->nMem = u.by.pFrame->nChildMem; |
| @@ -68072,31 +68555,45 @@ | ||
| 68072 | 68555 | sqlite_int64 rowid; |
| 68073 | 68556 | Mem **apArg; |
| 68074 | 68557 | Mem *pX; |
| 68075 | 68558 | #endif /* local variables moved into u.cm */ |
| 68076 | 68559 | |
| 68560 | + assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback | |
| 68561 | + || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace | |
| 68562 | + ); | |
| 68077 | 68563 | u.cm.pVtab = pOp->p4.pVtab->pVtab; |
| 68078 | 68564 | u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule; |
| 68079 | 68565 | u.cm.nArg = pOp->p2; |
| 68080 | 68566 | assert( pOp->p4type==P4_VTAB ); |
| 68081 | 68567 | if( ALWAYS(u.cm.pModule->xUpdate) ){ |
| 68568 | + u8 vtabOnConflict = db->vtabOnConflict; | |
| 68082 | 68569 | u.cm.apArg = p->apArg; |
| 68083 | 68570 | u.cm.pX = &aMem[pOp->p3]; |
| 68084 | 68571 | for(u.cm.i=0; u.cm.i<u.cm.nArg; u.cm.i++){ |
| 68085 | 68572 | assert( memIsValid(u.cm.pX) ); |
| 68086 | 68573 | memAboutToChange(p, u.cm.pX); |
| 68087 | 68574 | sqlite3VdbeMemStoreType(u.cm.pX); |
| 68088 | 68575 | u.cm.apArg[u.cm.i] = u.cm.pX; |
| 68089 | 68576 | u.cm.pX++; |
| 68090 | 68577 | } |
| 68578 | + db->vtabOnConflict = pOp->p5; | |
| 68091 | 68579 | rc = u.cm.pModule->xUpdate(u.cm.pVtab, u.cm.nArg, u.cm.apArg, &u.cm.rowid); |
| 68580 | + db->vtabOnConflict = vtabOnConflict; | |
| 68092 | 68581 | importVtabErrMsg(p, u.cm.pVtab); |
| 68093 | 68582 | if( rc==SQLITE_OK && pOp->p1 ){ |
| 68094 | 68583 | assert( u.cm.nArg>1 && u.cm.apArg[0] && (u.cm.apArg[0]->flags&MEM_Null) ); |
| 68095 | - db->lastRowid = u.cm.rowid; | |
| 68584 | + db->lastRowid = lastRowid = u.cm.rowid; | |
| 68096 | 68585 | } |
| 68097 | - p->nChange++; | |
| 68586 | + if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ | |
| 68587 | + if( pOp->p5==OE_Ignore ){ | |
| 68588 | + rc = SQLITE_OK; | |
| 68589 | + }else{ | |
| 68590 | + p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); | |
| 68591 | + } | |
| 68592 | + }else{ | |
| 68593 | + p->nChange++; | |
| 68594 | + } | |
| 68098 | 68595 | } |
| 68099 | 68596 | break; |
| 68100 | 68597 | } |
| 68101 | 68598 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 68102 | 68599 | |
| @@ -68242,10 +68739,11 @@ | ||
| 68242 | 68739 | |
| 68243 | 68740 | /* This is the only way out of this procedure. We have to |
| 68244 | 68741 | ** release the mutexes on btrees that were acquired at the |
| 68245 | 68742 | ** top. */ |
| 68246 | 68743 | vdbe_return: |
| 68744 | + db->lastRowid = lastRowid; | |
| 68247 | 68745 | sqlite3VdbeLeave(p); |
| 68248 | 68746 | return rc; |
| 68249 | 68747 | |
| 68250 | 68748 | /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH |
| 68251 | 68749 | ** is encountered. |
| @@ -75970,12 +76468,16 @@ | ||
| 75970 | 76468 | int i; |
| 75971 | 76469 | int rc = 0; |
| 75972 | 76470 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 75973 | 76471 | const char *zName; |
| 75974 | 76472 | const char *zFile; |
| 76473 | + char *zPath = 0; | |
| 76474 | + char *zErr = 0; | |
| 76475 | + unsigned int flags; | |
| 75975 | 76476 | Db *aNew; |
| 75976 | 76477 | char *zErrDyn = 0; |
| 76478 | + sqlite3_vfs *pVfs; | |
| 75977 | 76479 | |
| 75978 | 76480 | UNUSED_PARAMETER(NotUsed); |
| 75979 | 76481 | |
| 75980 | 76482 | zFile = (const char *)sqlite3_value_text(argv[0]); |
| 75981 | 76483 | zName = (const char *)sqlite3_value_text(argv[1]); |
| @@ -76024,12 +76526,22 @@ | ||
| 76024 | 76526 | |
| 76025 | 76527 | /* Open the database file. If the btree is successfully opened, use |
| 76026 | 76528 | ** it to obtain the database schema. At this point the schema may |
| 76027 | 76529 | ** or may not be initialised. |
| 76028 | 76530 | */ |
| 76029 | - rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0, | |
| 76030 | - db->openFlags | SQLITE_OPEN_MAIN_DB); | |
| 76531 | + flags = db->openFlags; | |
| 76532 | + rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); | |
| 76533 | + if( rc!=SQLITE_OK ){ | |
| 76534 | + if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; | |
| 76535 | + sqlite3_result_error(context, zErr, -1); | |
| 76536 | + sqlite3_free(zErr); | |
| 76537 | + return; | |
| 76538 | + } | |
| 76539 | + assert( pVfs ); | |
| 76540 | + flags |= SQLITE_OPEN_MAIN_DB; | |
| 76541 | + rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); | |
| 76542 | + sqlite3_free( zPath ); | |
| 76031 | 76543 | db->nDb++; |
| 76032 | 76544 | if( rc==SQLITE_CONSTRAINT ){ |
| 76033 | 76545 | rc = SQLITE_ERROR; |
| 76034 | 76546 | zErrDyn = sqlite3MPrintf(db, "database is already attached"); |
| 76035 | 76547 | }else if( rc==SQLITE_OK ){ |
| @@ -80139,11 +80651,11 @@ | ||
| 80139 | 80651 | SQLITE_OPEN_CREATE | |
| 80140 | 80652 | SQLITE_OPEN_EXCLUSIVE | |
| 80141 | 80653 | SQLITE_OPEN_DELETEONCLOSE | |
| 80142 | 80654 | SQLITE_OPEN_TEMP_DB; |
| 80143 | 80655 | |
| 80144 | - rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags); | |
| 80656 | + rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags); | |
| 80145 | 80657 | if( rc!=SQLITE_OK ){ |
| 80146 | 80658 | sqlite3ErrorMsg(pParse, "unable to open a temporary database " |
| 80147 | 80659 | "file for storing temporary tables"); |
| 80148 | 80660 | pParse->rc = rc; |
| 80149 | 80661 | return 1; |
| @@ -82329,10 +82841,25 @@ | ||
| 82329 | 82841 | UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| 82330 | 82842 | /* IMP: R-24470-31136 This function is an SQL wrapper around the |
| 82331 | 82843 | ** sqlite3_sourceid() C interface. */ |
| 82332 | 82844 | sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); |
| 82333 | 82845 | } |
| 82846 | + | |
| 82847 | +/* | |
| 82848 | +** Implementation of the sqlite_log() function. This is a wrapper around | |
| 82849 | +** sqlite3_log(). The return value is NULL. The function exists purely for | |
| 82850 | +** its side-effects. | |
| 82851 | +*/ | |
| 82852 | +static void errlogFunc( | |
| 82853 | + sqlite3_context *context, | |
| 82854 | + int argc, | |
| 82855 | + sqlite3_value **argv | |
| 82856 | +){ | |
| 82857 | + UNUSED_PARAMETER(argc); | |
| 82858 | + UNUSED_PARAMETER(context); | |
| 82859 | + sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); | |
| 82860 | +} | |
| 82334 | 82861 | |
| 82335 | 82862 | /* |
| 82336 | 82863 | ** Implementation of the sqlite_compileoption_used() function. |
| 82337 | 82864 | ** The result is an integer that identifies if the compiler option |
| 82338 | 82865 | ** was used to build SQLite. |
| @@ -83097,10 +83624,11 @@ | ||
| 83097 | 83624 | FUNCTION(random, 0, 0, 0, randomFunc ), |
| 83098 | 83625 | FUNCTION(randomblob, 1, 0, 0, randomBlob ), |
| 83099 | 83626 | FUNCTION(nullif, 2, 0, 1, nullifFunc ), |
| 83100 | 83627 | FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), |
| 83101 | 83628 | FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), |
| 83629 | + FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), | |
| 83102 | 83630 | #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| 83103 | 83631 | FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), |
| 83104 | 83632 | FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), |
| 83105 | 83633 | #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
| 83106 | 83634 | FUNCTION(quote, 1, 0, 0, quoteFunc ), |
| @@ -85309,10 +85837,11 @@ | ||
| 85309 | 85837 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 85310 | 85838 | if( IsVirtual(pTab) ){ |
| 85311 | 85839 | const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); |
| 85312 | 85840 | sqlite3VtabMakeWritable(pParse, pTab); |
| 85313 | 85841 | sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); |
| 85842 | + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); | |
| 85314 | 85843 | sqlite3MayAbort(pParse); |
| 85315 | 85844 | }else |
| 85316 | 85845 | #endif |
| 85317 | 85846 | { |
| 85318 | 85847 | int isReplace; /* Set to true if constraints may cause a replace */ |
| @@ -86073,10 +86602,22 @@ | ||
| 86073 | 86602 | } |
| 86074 | 86603 | #ifndef SQLITE_OMIT_CHECK |
| 86075 | 86604 | if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){ |
| 86076 | 86605 | return 0; /* Tables have different CHECK constraints. Ticket #2252 */ |
| 86077 | 86606 | } |
| 86607 | +#endif | |
| 86608 | +#ifndef SQLITE_OMIT_FOREIGN_KEY | |
| 86609 | + /* Disallow the transfer optimization if the destination table constains | |
| 86610 | + ** any foreign key constraints. This is more restrictive than necessary. | |
| 86611 | + ** But the main beneficiary of the transfer optimization is the VACUUM | |
| 86612 | + ** command, and the VACUUM command disables foreign key constraints. So | |
| 86613 | + ** the extra complication to make this rule less restrictive is probably | |
| 86614 | + ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] | |
| 86615 | + */ | |
| 86616 | + if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ | |
| 86617 | + return 0; | |
| 86618 | + } | |
| 86078 | 86619 | #endif |
| 86079 | 86620 | |
| 86080 | 86621 | /* If we get this far, it means either: |
| 86081 | 86622 | ** |
| 86082 | 86623 | ** * We can always do the transfer if the table contains an |
| @@ -87442,11 +87983,11 @@ | ||
| 87442 | 87983 | } |
| 87443 | 87984 | |
| 87444 | 87985 | /* |
| 87445 | 87986 | ** Interpret the given string as a boolean value. |
| 87446 | 87987 | */ |
| 87447 | -static u8 getBoolean(const char *z){ | |
| 87988 | +SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z){ | |
| 87448 | 87989 | return getSafetyLevel(z)&1; |
| 87449 | 87990 | } |
| 87450 | 87991 | |
| 87451 | 87992 | /* |
| 87452 | 87993 | ** Interpret the given string as a locking mode value. |
| @@ -87612,11 +88153,11 @@ | ||
| 87612 | 88153 | /* Foreign key support may not be enabled or disabled while not |
| 87613 | 88154 | ** in auto-commit mode. */ |
| 87614 | 88155 | mask &= ~(SQLITE_ForeignKeys); |
| 87615 | 88156 | } |
| 87616 | 88157 | |
| 87617 | - if( getBoolean(zRight) ){ | |
| 88158 | + if( sqlite3GetBoolean(zRight) ){ | |
| 87618 | 88159 | db->flags |= mask; |
| 87619 | 88160 | }else{ |
| 87620 | 88161 | db->flags &= ~mask; |
| 87621 | 88162 | } |
| 87622 | 88163 | |
| @@ -87826,11 +88367,11 @@ | ||
| 87826 | 88367 | if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){ |
| 87827 | 88368 | Btree *pBt = pDb->pBt; |
| 87828 | 88369 | int b = -1; |
| 87829 | 88370 | assert( pBt!=0 ); |
| 87830 | 88371 | if( zRight ){ |
| 87831 | - b = getBoolean(zRight); | |
| 88372 | + b = sqlite3GetBoolean(zRight); | |
| 87832 | 88373 | } |
| 87833 | 88374 | if( pId2->n==0 && b>=0 ){ |
| 87834 | 88375 | int ii; |
| 87835 | 88376 | for(ii=0; ii<db->nDb; ii++){ |
| 87836 | 88377 | sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b); |
| @@ -88426,11 +88967,11 @@ | ||
| 88426 | 88967 | #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ |
| 88427 | 88968 | |
| 88428 | 88969 | #ifndef NDEBUG |
| 88429 | 88970 | if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ |
| 88430 | 88971 | if( zRight ){ |
| 88431 | - if( getBoolean(zRight) ){ | |
| 88972 | + if( sqlite3GetBoolean(zRight) ){ | |
| 88432 | 88973 | sqlite3ParserTrace(stderr, "parser: "); |
| 88433 | 88974 | }else{ |
| 88434 | 88975 | sqlite3ParserTrace(0, 0); |
| 88435 | 88976 | } |
| 88436 | 88977 | } |
| @@ -88440,11 +88981,11 @@ | ||
| 88440 | 88981 | /* Reinstall the LIKE and GLOB functions. The variant of LIKE |
| 88441 | 88982 | ** used will be case sensitive or not depending on the RHS. |
| 88442 | 88983 | */ |
| 88443 | 88984 | if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ |
| 88444 | 88985 | if( zRight ){ |
| 88445 | - sqlite3RegisterLikeFunctions(db, getBoolean(zRight)); | |
| 88986 | + sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight)); | |
| 88446 | 88987 | } |
| 88447 | 88988 | }else |
| 88448 | 88989 | |
| 88449 | 88990 | #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX |
| 88450 | 88991 | # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 |
| @@ -94017,16 +94558,18 @@ | ||
| 94017 | 94558 | ** does, then we can assume that it consumes less space on disk and |
| 94018 | 94559 | ** will therefore be cheaper to scan to determine the query result. |
| 94019 | 94560 | ** In this case set iRoot to the root page number of the index b-tree |
| 94020 | 94561 | ** and pKeyInfo to the KeyInfo structure required to navigate the |
| 94021 | 94562 | ** index. |
| 94563 | + ** | |
| 94564 | + ** (2011-04-15) Do not do a full scan of an unordered index. | |
| 94022 | 94565 | ** |
| 94023 | 94566 | ** In practice the KeyInfo structure will not be used. It is only |
| 94024 | 94567 | ** passed to keep OP_OpenRead happy. |
| 94025 | 94568 | */ |
| 94026 | 94569 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 94027 | - if( !pBest || pIdx->nColumn<pBest->nColumn ){ | |
| 94570 | + if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){ | |
| 94028 | 94571 | pBest = pIdx; |
| 94029 | 94572 | } |
| 94030 | 94573 | } |
| 94031 | 94574 | if( pBest && pBest->nColumn<pTab->nCol ){ |
| 94032 | 94575 | iRoot = pBest->tnum; |
| @@ -95579,11 +96122,12 @@ | ||
| 95579 | 96122 | SrcList *pSrc, /* The virtual table to be modified */ |
| 95580 | 96123 | Table *pTab, /* The virtual table */ |
| 95581 | 96124 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 95582 | 96125 | Expr *pRowidExpr, /* Expression used to recompute the rowid */ |
| 95583 | 96126 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 95584 | - Expr *pWhere /* WHERE clause of the UPDATE statement */ | |
| 96127 | + Expr *pWhere, /* WHERE clause of the UPDATE statement */ | |
| 96128 | + int onError /* ON CONFLICT strategy */ | |
| 95585 | 96129 | ); |
| 95586 | 96130 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 95587 | 96131 | |
| 95588 | 96132 | /* |
| 95589 | 96133 | ** The most recently coded instruction was an OP_Column to retrieve the |
| @@ -95823,11 +96367,11 @@ | ||
| 95823 | 96367 | |
| 95824 | 96368 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 95825 | 96369 | /* Virtual tables must be handled separately */ |
| 95826 | 96370 | if( IsVirtual(pTab) ){ |
| 95827 | 96371 | updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, |
| 95828 | - pWhere); | |
| 96372 | + pWhere, onError); | |
| 95829 | 96373 | pWhere = 0; |
| 95830 | 96374 | pTabList = 0; |
| 95831 | 96375 | goto update_cleanup; |
| 95832 | 96376 | } |
| 95833 | 96377 | #endif |
| @@ -96153,11 +96697,12 @@ | ||
| 96153 | 96697 | SrcList *pSrc, /* The virtual table to be modified */ |
| 96154 | 96698 | Table *pTab, /* The virtual table */ |
| 96155 | 96699 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 96156 | 96700 | Expr *pRowid, /* Expression used to recompute the rowid */ |
| 96157 | 96701 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 96158 | - Expr *pWhere /* WHERE clause of the UPDATE statement */ | |
| 96702 | + Expr *pWhere, /* WHERE clause of the UPDATE statement */ | |
| 96703 | + int onError /* ON CONFLICT strategy */ | |
| 96159 | 96704 | ){ |
| 96160 | 96705 | Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ |
| 96161 | 96706 | ExprList *pEList = 0; /* The result set of the SELECT statement */ |
| 96162 | 96707 | Select *pSelect = 0; /* The SELECT statement */ |
| 96163 | 96708 | Expr *pExpr; /* Temporary expression */ |
| @@ -96210,10 +96755,11 @@ | ||
| 96210 | 96755 | for(i=0; i<pTab->nCol; i++){ |
| 96211 | 96756 | sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); |
| 96212 | 96757 | } |
| 96213 | 96758 | sqlite3VtabMakeWritable(pParse, pTab); |
| 96214 | 96759 | sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); |
| 96760 | + sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); | |
| 96215 | 96761 | sqlite3MayAbort(pParse); |
| 96216 | 96762 | sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); |
| 96217 | 96763 | sqlite3VdbeJumpHere(v, addr); |
| 96218 | 96764 | sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); |
| 96219 | 96765 | |
| @@ -96583,10 +97129,22 @@ | ||
| 96583 | 97129 | ************************************************************************* |
| 96584 | 97130 | ** This file contains code used to help implement virtual tables. |
| 96585 | 97131 | */ |
| 96586 | 97132 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 96587 | 97133 | |
| 97134 | +/* | |
| 97135 | +** Before a virtual table xCreate() or xConnect() method is invoked, the | |
| 97136 | +** sqlite3.pVtabCtx member variable is set to point to an instance of | |
| 97137 | +** this struct allocated on the stack. It is used by the implementation of | |
| 97138 | +** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which | |
| 97139 | +** are invoked only from within xCreate and xConnect methods. | |
| 97140 | +*/ | |
| 97141 | +struct VtabCtx { | |
| 97142 | + Table *pTab; | |
| 97143 | + VTable *pVTable; | |
| 97144 | +}; | |
| 97145 | + | |
| 96588 | 97146 | /* |
| 96589 | 97147 | ** The actual function that does the work of creating a new module. |
| 96590 | 97148 | ** This function implements the sqlite3_create_module() and |
| 96591 | 97149 | ** sqlite3_create_module_v2() interfaces. |
| 96592 | 97150 | */ |
| @@ -96611,17 +97169,17 @@ | ||
| 96611 | 97169 | pMod->pModule = pModule; |
| 96612 | 97170 | pMod->pAux = pAux; |
| 96613 | 97171 | pMod->xDestroy = xDestroy; |
| 96614 | 97172 | pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); |
| 96615 | 97173 | if( pDel && pDel->xDestroy ){ |
| 97174 | + sqlite3ResetInternalSchema(db, -1); | |
| 96616 | 97175 | pDel->xDestroy(pDel->pAux); |
| 96617 | 97176 | } |
| 96618 | 97177 | sqlite3DbFree(db, pDel); |
| 96619 | 97178 | if( pDel==pMod ){ |
| 96620 | 97179 | db->mallocFailed = 1; |
| 96621 | 97180 | } |
| 96622 | - sqlite3ResetInternalSchema(db, -1); | |
| 96623 | 97181 | }else if( xDestroy ){ |
| 96624 | 97182 | xDestroy(pAux); |
| 96625 | 97183 | } |
| 96626 | 97184 | rc = sqlite3ApiExit(db, SQLITE_OK); |
| 96627 | 97185 | sqlite3_mutex_leave(db->mutex); |
| @@ -97003,10 +97561,11 @@ | ||
| 97003 | 97561 | Table *pTab, |
| 97004 | 97562 | Module *pMod, |
| 97005 | 97563 | int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), |
| 97006 | 97564 | char **pzErr |
| 97007 | 97565 | ){ |
| 97566 | + VtabCtx sCtx; | |
| 97008 | 97567 | VTable *pVTable; |
| 97009 | 97568 | int rc; |
| 97010 | 97569 | const char *const*azArg = (const char *const*)pTab->azModuleArg; |
| 97011 | 97570 | int nArg = pTab->nModuleArg; |
| 97012 | 97571 | char *zErr = 0; |
| @@ -97022,16 +97581,18 @@ | ||
| 97022 | 97581 | return SQLITE_NOMEM; |
| 97023 | 97582 | } |
| 97024 | 97583 | pVTable->db = db; |
| 97025 | 97584 | pVTable->pMod = pMod; |
| 97026 | 97585 | |
| 97027 | - assert( !db->pVTab ); | |
| 97586 | + /* Invoke the virtual table constructor */ | |
| 97587 | + assert( &db->pVtabCtx ); | |
| 97028 | 97588 | assert( xConstruct ); |
| 97029 | - db->pVTab = pTab; | |
| 97030 | - | |
| 97031 | - /* Invoke the virtual table constructor */ | |
| 97589 | + sCtx.pTab = pTab; | |
| 97590 | + sCtx.pVTable = pVTable; | |
| 97591 | + db->pVtabCtx = &sCtx; | |
| 97032 | 97592 | rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); |
| 97593 | + db->pVtabCtx = 0; | |
| 97033 | 97594 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 97034 | 97595 | |
| 97035 | 97596 | if( SQLITE_OK!=rc ){ |
| 97036 | 97597 | if( zErr==0 ){ |
| 97037 | 97598 | *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); |
| @@ -97043,11 +97604,11 @@ | ||
| 97043 | 97604 | }else if( ALWAYS(pVTable->pVtab) ){ |
| 97044 | 97605 | /* Justification of ALWAYS(): A correct vtab constructor must allocate |
| 97045 | 97606 | ** the sqlite3_vtab object if successful. */ |
| 97046 | 97607 | pVTable->pVtab->pModule = pMod->pModule; |
| 97047 | 97608 | pVTable->nRef = 1; |
| 97048 | - if( db->pVTab ){ | |
| 97609 | + if( sCtx.pTab ){ | |
| 97049 | 97610 | const char *zFormat = "vtable constructor did not declare schema: %s"; |
| 97050 | 97611 | *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); |
| 97051 | 97612 | sqlite3VtabUnlock(pVTable); |
| 97052 | 97613 | rc = SQLITE_ERROR; |
| 97053 | 97614 | }else{ |
| @@ -97091,11 +97652,10 @@ | ||
| 97091 | 97652 | } |
| 97092 | 97653 | } |
| 97093 | 97654 | } |
| 97094 | 97655 | |
| 97095 | 97656 | sqlite3DbFree(db, zModuleName); |
| 97096 | - db->pVTab = 0; | |
| 97097 | 97657 | return rc; |
| 97098 | 97658 | } |
| 97099 | 97659 | |
| 97100 | 97660 | /* |
| 97101 | 97661 | ** This function is invoked by the parser to call the xConnect() method |
| @@ -97211,12 +97771,11 @@ | ||
| 97211 | 97771 | int rc = SQLITE_OK; |
| 97212 | 97772 | Table *pTab; |
| 97213 | 97773 | char *zErr = 0; |
| 97214 | 97774 | |
| 97215 | 97775 | sqlite3_mutex_enter(db->mutex); |
| 97216 | - pTab = db->pVTab; | |
| 97217 | - if( !pTab ){ | |
| 97776 | + if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ | |
| 97218 | 97777 | sqlite3Error(db, SQLITE_MISUSE, 0); |
| 97219 | 97778 | sqlite3_mutex_leave(db->mutex); |
| 97220 | 97779 | return SQLITE_MISUSE_BKPT; |
| 97221 | 97780 | } |
| 97222 | 97781 | assert( (pTab->tabFlags & TF_Virtual)!=0 ); |
| @@ -97239,11 +97798,11 @@ | ||
| 97239 | 97798 | pTab->aCol = pParse->pNewTable->aCol; |
| 97240 | 97799 | pTab->nCol = pParse->pNewTable->nCol; |
| 97241 | 97800 | pParse->pNewTable->nCol = 0; |
| 97242 | 97801 | pParse->pNewTable->aCol = 0; |
| 97243 | 97802 | } |
| 97244 | - db->pVTab = 0; | |
| 97803 | + db->pVtabCtx->pTab = 0; | |
| 97245 | 97804 | }else{ |
| 97246 | 97805 | sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); |
| 97247 | 97806 | sqlite3DbFree(db, zErr); |
| 97248 | 97807 | rc = SQLITE_ERROR; |
| 97249 | 97808 | } |
| @@ -97391,11 +97950,10 @@ | ||
| 97391 | 97950 | pModule = pVTab->pVtab->pModule; |
| 97392 | 97951 | |
| 97393 | 97952 | if( pModule->xBegin ){ |
| 97394 | 97953 | int i; |
| 97395 | 97954 | |
| 97396 | - | |
| 97397 | 97955 | /* If pVtab is already in the aVTrans array, return early */ |
| 97398 | 97956 | for(i=0; i<db->nVTrans; i++){ |
| 97399 | 97957 | if( db->aVTrans[i]==pVTab ){ |
| 97400 | 97958 | return SQLITE_OK; |
| 97401 | 97959 | } |
| @@ -97404,10 +97962,53 @@ | ||
| 97404 | 97962 | /* Invoke the xBegin method */ |
| 97405 | 97963 | rc = pModule->xBegin(pVTab->pVtab); |
| 97406 | 97964 | if( rc==SQLITE_OK ){ |
| 97407 | 97965 | rc = addToVTrans(db, pVTab); |
| 97408 | 97966 | } |
| 97967 | + } | |
| 97968 | + return rc; | |
| 97969 | +} | |
| 97970 | + | |
| 97971 | +/* | |
| 97972 | +** Invoke either the xSavepoint, xRollbackTo or xRelease method of all | |
| 97973 | +** virtual tables that currently have an open transaction. Pass iSavepoint | |
| 97974 | +** as the second argument to the virtual table method invoked. | |
| 97975 | +** | |
| 97976 | +** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is | |
| 97977 | +** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is | |
| 97978 | +** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with | |
| 97979 | +** an open transaction is invoked. | |
| 97980 | +** | |
| 97981 | +** If any virtual table method returns an error code other than SQLITE_OK, | |
| 97982 | +** processing is abandoned and the error returned to the caller of this | |
| 97983 | +** function immediately. If all calls to virtual table methods are successful, | |
| 97984 | +** SQLITE_OK is returned. | |
| 97985 | +*/ | |
| 97986 | +SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ | |
| 97987 | + int rc = SQLITE_OK; | |
| 97988 | + | |
| 97989 | + assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); | |
| 97990 | + if( db->aVTrans ){ | |
| 97991 | + int i; | |
| 97992 | + for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ | |
| 97993 | + const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; | |
| 97994 | + if( pMod->iVersion>=2 ){ | |
| 97995 | + int (*xMethod)(sqlite3_vtab *, int); | |
| 97996 | + switch( op ){ | |
| 97997 | + case SAVEPOINT_BEGIN: | |
| 97998 | + xMethod = pMod->xSavepoint; | |
| 97999 | + break; | |
| 98000 | + case SAVEPOINT_ROLLBACK: | |
| 98001 | + xMethod = pMod->xRollbackTo; | |
| 98002 | + break; | |
| 98003 | + default: | |
| 98004 | + xMethod = pMod->xRelease; | |
| 98005 | + break; | |
| 98006 | + } | |
| 98007 | + if( xMethod ) rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint); | |
| 98008 | + } | |
| 98009 | + } | |
| 97409 | 98010 | } |
| 97410 | 98011 | return rc; |
| 97411 | 98012 | } |
| 97412 | 98013 | |
| 97413 | 98014 | /* |
| @@ -97505,10 +98106,61 @@ | ||
| 97505 | 98106 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; |
| 97506 | 98107 | }else{ |
| 97507 | 98108 | pToplevel->db->mallocFailed = 1; |
| 97508 | 98109 | } |
| 97509 | 98110 | } |
| 98111 | + | |
| 98112 | +/* | |
| 98113 | +** Return the ON CONFLICT resolution mode in effect for the virtual | |
| 98114 | +** table update operation currently in progress. | |
| 98115 | +** | |
| 98116 | +** The results of this routine are undefined unless it is called from | |
| 98117 | +** within an xUpdate method. | |
| 98118 | +*/ | |
| 98119 | +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ | |
| 98120 | + static const unsigned char aMap[] = { | |
| 98121 | + SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE | |
| 98122 | + }; | |
| 98123 | + assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); | |
| 98124 | + assert( OE_Ignore==4 && OE_Replace==5 ); | |
| 98125 | + assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); | |
| 98126 | + return (int)aMap[db->vtabOnConflict-1]; | |
| 98127 | +} | |
| 98128 | + | |
| 98129 | +/* | |
| 98130 | +** Call from within the xCreate() or xConnect() methods to provide | |
| 98131 | +** the SQLite core with additional information about the behavior | |
| 98132 | +** of the virtual table being implemented. | |
| 98133 | +*/ | |
| 98134 | +SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ | |
| 98135 | + va_list ap; | |
| 98136 | + int rc = SQLITE_OK; | |
| 98137 | + | |
| 98138 | + sqlite3_mutex_enter(db->mutex); | |
| 98139 | + | |
| 98140 | + va_start(ap, op); | |
| 98141 | + switch( op ){ | |
| 98142 | + case SQLITE_VTAB_CONSTRAINT_SUPPORT: { | |
| 98143 | + VtabCtx *p = db->pVtabCtx; | |
| 98144 | + if( !p ){ | |
| 98145 | + rc = SQLITE_MISUSE_BKPT; | |
| 98146 | + }else{ | |
| 98147 | + assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); | |
| 98148 | + p->pVTable->bConstraint = (u8)va_arg(ap, int); | |
| 98149 | + } | |
| 98150 | + break; | |
| 98151 | + } | |
| 98152 | + default: | |
| 98153 | + rc = SQLITE_MISUSE_BKPT; | |
| 98154 | + break; | |
| 98155 | + } | |
| 98156 | + va_end(ap); | |
| 98157 | + | |
| 98158 | + if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0); | |
| 98159 | + sqlite3_mutex_leave(db->mutex); | |
| 98160 | + return rc; | |
| 98161 | +} | |
| 97510 | 98162 | |
| 97511 | 98163 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 97512 | 98164 | |
| 97513 | 98165 | /************** End of vtab.c ************************************************/ |
| 97514 | 98166 | /************** Begin file where.c *******************************************/ |
| @@ -107527,10 +108179,15 @@ | ||
| 107527 | 108179 | typedef void(*LOGFUNC_t)(void*,int,const char*); |
| 107528 | 108180 | sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); |
| 107529 | 108181 | sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); |
| 107530 | 108182 | break; |
| 107531 | 108183 | } |
| 108184 | + | |
| 108185 | + case SQLITE_CONFIG_URI: { | |
| 108186 | + sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); | |
| 108187 | + break; | |
| 108188 | + } | |
| 107532 | 108189 | |
| 107533 | 108190 | default: { |
| 107534 | 108191 | rc = SQLITE_ERROR; |
| 107535 | 108192 | break; |
| 107536 | 108193 | } |
| @@ -108886,25 +109543,257 @@ | ||
| 108886 | 109543 | } |
| 108887 | 109544 | db->aLimit[limitId] = newLimit; |
| 108888 | 109545 | } |
| 108889 | 109546 | return oldLimit; /* IMP: R-53341-35419 */ |
| 108890 | 109547 | } |
| 109548 | + | |
| 109549 | +/* | |
| 109550 | +** This function is used to parse both URIs and non-URI filenames passed by the | |
| 109551 | +** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database | |
| 109552 | +** URIs specified as part of ATTACH statements. | |
| 109553 | +** | |
| 109554 | +** The first argument to this function is the name of the VFS to use (or | |
| 109555 | +** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" | |
| 109556 | +** query parameter. The second argument contains the URI (or non-URI filename) | |
| 109557 | +** itself. When this function is called the *pFlags variable should contain | |
| 109558 | +** the default flags to open the database handle with. The value stored in | |
| 109559 | +** *pFlags may be updated before returning if the URI filename contains | |
| 109560 | +** "cache=xxx" or "mode=xxx" query parameters. | |
| 109561 | +** | |
| 109562 | +** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to | |
| 109563 | +** the VFS that should be used to open the database file. *pzFile is set to | |
| 109564 | +** point to a buffer containing the name of the file to open. It is the | |
| 109565 | +** responsibility of the caller to eventually call sqlite3_free() to release | |
| 109566 | +** this buffer. | |
| 109567 | +** | |
| 109568 | +** If an error occurs, then an SQLite error code is returned and *pzErrMsg | |
| 109569 | +** may be set to point to a buffer containing an English language error | |
| 109570 | +** message. It is the responsibility of the caller to eventually release | |
| 109571 | +** this buffer by calling sqlite3_free(). | |
| 109572 | +*/ | |
| 109573 | +SQLITE_PRIVATE int sqlite3ParseUri( | |
| 109574 | + const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ | |
| 109575 | + const char *zUri, /* Nul-terminated URI to parse */ | |
| 109576 | + unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ | |
| 109577 | + sqlite3_vfs **ppVfs, /* OUT: VFS to use */ | |
| 109578 | + char **pzFile, /* OUT: Filename component of URI */ | |
| 109579 | + char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ | |
| 109580 | +){ | |
| 109581 | + int rc = SQLITE_OK; | |
| 109582 | + unsigned int flags = *pFlags; | |
| 109583 | + const char *zVfs = zDefaultVfs; | |
| 109584 | + char *zFile; | |
| 109585 | + char c; | |
| 109586 | + int nUri = sqlite3Strlen30(zUri); | |
| 109587 | + | |
| 109588 | + assert( *pzErrMsg==0 ); | |
| 109589 | + | |
| 109590 | + if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) | |
| 109591 | + && nUri>=5 && memcmp(zUri, "file:", 5)==0 | |
| 109592 | + ){ | |
| 109593 | + char *zOpt; | |
| 109594 | + int eState; /* Parser state when parsing URI */ | |
| 109595 | + int iIn; /* Input character index */ | |
| 109596 | + int iOut = 0; /* Output character index */ | |
| 109597 | + int nByte = nUri+2; /* Bytes of space to allocate */ | |
| 109598 | + | |
| 109599 | + /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen | |
| 109600 | + ** method that there may be extra parameters following the file-name. */ | |
| 109601 | + flags |= SQLITE_OPEN_URI; | |
| 109602 | + | |
| 109603 | + for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); | |
| 109604 | + zFile = sqlite3_malloc(nByte); | |
| 109605 | + if( !zFile ) return SQLITE_NOMEM; | |
| 109606 | + | |
| 109607 | + /* Discard the scheme and authority segments of the URI. */ | |
| 109608 | + if( zUri[5]=='/' && zUri[6]=='/' ){ | |
| 109609 | + iIn = 7; | |
| 109610 | + while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; | |
| 109611 | + | |
| 109612 | + if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ | |
| 109613 | + *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s", | |
| 109614 | + iIn-7, &zUri[7]); | |
| 109615 | + rc = SQLITE_ERROR; | |
| 109616 | + goto parse_uri_out; | |
| 109617 | + } | |
| 109618 | + }else{ | |
| 109619 | + iIn = 5; | |
| 109620 | + } | |
| 109621 | + | |
| 109622 | + /* Copy the filename and any query parameters into the zFile buffer. | |
| 109623 | + ** Decode %HH escape codes along the way. | |
| 109624 | + ** | |
| 109625 | + ** Within this loop, variable eState may be set to 0, 1 or 2, depending | |
| 109626 | + ** on the parsing context. As follows: | |
| 109627 | + ** | |
| 109628 | + ** 0: Parsing file-name. | |
| 109629 | + ** 1: Parsing name section of a name=value query parameter. | |
| 109630 | + ** 2: Parsing value section of a name=value query parameter. | |
| 109631 | + */ | |
| 109632 | + eState = 0; | |
| 109633 | + while( (c = zUri[iIn])!=0 && c!='#' ){ | |
| 109634 | + iIn++; | |
| 109635 | + if( c=='%' | |
| 109636 | + && sqlite3Isxdigit(zUri[iIn]) | |
| 109637 | + && sqlite3Isxdigit(zUri[iIn+1]) | |
| 109638 | + ){ | |
| 109639 | + int octet = (sqlite3HexToInt(zUri[iIn++]) << 4); | |
| 109640 | + octet += sqlite3HexToInt(zUri[iIn++]); | |
| 109641 | + | |
| 109642 | + assert( octet>=0 && octet<256 ); | |
| 109643 | + if( octet==0 ){ | |
| 109644 | + /* This branch is taken when "%00" appears within the URI. In this | |
| 109645 | + ** case we ignore all text in the remainder of the path, name or | |
| 109646 | + ** value currently being parsed. So ignore the current character | |
| 109647 | + ** and skip to the next "?", "=" or "&", as appropriate. */ | |
| 109648 | + while( (c = zUri[iIn])!=0 && c!='#' | |
| 109649 | + && (eState!=0 || c!='?') | |
| 109650 | + && (eState!=1 || (c!='=' && c!='&')) | |
| 109651 | + && (eState!=2 || c!='&') | |
| 109652 | + ){ | |
| 109653 | + iIn++; | |
| 109654 | + } | |
| 109655 | + continue; | |
| 109656 | + } | |
| 109657 | + c = octet; | |
| 109658 | + }else if( eState==1 && (c=='&' || c=='=') ){ | |
| 109659 | + if( zFile[iOut-1]==0 ){ | |
| 109660 | + /* An empty option name. Ignore this option altogether. */ | |
| 109661 | + while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; | |
| 109662 | + continue; | |
| 109663 | + } | |
| 109664 | + if( c=='&' ){ | |
| 109665 | + zFile[iOut++] = '\0'; | |
| 109666 | + }else{ | |
| 109667 | + eState = 2; | |
| 109668 | + } | |
| 109669 | + c = 0; | |
| 109670 | + }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ | |
| 109671 | + c = 0; | |
| 109672 | + eState = 1; | |
| 109673 | + } | |
| 109674 | + zFile[iOut++] = c; | |
| 109675 | + } | |
| 109676 | + if( eState==1 ) zFile[iOut++] = '\0'; | |
| 109677 | + zFile[iOut++] = '\0'; | |
| 109678 | + zFile[iOut++] = '\0'; | |
| 109679 | + | |
| 109680 | + /* Check if there were any options specified that should be interpreted | |
| 109681 | + ** here. Options that are interpreted here include "vfs" and those that | |
| 109682 | + ** correspond to flags that may be passed to the sqlite3_open_v2() | |
| 109683 | + ** method. */ | |
| 109684 | + zOpt = &zFile[sqlite3Strlen30(zFile)+1]; | |
| 109685 | + while( zOpt[0] ){ | |
| 109686 | + int nOpt = sqlite3Strlen30(zOpt); | |
| 109687 | + char *zVal = &zOpt[nOpt+1]; | |
| 109688 | + int nVal = sqlite3Strlen30(zVal); | |
| 109689 | + | |
| 109690 | + if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ | |
| 109691 | + zVfs = zVal; | |
| 109692 | + }else{ | |
| 109693 | + struct OpenMode { | |
| 109694 | + const char *z; | |
| 109695 | + int mode; | |
| 109696 | + } *aMode = 0; | |
| 109697 | + char *zModeType; | |
| 109698 | + int mask; | |
| 109699 | + int limit; | |
| 109700 | + | |
| 109701 | + if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ | |
| 109702 | + static struct OpenMode aCacheMode[] = { | |
| 109703 | + { "shared", SQLITE_OPEN_SHAREDCACHE }, | |
| 109704 | + { "private", SQLITE_OPEN_PRIVATECACHE }, | |
| 109705 | + { 0, 0 } | |
| 109706 | + }; | |
| 109707 | + | |
| 109708 | + mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; | |
| 109709 | + aMode = aCacheMode; | |
| 109710 | + limit = mask; | |
| 109711 | + zModeType = "cache"; | |
| 109712 | + } | |
| 109713 | + if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ | |
| 109714 | + static struct OpenMode aOpenMode[] = { | |
| 109715 | + { "ro", SQLITE_OPEN_READONLY }, | |
| 109716 | + { "rw", SQLITE_OPEN_READWRITE }, | |
| 109717 | + { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, | |
| 109718 | + { 0, 0 } | |
| 109719 | + }; | |
| 109720 | + | |
| 109721 | + mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; | |
| 109722 | + aMode = aOpenMode; | |
| 109723 | + limit = mask & flags; | |
| 109724 | + zModeType = "access"; | |
| 109725 | + } | |
| 109726 | + | |
| 109727 | + if( aMode ){ | |
| 109728 | + int i; | |
| 109729 | + int mode = 0; | |
| 109730 | + for(i=0; aMode[i].z; i++){ | |
| 109731 | + const char *z = aMode[i].z; | |
| 109732 | + if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ | |
| 109733 | + mode = aMode[i].mode; | |
| 109734 | + break; | |
| 109735 | + } | |
| 109736 | + } | |
| 109737 | + if( mode==0 ){ | |
| 109738 | + *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); | |
| 109739 | + rc = SQLITE_ERROR; | |
| 109740 | + goto parse_uri_out; | |
| 109741 | + } | |
| 109742 | + if( mode>limit ){ | |
| 109743 | + *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", | |
| 109744 | + zModeType, zVal); | |
| 109745 | + rc = SQLITE_PERM; | |
| 109746 | + goto parse_uri_out; | |
| 109747 | + } | |
| 109748 | + flags = (flags & ~mask) | mode; | |
| 109749 | + } | |
| 109750 | + } | |
| 109751 | + | |
| 109752 | + zOpt = &zVal[nVal+1]; | |
| 109753 | + } | |
| 109754 | + | |
| 109755 | + }else{ | |
| 109756 | + zFile = sqlite3_malloc(nUri+2); | |
| 109757 | + if( !zFile ) return SQLITE_NOMEM; | |
| 109758 | + memcpy(zFile, zUri, nUri); | |
| 109759 | + zFile[nUri] = '\0'; | |
| 109760 | + zFile[nUri+1] = '\0'; | |
| 109761 | + } | |
| 109762 | + | |
| 109763 | + *ppVfs = sqlite3_vfs_find(zVfs); | |
| 109764 | + if( *ppVfs==0 ){ | |
| 109765 | + *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); | |
| 109766 | + rc = SQLITE_ERROR; | |
| 109767 | + } | |
| 109768 | + parse_uri_out: | |
| 109769 | + if( rc!=SQLITE_OK ){ | |
| 109770 | + sqlite3_free(zFile); | |
| 109771 | + zFile = 0; | |
| 109772 | + } | |
| 109773 | + *pFlags = flags; | |
| 109774 | + *pzFile = zFile; | |
| 109775 | + return rc; | |
| 109776 | +} | |
| 109777 | + | |
| 108891 | 109778 | |
| 108892 | 109779 | /* |
| 108893 | 109780 | ** This routine does the work of opening a database on behalf of |
| 108894 | 109781 | ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" |
| 108895 | 109782 | ** is UTF-8 encoded. |
| 108896 | 109783 | */ |
| 108897 | 109784 | static int openDatabase( |
| 108898 | 109785 | const char *zFilename, /* Database filename UTF-8 encoded */ |
| 108899 | 109786 | sqlite3 **ppDb, /* OUT: Returned database handle */ |
| 108900 | - unsigned flags, /* Operational flags */ | |
| 109787 | + unsigned int flags, /* Operational flags */ | |
| 108901 | 109788 | const char *zVfs /* Name of the VFS to use */ |
| 108902 | 109789 | ){ |
| 108903 | - sqlite3 *db; | |
| 108904 | - int rc; | |
| 108905 | - int isThreadsafe; | |
| 109790 | + sqlite3 *db; /* Store allocated handle here */ | |
| 109791 | + int rc; /* Return code */ | |
| 109792 | + int isThreadsafe; /* True for threadsafe connections */ | |
| 109793 | + char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ | |
| 109794 | + char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ | |
| 108906 | 109795 | |
| 108907 | 109796 | *ppDb = 0; |
| 108908 | 109797 | #ifndef SQLITE_OMIT_AUTOINIT |
| 108909 | 109798 | rc = sqlite3_initialize(); |
| 108910 | 109799 | if( rc ) return rc; |
| @@ -108924,11 +109813,11 @@ | ||
| 108924 | 109813 | assert( SQLITE_OPEN_READWRITE == 0x02 ); |
| 108925 | 109814 | assert( SQLITE_OPEN_CREATE == 0x04 ); |
| 108926 | 109815 | testcase( (1<<(flags&7))==0x02 ); /* READONLY */ |
| 108927 | 109816 | testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ |
| 108928 | 109817 | testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ |
| 108929 | - if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE; | |
| 109818 | + if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT; | |
| 108930 | 109819 | |
| 108931 | 109820 | if( sqlite3GlobalConfig.bCoreMutex==0 ){ |
| 108932 | 109821 | isThreadsafe = 0; |
| 108933 | 109822 | }else if( flags & SQLITE_OPEN_NOMUTEX ){ |
| 108934 | 109823 | isThreadsafe = 0; |
| @@ -109005,17 +109894,10 @@ | ||
| 109005 | 109894 | sqlite3HashInit(&db->aCollSeq); |
| 109006 | 109895 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 109007 | 109896 | sqlite3HashInit(&db->aModule); |
| 109008 | 109897 | #endif |
| 109009 | 109898 | |
| 109010 | - db->pVfs = sqlite3_vfs_find(zVfs); | |
| 109011 | - if( !db->pVfs ){ | |
| 109012 | - rc = SQLITE_ERROR; | |
| 109013 | - sqlite3Error(db, rc, "no such vfs: %s", zVfs); | |
| 109014 | - goto opendb_out; | |
| 109015 | - } | |
| 109016 | - | |
| 109017 | 109899 | /* Add the default collation sequence BINARY. BINARY works for both UTF-8 |
| 109018 | 109900 | ** and UTF-16, so add a version for each to avoid any unnecessary |
| 109019 | 109901 | ** conversions. The only error that can occur here is a malloc() failure. |
| 109020 | 109902 | */ |
| 109021 | 109903 | createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0, |
| @@ -109034,13 +109916,22 @@ | ||
| 109034 | 109916 | |
| 109035 | 109917 | /* Also add a UTF-8 case-insensitive collation sequence. */ |
| 109036 | 109918 | createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0, |
| 109037 | 109919 | nocaseCollatingFunc, 0); |
| 109038 | 109920 | |
| 109039 | - /* Open the backend database driver */ | |
| 109921 | + /* Parse the filename/URI argument. */ | |
| 109040 | 109922 | db->openFlags = flags; |
| 109041 | - rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0, | |
| 109923 | + rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); | |
| 109924 | + if( rc!=SQLITE_OK ){ | |
| 109925 | + if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; | |
| 109926 | + sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg); | |
| 109927 | + sqlite3_free(zErrMsg); | |
| 109928 | + goto opendb_out; | |
| 109929 | + } | |
| 109930 | + | |
| 109931 | + /* Open the backend database driver */ | |
| 109932 | + rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, | |
| 109042 | 109933 | flags | SQLITE_OPEN_MAIN_DB); |
| 109043 | 109934 | if( rc!=SQLITE_OK ){ |
| 109044 | 109935 | if( rc==SQLITE_IOERR_NOMEM ){ |
| 109045 | 109936 | rc = SQLITE_NOMEM; |
| 109046 | 109937 | } |
| @@ -109129,10 +110020,11 @@ | ||
| 109129 | 110020 | sqlite3GlobalConfig.nLookaside); |
| 109130 | 110021 | |
| 109131 | 110022 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 109132 | 110023 | |
| 109133 | 110024 | opendb_out: |
| 110025 | + sqlite3_free(zOpen); | |
| 109134 | 110026 | if( db ){ |
| 109135 | 110027 | assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); |
| 109136 | 110028 | sqlite3_mutex_leave(db->mutex); |
| 109137 | 110029 | } |
| 109138 | 110030 | rc = sqlite3_errcode(db); |
| @@ -109160,11 +110052,11 @@ | ||
| 109160 | 110052 | const char *filename, /* Database filename (UTF-8) */ |
| 109161 | 110053 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 109162 | 110054 | int flags, /* Flags */ |
| 109163 | 110055 | const char *zVfs /* Name of VFS module to use */ |
| 109164 | 110056 | ){ |
| 109165 | - return openDatabase(filename, ppDb, flags, zVfs); | |
| 110057 | + return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); | |
| 109166 | 110058 | } |
| 109167 | 110059 | |
| 109168 | 110060 | #ifndef SQLITE_OMIT_UTF16 |
| 109169 | 110061 | /* |
| 109170 | 110062 | ** Open a new database handle. |
| @@ -109770,10 +110662,32 @@ | ||
| 109770 | 110662 | } |
| 109771 | 110663 | va_end(ap); |
| 109772 | 110664 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 109773 | 110665 | return rc; |
| 109774 | 110666 | } |
| 110667 | + | |
| 110668 | +/* | |
| 110669 | +** This is a utility routine, useful to VFS implementations, that checks | |
| 110670 | +** to see if a database file was a URI that contained a specific query | |
| 110671 | +** parameter, and if so obtains the value of the query parameter. | |
| 110672 | +** | |
| 110673 | +** The zFilename argument is the filename pointer passed into the xOpen() | |
| 110674 | +** method of a VFS implementation. The zParam argument is the name of the | |
| 110675 | +** query parameter we seek. This routine returns the value of the zParam | |
| 110676 | +** parameter if it exists. If the parameter does not exist, this routine | |
| 110677 | +** returns a NULL pointer. | |
| 110678 | +*/ | |
| 110679 | +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ | |
| 110680 | + zFilename += sqlite3Strlen30(zFilename) + 1; | |
| 110681 | + while( zFilename[0] ){ | |
| 110682 | + int x = strcmp(zFilename, zParam); | |
| 110683 | + zFilename += sqlite3Strlen30(zFilename) + 1; | |
| 110684 | + if( x==0 ) return zFilename; | |
| 110685 | + zFilename += sqlite3Strlen30(zFilename) + 1; | |
| 110686 | + } | |
| 110687 | + return 0; | |
| 110688 | +} | |
| 109775 | 110689 | |
| 109776 | 110690 | /************** End of main.c ************************************************/ |
| 109777 | 110691 | /************** Begin file notify.c ******************************************/ |
| 109778 | 110692 | /* |
| 109779 | 110693 | ** 2009 March 3 |
| @@ -110851,10 +111765,11 @@ | ||
| 110851 | 111765 | Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ |
| 110852 | 111766 | sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ |
| 110853 | 111767 | char *pNextId; /* Pointer into the body of aDoclist */ |
| 110854 | 111768 | char *aDoclist; /* List of docids for full-text queries */ |
| 110855 | 111769 | int nDoclist; /* Size of buffer at aDoclist */ |
| 111770 | + int desc; /* True to sort in descending order */ | |
| 110856 | 111771 | int eEvalmode; /* An FTS3_EVAL_XX constant */ |
| 110857 | 111772 | int nRowAvg; /* Average size of database rows, in pages */ |
| 110858 | 111773 | |
| 110859 | 111774 | int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ |
| 110860 | 111775 | u32 *aMatchinfo; /* Information about most recent match */ |
| @@ -111033,11 +111948,11 @@ | ||
| 111033 | 111948 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 111034 | 111949 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 111035 | 111950 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 111036 | 111951 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 111037 | 111952 | |
| 111038 | -SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int); | |
| 111953 | +SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Cursor *, Fts3Expr *, sqlite3_int64, int); | |
| 111039 | 111954 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *); |
| 111040 | 111955 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *); |
| 111041 | 111956 | SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int); |
| 111042 | 111957 | |
| 111043 | 111958 | /* fts3_tokenizer.c */ |
| @@ -111060,10 +111975,11 @@ | ||
| 111060 | 111975 | char **, int, int, const char *, int, Fts3Expr ** |
| 111061 | 111976 | ); |
| 111062 | 111977 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 111063 | 111978 | #ifdef SQLITE_TEST |
| 111064 | 111979 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 111980 | +SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); | |
| 111065 | 111981 | #endif |
| 111066 | 111982 | |
| 111067 | 111983 | /* fts3_aux.c */ |
| 111068 | 111984 | SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); |
| 111069 | 111985 | |
| @@ -111180,10 +112096,38 @@ | ||
| 111180 | 112096 | static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ |
| 111181 | 112097 | sqlite3_int64 iVal; |
| 111182 | 112098 | *pp += sqlite3Fts3GetVarint(*pp, &iVal); |
| 111183 | 112099 | *pVal += iVal; |
| 111184 | 112100 | } |
| 112101 | + | |
| 112102 | +/* | |
| 112103 | +** When this function is called, *pp points to the first byte following a | |
| 112104 | +** varint that is part of a doclist (or position-list, or any other list | |
| 112105 | +** of varints). This function moves *pp to point to the start of that varint, | |
| 112106 | +** and decrements the value stored in *pVal by the varint value. | |
| 112107 | +** | |
| 112108 | +** Argument pStart points to the first byte of the doclist that the | |
| 112109 | +** varint is part of. | |
| 112110 | +*/ | |
| 112111 | +static void fts3GetReverseDeltaVarint( | |
| 112112 | + char **pp, | |
| 112113 | + char *pStart, | |
| 112114 | + sqlite3_int64 *pVal | |
| 112115 | +){ | |
| 112116 | + sqlite3_int64 iVal; | |
| 112117 | + char *p = *pp; | |
| 112118 | + | |
| 112119 | + /* Pointer p now points at the first byte past the varint we are | |
| 112120 | + ** interested in. So, unless the doclist is corrupt, the 0x80 bit is | |
| 112121 | + ** clear on character p[-1]. */ | |
| 112122 | + for(p = (*pp)-2; p>=pStart && *p&0x80; p--); | |
| 112123 | + p++; | |
| 112124 | + *pp = p; | |
| 112125 | + | |
| 112126 | + sqlite3Fts3GetVarint(p, &iVal); | |
| 112127 | + *pVal -= iVal; | |
| 112128 | +} | |
| 111185 | 112129 | |
| 111186 | 112130 | /* |
| 111187 | 112131 | ** As long as *pp has not reached its end (pEnd), then do the same |
| 111188 | 112132 | ** as fts3GetDeltaVarint(): read a single varint and add it to *pVal. |
| 111189 | 112133 | ** But if we have reached the end of the varint, just set *pp=0 and |
| @@ -111285,10 +112229,12 @@ | ||
| 111285 | 112229 | if( *pRc==SQLITE_OK ){ |
| 111286 | 112230 | int i; /* Iterator variable */ |
| 111287 | 112231 | int rc; /* Return code */ |
| 111288 | 112232 | char *zSql; /* SQL statement passed to declare_vtab() */ |
| 111289 | 112233 | char *zCols; /* List of user defined columns */ |
| 112234 | + | |
| 112235 | + sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); | |
| 111290 | 112236 | |
| 111291 | 112237 | /* Create a list of user columns for the virtual table */ |
| 111292 | 112238 | zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); |
| 111293 | 112239 | for(i=1; zCols && i<p->nColumn; i++){ |
| 111294 | 112240 | zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); |
| @@ -111854,10 +112800,26 @@ | ||
| 111854 | 112800 | |
| 111855 | 112801 | if( iCons>=0 ){ |
| 111856 | 112802 | pInfo->aConstraintUsage[iCons].argvIndex = 1; |
| 111857 | 112803 | pInfo->aConstraintUsage[iCons].omit = 1; |
| 111858 | 112804 | } |
| 112805 | + | |
| 112806 | + /* Regardless of the strategy selected, FTS can deliver rows in rowid (or | |
| 112807 | + ** docid) order. Both ascending and descending are possible. | |
| 112808 | + */ | |
| 112809 | + if( pInfo->nOrderBy==1 ){ | |
| 112810 | + struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; | |
| 112811 | + if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ | |
| 112812 | + if( pOrder->desc ){ | |
| 112813 | + pInfo->idxStr = "DESC"; | |
| 112814 | + }else{ | |
| 112815 | + pInfo->idxStr = "ASC"; | |
| 112816 | + } | |
| 112817 | + } | |
| 112818 | + pInfo->orderByConsumed = 1; | |
| 112819 | + } | |
| 112820 | + | |
| 111859 | 112821 | return SQLITE_OK; |
| 111860 | 112822 | } |
| 111861 | 112823 | |
| 111862 | 112824 | /* |
| 111863 | 112825 | ** Implementation of xOpen method. |
| @@ -111911,11 +112873,11 @@ | ||
| 111911 | 112873 | if( rc==SQLITE_OK ){ |
| 111912 | 112874 | /* If no row was found and no error has occured, then the %_content |
| 111913 | 112875 | ** table is missing a row that is present in the full-text index. |
| 111914 | 112876 | ** The data structures are corrupt. |
| 111915 | 112877 | */ |
| 111916 | - rc = SQLITE_CORRUPT; | |
| 112878 | + rc = SQLITE_CORRUPT_VTAB; | |
| 111917 | 112879 | } |
| 111918 | 112880 | pCsr->isEof = 1; |
| 111919 | 112881 | if( pContext ){ |
| 111920 | 112882 | sqlite3_result_error_code(pContext, rc); |
| 111921 | 112883 | } |
| @@ -111971,11 +112933,11 @@ | ||
| 111971 | 112933 | ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). |
| 111972 | 112934 | */ |
| 111973 | 112935 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 111974 | 112936 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 111975 | 112937 | if( zCsr>zEnd ){ |
| 111976 | - return SQLITE_CORRUPT; | |
| 112938 | + return SQLITE_CORRUPT_VTAB; | |
| 111977 | 112939 | } |
| 111978 | 112940 | |
| 111979 | 112941 | while( zCsr<zEnd && (piFirst || piLast) ){ |
| 111980 | 112942 | int cmp; /* memcmp() result */ |
| 111981 | 112943 | int nSuffix; /* Size of term suffix */ |
| @@ -111989,11 +112951,11 @@ | ||
| 111989 | 112951 | } |
| 111990 | 112952 | isFirstTerm = 0; |
| 111991 | 112953 | zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix); |
| 111992 | 112954 | |
| 111993 | 112955 | if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){ |
| 111994 | - rc = SQLITE_CORRUPT; | |
| 112956 | + rc = SQLITE_CORRUPT_VTAB; | |
| 111995 | 112957 | goto finish_scan; |
| 111996 | 112958 | } |
| 111997 | 112959 | if( nPrefix+nSuffix>nAlloc ){ |
| 111998 | 112960 | char *zNew; |
| 111999 | 112961 | nAlloc = (nPrefix+nSuffix) * 2; |
| @@ -113758,16 +114720,24 @@ | ||
| 113758 | 114720 | rc = sqlite3_reset(pCsr->pStmt); |
| 113759 | 114721 | break; |
| 113760 | 114722 | } |
| 113761 | 114723 | pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); |
| 113762 | 114724 | }else{ |
| 113763 | - if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ | |
| 113764 | - pCsr->isEof = 1; | |
| 113765 | - break; | |
| 114725 | + if( pCsr->desc==0 ){ | |
| 114726 | + if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ | |
| 114727 | + pCsr->isEof = 1; | |
| 114728 | + break; | |
| 114729 | + } | |
| 114730 | + fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); | |
| 114731 | + }else{ | |
| 114732 | + fts3GetReverseDeltaVarint(&pCsr->pNextId,pCsr->aDoclist,&pCsr->iPrevId); | |
| 114733 | + if( pCsr->pNextId<=pCsr->aDoclist ){ | |
| 114734 | + pCsr->isEof = 1; | |
| 114735 | + break; | |
| 114736 | + } | |
| 113766 | 114737 | } |
| 113767 | 114738 | sqlite3_reset(pCsr->pStmt); |
| 113768 | - fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); | |
| 113769 | 114739 | pCsr->isRequireSeek = 1; |
| 113770 | 114740 | pCsr->isMatchinfoNeeded = 1; |
| 113771 | 114741 | } |
| 113772 | 114742 | }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 ); |
| 113773 | 114743 | |
| @@ -113796,12 +114766,12 @@ | ||
| 113796 | 114766 | const char *idxStr, /* Unused */ |
| 113797 | 114767 | int nVal, /* Number of elements in apVal */ |
| 113798 | 114768 | sqlite3_value **apVal /* Arguments for the indexing scheme */ |
| 113799 | 114769 | ){ |
| 113800 | 114770 | const char *azSql[] = { |
| 113801 | - "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ | |
| 113802 | - "SELECT %s FROM %Q.'%q_content' AS x ", /* full-scan */ | |
| 114771 | + "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ | |
| 114772 | + "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s", /* full-scan */ | |
| 113803 | 114773 | }; |
| 113804 | 114774 | int rc; /* Return code */ |
| 113805 | 114775 | char *zSql; /* SQL statement used to access %_content */ |
| 113806 | 114776 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; |
| 113807 | 114777 | Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; |
| @@ -113853,11 +114823,13 @@ | ||
| 113853 | 114823 | ** statement loops through all rows of the %_content table. For a |
| 113854 | 114824 | ** full-text query or docid lookup, the statement retrieves a single |
| 113855 | 114825 | ** row by docid. |
| 113856 | 114826 | */ |
| 113857 | 114827 | zSql = (char *)azSql[idxNum==FTS3_FULLSCAN_SEARCH]; |
| 113858 | - zSql = sqlite3_mprintf(zSql, p->zReadExprlist, p->zDb, p->zName); | |
| 114828 | + zSql = sqlite3_mprintf( | |
| 114829 | + zSql, p->zReadExprlist, p->zDb, p->zName, (idxStr ? idxStr : "ASC") | |
| 114830 | + ); | |
| 113859 | 114831 | if( !zSql ){ |
| 113860 | 114832 | rc = SQLITE_NOMEM; |
| 113861 | 114833 | }else{ |
| 113862 | 114834 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 113863 | 114835 | sqlite3_free(zSql); |
| @@ -113865,11 +114837,26 @@ | ||
| 113865 | 114837 | if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){ |
| 113866 | 114838 | rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); |
| 113867 | 114839 | } |
| 113868 | 114840 | pCsr->eSearch = (i16)idxNum; |
| 113869 | 114841 | |
| 114842 | + assert( pCsr->desc==0 ); | |
| 113870 | 114843 | if( rc!=SQLITE_OK ) return rc; |
| 114844 | + if( rc==SQLITE_OK && pCsr->nDoclist>0 && idxStr && idxStr[0]=='D' ){ | |
| 114845 | + sqlite3_int64 iDocid = 0; | |
| 114846 | + char *csr = pCsr->aDoclist; | |
| 114847 | + while( csr<&pCsr->aDoclist[pCsr->nDoclist] ){ | |
| 114848 | + fts3GetDeltaVarint(&csr, &iDocid); | |
| 114849 | + } | |
| 114850 | + pCsr->pNextId = csr; | |
| 114851 | + pCsr->iPrevId = iDocid; | |
| 114852 | + pCsr->desc = 1; | |
| 114853 | + pCsr->isRequireSeek = 1; | |
| 114854 | + pCsr->isMatchinfoNeeded = 1; | |
| 114855 | + pCsr->eEvalmode = FTS3_EVAL_NEXT; | |
| 114856 | + return SQLITE_OK; | |
| 114857 | + } | |
| 113871 | 114858 | return fts3NextMethod(pCursor); |
| 113872 | 114859 | } |
| 113873 | 114860 | |
| 113874 | 114861 | /* |
| 113875 | 114862 | ** This is the xEof method of the virtual table. SQLite calls this |
| @@ -114017,17 +115004,37 @@ | ||
| 114017 | 115004 | pCsr->eEvalmode = FTS3_EVAL_MATCHINFO; |
| 114018 | 115005 | rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1); |
| 114019 | 115006 | pCsr->eEvalmode = FTS3_EVAL_NEXT; |
| 114020 | 115007 | return rc; |
| 114021 | 115008 | } |
| 115009 | + | |
| 115010 | + | |
| 115011 | +/* | |
| 115012 | +** When called, *ppPoslist must point to the byte immediately following the | |
| 115013 | +** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function | |
| 115014 | +** moves *ppPoslist so that it instead points to the first byte of the | |
| 115015 | +** same position list. | |
| 115016 | +*/ | |
| 115017 | +static void fts3ReversePoslist(char *pStart, char **ppPoslist){ | |
| 115018 | + char *p = &(*ppPoslist)[-3]; | |
| 115019 | + char c = p[1]; | |
| 115020 | + while( p>pStart && (*p & 0x80) | c ){ | |
| 115021 | + c = *p--; | |
| 115022 | + } | |
| 115023 | + if( p>pStart ){ p = &p[2]; } | |
| 115024 | + while( *p++&0x80 ); | |
| 115025 | + *ppPoslist = p; | |
| 115026 | +} | |
| 115027 | + | |
| 114022 | 115028 | |
| 114023 | 115029 | /* |
| 114024 | 115030 | ** After ExprLoadDoclist() (see above) has been called, this function is |
| 114025 | 115031 | ** used to iterate/search through the position lists that make up the doclist |
| 114026 | 115032 | ** stored in pExpr->aDoclist. |
| 114027 | 115033 | */ |
| 114028 | 115034 | SQLITE_PRIVATE char *sqlite3Fts3FindPositions( |
| 115035 | + Fts3Cursor *pCursor, /* Associate FTS3 cursor */ | |
| 114029 | 115036 | Fts3Expr *pExpr, /* Access this expressions doclist */ |
| 114030 | 115037 | sqlite3_int64 iDocid, /* Docid associated with requested pos-list */ |
| 114031 | 115038 | int iCol /* Column of requested pos-list */ |
| 114032 | 115039 | ){ |
| 114033 | 115040 | assert( pExpr->isLoaded ); |
| @@ -114034,23 +115041,39 @@ | ||
| 114034 | 115041 | if( pExpr->aDoclist ){ |
| 114035 | 115042 | char *pEnd = &pExpr->aDoclist[pExpr->nDoclist]; |
| 114036 | 115043 | char *pCsr; |
| 114037 | 115044 | |
| 114038 | 115045 | if( pExpr->pCurrent==0 ){ |
| 114039 | - pExpr->pCurrent = pExpr->aDoclist; | |
| 114040 | - pExpr->iCurrent = 0; | |
| 114041 | - pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent); | |
| 115046 | + if( pCursor->desc==0 ){ | |
| 115047 | + pExpr->pCurrent = pExpr->aDoclist; | |
| 115048 | + pExpr->iCurrent = 0; | |
| 115049 | + fts3GetDeltaVarint(&pExpr->pCurrent, &pExpr->iCurrent); | |
| 115050 | + }else{ | |
| 115051 | + pCsr = pExpr->aDoclist; | |
| 115052 | + while( pCsr<pEnd ){ | |
| 115053 | + fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent); | |
| 115054 | + fts3PoslistCopy(0, &pCsr); | |
| 115055 | + } | |
| 115056 | + fts3ReversePoslist(pExpr->aDoclist, &pCsr); | |
| 115057 | + pExpr->pCurrent = pCsr; | |
| 115058 | + } | |
| 114042 | 115059 | } |
| 114043 | 115060 | pCsr = pExpr->pCurrent; |
| 114044 | 115061 | assert( pCsr ); |
| 114045 | 115062 | |
| 114046 | - while( pCsr<pEnd ){ | |
| 114047 | - if( pExpr->iCurrent<iDocid ){ | |
| 115063 | + while( (pCursor->desc==0 && pCsr<pEnd) | |
| 115064 | + || (pCursor->desc && pCsr>pExpr->aDoclist) | |
| 115065 | + ){ | |
| 115066 | + if( pCursor->desc==0 && pExpr->iCurrent<iDocid ){ | |
| 114048 | 115067 | fts3PoslistCopy(0, &pCsr); |
| 114049 | 115068 | if( pCsr<pEnd ){ |
| 114050 | 115069 | fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent); |
| 114051 | 115070 | } |
| 115071 | + pExpr->pCurrent = pCsr; | |
| 115072 | + }else if( pCursor->desc && pExpr->iCurrent>iDocid ){ | |
| 115073 | + fts3GetReverseDeltaVarint(&pCsr, pExpr->aDoclist, &pExpr->iCurrent); | |
| 115074 | + fts3ReversePoslist(pExpr->aDoclist, &pCsr); | |
| 114052 | 115075 | pExpr->pCurrent = pCsr; |
| 114053 | 115076 | }else{ |
| 114054 | 115077 | if( pExpr->iCurrent==iDocid ){ |
| 114055 | 115078 | int iThis = 0; |
| 114056 | 115079 | if( iCol<0 ){ |
| @@ -114303,13 +115326,24 @@ | ||
| 114303 | 115326 | "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", |
| 114304 | 115327 | p->zDb, p->zName, zName |
| 114305 | 115328 | ); |
| 114306 | 115329 | return rc; |
| 114307 | 115330 | } |
| 115331 | + | |
| 115332 | +static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ | |
| 115333 | + return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab); | |
| 115334 | +} | |
| 115335 | +static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ | |
| 115336 | + return SQLITE_OK; | |
| 115337 | +} | |
| 115338 | +static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ | |
| 115339 | + sqlite3Fts3PendingTermsClear((Fts3Table *)pVtab); | |
| 115340 | + return SQLITE_OK; | |
| 115341 | +} | |
| 114308 | 115342 | |
| 114309 | 115343 | static const sqlite3_module fts3Module = { |
| 114310 | - /* iVersion */ 0, | |
| 115344 | + /* iVersion */ 2, | |
| 114311 | 115345 | /* xCreate */ fts3CreateMethod, |
| 114312 | 115346 | /* xConnect */ fts3ConnectMethod, |
| 114313 | 115347 | /* xBestIndex */ fts3BestIndexMethod, |
| 114314 | 115348 | /* xDisconnect */ fts3DisconnectMethod, |
| 114315 | 115349 | /* xDestroy */ fts3DestroyMethod, |
| @@ -114325,10 +115359,13 @@ | ||
| 114325 | 115359 | /* xSync */ fts3SyncMethod, |
| 114326 | 115360 | /* xCommit */ fts3CommitMethod, |
| 114327 | 115361 | /* xRollback */ fts3RollbackMethod, |
| 114328 | 115362 | /* xFindFunction */ fts3FindFunctionMethod, |
| 114329 | 115363 | /* xRename */ fts3RenameMethod, |
| 115364 | + /* xSavepoint */ fts3SavepointMethod, | |
| 115365 | + /* xRelease */ fts3ReleaseMethod, | |
| 115366 | + /* xRollbackTo */ fts3RollbackToMethod, | |
| 114330 | 115367 | }; |
| 114331 | 115368 | |
| 114332 | 115369 | /* |
| 114333 | 115370 | ** This function is registered as the module destructor (called when an |
| 114334 | 115371 | ** FTS3 enabled database connection is closed). It frees the memory |
| @@ -114370,10 +115407,15 @@ | ||
| 114370 | 115407 | |
| 114371 | 115408 | #ifdef SQLITE_ENABLE_ICU |
| 114372 | 115409 | const sqlite3_tokenizer_module *pIcu = 0; |
| 114373 | 115410 | sqlite3Fts3IcuTokenizerModule(&pIcu); |
| 114374 | 115411 | #endif |
| 115412 | + | |
| 115413 | +#ifdef SQLITE_TEST | |
| 115414 | + rc = sqlite3Fts3InitTerm(db); | |
| 115415 | + if( rc!=SQLITE_OK ) return rc; | |
| 115416 | +#endif | |
| 114375 | 115417 | |
| 114376 | 115418 | rc = sqlite3Fts3InitAux(db); |
| 114377 | 115419 | if( rc!=SQLITE_OK ) return rc; |
| 114378 | 115420 | |
| 114379 | 115421 | sqlite3Fts3SimpleTokenizerModule(&pSimple); |
| @@ -117891,11 +118933,11 @@ | ||
| 117891 | 118933 | sqlite3_bind_int64(pStmt, 1, iDocid); |
| 117892 | 118934 | } |
| 117893 | 118935 | rc = sqlite3_step(pStmt); |
| 117894 | 118936 | if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ |
| 117895 | 118937 | rc = sqlite3_reset(pStmt); |
| 117896 | - if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT; | |
| 118938 | + if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB; | |
| 117897 | 118939 | pStmt = 0; |
| 117898 | 118940 | }else{ |
| 117899 | 118941 | rc = SQLITE_OK; |
| 117900 | 118942 | } |
| 117901 | 118943 | } |
| @@ -118141,10 +119183,18 @@ | ||
| 118141 | 119183 | sqlite3_tokenizer_cursor *pCsr; |
| 118142 | 119184 | int (*xNext)(sqlite3_tokenizer_cursor *pCursor, |
| 118143 | 119185 | const char**,int*,int*,int*,int*); |
| 118144 | 119186 | |
| 118145 | 119187 | assert( pTokenizer && pModule ); |
| 119188 | + | |
| 119189 | + /* If the user has inserted a NULL value, this function may be called with | |
| 119190 | + ** zText==0. In this case, add zero token entries to the hash table and | |
| 119191 | + ** return early. */ | |
| 119192 | + if( zText==0 ){ | |
| 119193 | + *pnWord = 0; | |
| 119194 | + return SQLITE_OK; | |
| 119195 | + } | |
| 118146 | 119196 | |
| 118147 | 119197 | rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr); |
| 118148 | 119198 | if( rc!=SQLITE_OK ){ |
| 118149 | 119199 | return rc; |
| 118150 | 119200 | } |
| @@ -118232,15 +119282,13 @@ | ||
| 118232 | 119282 | */ |
| 118233 | 119283 | static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){ |
| 118234 | 119284 | int i; /* Iterator variable */ |
| 118235 | 119285 | for(i=2; i<p->nColumn+2; i++){ |
| 118236 | 119286 | const char *zText = (const char *)sqlite3_value_text(apVal[i]); |
| 118237 | - if( zText ){ | |
| 118238 | - int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); | |
| 118239 | - if( rc!=SQLITE_OK ){ | |
| 118240 | - return rc; | |
| 118241 | - } | |
| 119287 | + int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); | |
| 119288 | + if( rc!=SQLITE_OK ){ | |
| 119289 | + return rc; | |
| 118242 | 119290 | } |
| 118243 | 119291 | aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); |
| 118244 | 119292 | } |
| 118245 | 119293 | return SQLITE_OK; |
| 118246 | 119294 | } |
| @@ -118341,18 +119389,18 @@ | ||
| 118341 | 119389 | ** full-text index. |
| 118342 | 119390 | */ |
| 118343 | 119391 | static void fts3DeleteTerms( |
| 118344 | 119392 | int *pRC, /* Result code */ |
| 118345 | 119393 | Fts3Table *p, /* The FTS table to delete from */ |
| 118346 | - sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */ | |
| 119394 | + sqlite3_value *pRowid, /* The docid to be deleted */ | |
| 118347 | 119395 | u32 *aSz /* Sizes of deleted document written here */ |
| 118348 | 119396 | ){ |
| 118349 | 119397 | int rc; |
| 118350 | 119398 | sqlite3_stmt *pSelect; |
| 118351 | 119399 | |
| 118352 | 119400 | if( *pRC ) return; |
| 118353 | - rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal); | |
| 119401 | + rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); | |
| 118354 | 119402 | if( rc==SQLITE_OK ){ |
| 118355 | 119403 | if( SQLITE_ROW==sqlite3_step(pSelect) ){ |
| 118356 | 119404 | int i; |
| 118357 | 119405 | for(i=1; i<=p->nColumn; i++){ |
| 118358 | 119406 | const char *zText = (const char *)sqlite3_column_text(pSelect, i); |
| @@ -118566,11 +119614,11 @@ | ||
| 118566 | 119614 | pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix); |
| 118567 | 119615 | pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix); |
| 118568 | 119616 | if( nPrefix<0 || nSuffix<=0 |
| 118569 | 119617 | || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] |
| 118570 | 119618 | ){ |
| 118571 | - return SQLITE_CORRUPT; | |
| 119619 | + return SQLITE_CORRUPT_VTAB; | |
| 118572 | 119620 | } |
| 118573 | 119621 | |
| 118574 | 119622 | if( nPrefix+nSuffix>pReader->nTermAlloc ){ |
| 118575 | 119623 | int nNew = (nPrefix+nSuffix)*2; |
| 118576 | 119624 | char *zNew = sqlite3_realloc(pReader->zTerm, nNew); |
| @@ -118592,11 +119640,11 @@ | ||
| 118592 | 119640 | ** of these statements is untrue, then the data structure is corrupt. |
| 118593 | 119641 | */ |
| 118594 | 119642 | if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] |
| 118595 | 119643 | || pReader->aDoclist[pReader->nDoclist-1] |
| 118596 | 119644 | ){ |
| 118597 | - return SQLITE_CORRUPT; | |
| 119645 | + return SQLITE_CORRUPT_VTAB; | |
| 118598 | 119646 | } |
| 118599 | 119647 | return SQLITE_OK; |
| 118600 | 119648 | } |
| 118601 | 119649 | |
| 118602 | 119650 | /* |
| @@ -118717,11 +119765,11 @@ | ||
| 118717 | 119765 | while( a<pEnd ){ |
| 118718 | 119766 | a += sqlite3Fts3GetVarint(a, &nByte); |
| 118719 | 119767 | } |
| 118720 | 119768 | if( nDoc==0 || nByte==0 ){ |
| 118721 | 119769 | sqlite3_reset(pStmt); |
| 118722 | - return SQLITE_CORRUPT; | |
| 119770 | + return SQLITE_CORRUPT_VTAB; | |
| 118723 | 119771 | } |
| 118724 | 119772 | |
| 118725 | 119773 | pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz); |
| 118726 | 119774 | assert( pCsr->nRowAvg>0 ); |
| 118727 | 119775 | rc = sqlite3_reset(pStmt); |
| @@ -119488,20 +120536,20 @@ | ||
| 119488 | 120536 | |
| 119489 | 120537 | /* |
| 119490 | 120538 | ** The first value in the apVal[] array is assumed to contain an integer. |
| 119491 | 120539 | ** This function tests if there exist any documents with docid values that |
| 119492 | 120540 | ** are different from that integer. i.e. if deleting the document with docid |
| 119493 | -** apVal[0] would mean the FTS3 table were empty. | |
| 120541 | +** pRowid would mean the FTS3 table were empty. | |
| 119494 | 120542 | ** |
| 119495 | 120543 | ** If successful, *pisEmpty is set to true if the table is empty except for |
| 119496 | -** document apVal[0], or false otherwise, and SQLITE_OK is returned. If an | |
| 120544 | +** document pRowid, or false otherwise, and SQLITE_OK is returned. If an | |
| 119497 | 120545 | ** error occurs, an SQLite error code is returned. |
| 119498 | 120546 | */ |
| 119499 | -static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){ | |
| 120547 | +static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ | |
| 119500 | 120548 | sqlite3_stmt *pStmt; |
| 119501 | 120549 | int rc; |
| 119502 | - rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, apVal); | |
| 120550 | + rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); | |
| 119503 | 120551 | if( rc==SQLITE_OK ){ |
| 119504 | 120552 | if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 119505 | 120553 | *pisEmpty = sqlite3_column_int(pStmt, 0); |
| 119506 | 120554 | } |
| 119507 | 120555 | rc = sqlite3_reset(pStmt); |
| @@ -120221,10 +121269,44 @@ | ||
| 120221 | 121269 | pToken->pDeferred = pDeferred; |
| 120222 | 121270 | |
| 120223 | 121271 | return SQLITE_OK; |
| 120224 | 121272 | } |
| 120225 | 121273 | |
| 121274 | +/* | |
| 121275 | +** SQLite value pRowid contains the rowid of a row that may or may not be | |
| 121276 | +** present in the FTS3 table. If it is, delete it and adjust the contents | |
| 121277 | +** of subsiduary data structures accordingly. | |
| 121278 | +*/ | |
| 121279 | +static int fts3DeleteByRowid( | |
| 121280 | + Fts3Table *p, | |
| 121281 | + sqlite3_value *pRowid, | |
| 121282 | + int *pnDoc, | |
| 121283 | + u32 *aSzDel | |
| 121284 | +){ | |
| 121285 | + int isEmpty = 0; | |
| 121286 | + int rc = fts3IsEmpty(p, pRowid, &isEmpty); | |
| 121287 | + if( rc==SQLITE_OK ){ | |
| 121288 | + if( isEmpty ){ | |
| 121289 | + /* Deleting this row means the whole table is empty. In this case | |
| 121290 | + ** delete the contents of all three tables and throw away any | |
| 121291 | + ** data in the pendingTerms hash table. */ | |
| 121292 | + rc = fts3DeleteAll(p); | |
| 121293 | + *pnDoc = *pnDoc - 1; | |
| 121294 | + }else{ | |
| 121295 | + sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); | |
| 121296 | + rc = fts3PendingTermsDocid(p, iRemove); | |
| 121297 | + fts3DeleteTerms(&rc, p, pRowid, aSzDel); | |
| 121298 | + fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); | |
| 121299 | + if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; | |
| 121300 | + if( p->bHasDocsize ){ | |
| 121301 | + fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); | |
| 121302 | + } | |
| 121303 | + } | |
| 121304 | + } | |
| 121305 | + | |
| 121306 | + return rc; | |
| 121307 | +} | |
| 120226 | 121308 | |
| 120227 | 121309 | /* |
| 120228 | 121310 | ** This function does the work for the xUpdate method of FTS3 virtual |
| 120229 | 121311 | ** tables. |
| 120230 | 121312 | */ |
| @@ -120239,50 +121321,95 @@ | ||
| 120239 | 121321 | int isRemove = 0; /* True for an UPDATE or DELETE */ |
| 120240 | 121322 | sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */ |
| 120241 | 121323 | u32 *aSzIns; /* Sizes of inserted documents */ |
| 120242 | 121324 | u32 *aSzDel; /* Sizes of deleted documents */ |
| 120243 | 121325 | int nChng = 0; /* Net change in number of documents */ |
| 121326 | + int bInsertDone = 0; | |
| 120244 | 121327 | |
| 120245 | 121328 | assert( p->pSegments==0 ); |
| 121329 | + | |
| 121330 | + /* Check for a "special" INSERT operation. One of the form: | |
| 121331 | + ** | |
| 121332 | + ** INSERT INTO xyz(xyz) VALUES('command'); | |
| 121333 | + */ | |
| 121334 | + if( nArg>1 | |
| 121335 | + && sqlite3_value_type(apVal[0])==SQLITE_NULL | |
| 121336 | + && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL | |
| 121337 | + ){ | |
| 121338 | + return fts3SpecialInsert(p, apVal[p->nColumn+2]); | |
| 121339 | + } | |
| 120246 | 121340 | |
| 120247 | 121341 | /* Allocate space to hold the change in document sizes */ |
| 120248 | 121342 | aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 ); |
| 120249 | 121343 | if( aSzIns==0 ) return SQLITE_NOMEM; |
| 120250 | 121344 | aSzDel = &aSzIns[p->nColumn+1]; |
| 120251 | 121345 | memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2); |
| 121346 | + | |
| 121347 | + /* If this is an INSERT operation, or an UPDATE that modifies the rowid | |
| 121348 | + ** value, then this operation requires constraint handling. | |
| 121349 | + ** | |
| 121350 | + ** If the on-conflict mode is REPLACE, this means that the existing row | |
| 121351 | + ** should be deleted from the database before inserting the new row. Or, | |
| 121352 | + ** if the on-conflict mode is other than REPLACE, then this method must | |
| 121353 | + ** detect the conflict and return SQLITE_CONSTRAINT before beginning to | |
| 121354 | + ** modify the database file. | |
| 121355 | + */ | |
| 121356 | + if( nArg>1 ){ | |
| 121357 | + /* Find the value object that holds the new rowid value. */ | |
| 121358 | + sqlite3_value *pNewRowid = apVal[3+p->nColumn]; | |
| 121359 | + if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ | |
| 121360 | + pNewRowid = apVal[1]; | |
| 121361 | + } | |
| 121362 | + | |
| 121363 | + if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( | |
| 121364 | + sqlite3_value_type(apVal[0])==SQLITE_NULL | |
| 121365 | + || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) | |
| 121366 | + )){ | |
| 121367 | + /* The new rowid is not NULL (in this case the rowid will be | |
| 121368 | + ** automatically assigned and there is no chance of a conflict), and | |
| 121369 | + ** the statement is either an INSERT or an UPDATE that modifies the | |
| 121370 | + ** rowid column. So if the conflict mode is REPLACE, then delete any | |
| 121371 | + ** existing row with rowid=pNewRowid. | |
| 121372 | + ** | |
| 121373 | + ** Or, if the conflict mode is not REPLACE, insert the new record into | |
| 121374 | + ** the %_content table. If we hit the duplicate rowid constraint (or any | |
| 121375 | + ** other error) while doing so, return immediately. | |
| 121376 | + ** | |
| 121377 | + ** This branch may also run if pNewRowid contains a value that cannot | |
| 121378 | + ** be losslessly converted to an integer. In this case, the eventual | |
| 121379 | + ** call to fts3InsertData() (either just below or further on in this | |
| 121380 | + ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is | |
| 121381 | + ** invoked, it will delete zero rows (since no row will have | |
| 121382 | + ** docid=$pNewRowid if $pNewRowid is not an integer value). | |
| 121383 | + */ | |
| 121384 | + if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ | |
| 121385 | + rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); | |
| 121386 | + }else{ | |
| 121387 | + rc = fts3InsertData(p, apVal, pRowid); | |
| 121388 | + bInsertDone = 1; | |
| 121389 | + } | |
| 121390 | + } | |
| 121391 | + } | |
| 121392 | + if( rc!=SQLITE_OK ){ | |
| 121393 | + sqlite3_free(aSzIns); | |
| 121394 | + return rc; | |
| 121395 | + } | |
| 120252 | 121396 | |
| 120253 | 121397 | /* If this is a DELETE or UPDATE operation, remove the old record. */ |
| 120254 | 121398 | if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 120255 | - int isEmpty = 0; | |
| 120256 | - rc = fts3IsEmpty(p, apVal, &isEmpty); | |
| 120257 | - if( rc==SQLITE_OK ){ | |
| 120258 | - if( isEmpty ){ | |
| 120259 | - /* Deleting this row means the whole table is empty. In this case | |
| 120260 | - ** delete the contents of all three tables and throw away any | |
| 120261 | - ** data in the pendingTerms hash table. | |
| 120262 | - */ | |
| 120263 | - rc = fts3DeleteAll(p); | |
| 120264 | - }else{ | |
| 120265 | - isRemove = 1; | |
| 120266 | - iRemove = sqlite3_value_int64(apVal[0]); | |
| 120267 | - rc = fts3PendingTermsDocid(p, iRemove); | |
| 120268 | - fts3DeleteTerms(&rc, p, apVal, aSzDel); | |
| 120269 | - fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal); | |
| 120270 | - if( p->bHasDocsize ){ | |
| 120271 | - fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal); | |
| 120272 | - } | |
| 120273 | - nChng--; | |
| 120274 | - } | |
| 120275 | - } | |
| 120276 | - }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){ | |
| 120277 | - sqlite3_free(aSzIns); | |
| 120278 | - return fts3SpecialInsert(p, apVal[p->nColumn+2]); | |
| 121399 | + assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); | |
| 121400 | + rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); | |
| 121401 | + isRemove = 1; | |
| 121402 | + iRemove = sqlite3_value_int64(apVal[0]); | |
| 120279 | 121403 | } |
| 120280 | 121404 | |
| 120281 | 121405 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 120282 | 121406 | if( nArg>1 && rc==SQLITE_OK ){ |
| 120283 | - rc = fts3InsertData(p, apVal, pRowid); | |
| 121407 | + if( bInsertDone==0 ){ | |
| 121408 | + rc = fts3InsertData(p, apVal, pRowid); | |
| 121409 | + if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB; | |
| 121410 | + } | |
| 120284 | 121411 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ |
| 120285 | 121412 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 120286 | 121413 | } |
| 120287 | 121414 | if( rc==SQLITE_OK ){ |
| 120288 | 121415 | rc = fts3InsertTerms(p, apVal, aSzIns); |
| @@ -120742,11 +121869,11 @@ | ||
| 120742 | 121869 | SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; |
| 120743 | 121870 | char *pCsr; |
| 120744 | 121871 | |
| 120745 | 121872 | pPhrase->nToken = pExpr->pPhrase->nToken; |
| 120746 | 121873 | |
| 120747 | - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol); | |
| 121874 | + pCsr = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->pCsr->iPrevId, p->iCol); | |
| 120748 | 121875 | if( pCsr ){ |
| 120749 | 121876 | int iFirst = 0; |
| 120750 | 121877 | pPhrase->pList = pCsr; |
| 120751 | 121878 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 120752 | 121879 | pPhrase->pHead = pCsr; |
| @@ -121215,11 +122342,11 @@ | ||
| 121215 | 122342 | for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0; |
| 121216 | 122343 | |
| 121217 | 122344 | if( pExpr->aDoclist ){ |
| 121218 | 122345 | char *pCsr; |
| 121219 | 122346 | |
| 121220 | - pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1); | |
| 122347 | + pCsr = sqlite3Fts3FindPositions(p->pCursor, pExpr, p->pCursor->iPrevId, -1); | |
| 121221 | 122348 | if( pCsr ){ |
| 121222 | 122349 | fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0); |
| 121223 | 122350 | } |
| 121224 | 122351 | } |
| 121225 | 122352 | |
| @@ -121287,11 +122414,11 @@ | ||
| 121287 | 122414 | pStmt = *ppStmt; |
| 121288 | 122415 | assert( sqlite3_data_count(pStmt)==1 ); |
| 121289 | 122416 | |
| 121290 | 122417 | a = sqlite3_column_blob(pStmt, 0); |
| 121291 | 122418 | a += sqlite3Fts3GetVarint(a, &nDoc); |
| 121292 | - if( nDoc==0 ) return SQLITE_CORRUPT; | |
| 122419 | + if( nDoc==0 ) return SQLITE_CORRUPT_VTAB; | |
| 121293 | 122420 | *pnDoc = (u32)nDoc; |
| 121294 | 122421 | |
| 121295 | 122422 | if( paLen ) *paLen = a; |
| 121296 | 122423 | return SQLITE_OK; |
| 121297 | 122424 | } |
| @@ -121382,11 +122509,11 @@ | ||
| 121382 | 122509 | (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); |
| 121383 | 122510 | for(i=0; i<pInfo->nPhrase; i++){ |
| 121384 | 122511 | LcsIterator *pIter = &aIter[i]; |
| 121385 | 122512 | nToken -= pIter->pExpr->pPhrase->nToken; |
| 121386 | 122513 | pIter->iPosOffset = nToken; |
| 121387 | - pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1); | |
| 122514 | + pIter->pRead = sqlite3Fts3FindPositions(pCsr,pIter->pExpr,pCsr->iPrevId,-1); | |
| 121388 | 122515 | if( pIter->pRead ){ |
| 121389 | 122516 | pIter->iPos = pIter->iPosOffset; |
| 121390 | 122517 | fts3LcsIteratorAdvance(&aIter[i]); |
| 121391 | 122518 | }else{ |
| 121392 | 122519 | pIter->iCol = LCS_ITERATOR_FINISHED; |
| @@ -121735,10 +122862,11 @@ | ||
| 121735 | 122862 | int iPos; /* Position just read from pList */ |
| 121736 | 122863 | int iOff; /* Offset of this term from read positions */ |
| 121737 | 122864 | }; |
| 121738 | 122865 | |
| 121739 | 122866 | struct TermOffsetCtx { |
| 122867 | + Fts3Cursor *pCsr; | |
| 121740 | 122868 | int iCol; /* Column of table to populate aTerm for */ |
| 121741 | 122869 | int iTerm; |
| 121742 | 122870 | sqlite3_int64 iDocid; |
| 121743 | 122871 | TermOffset *aTerm; |
| 121744 | 122872 | }; |
| @@ -121752,11 +122880,11 @@ | ||
| 121752 | 122880 | int iTerm; /* For looping through nTerm phrase terms */ |
| 121753 | 122881 | char *pList; /* Pointer to position list for phrase */ |
| 121754 | 122882 | int iPos = 0; /* First position in position-list */ |
| 121755 | 122883 | |
| 121756 | 122884 | UNUSED_PARAMETER(iPhrase); |
| 121757 | - pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol); | |
| 122885 | + pList = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->iDocid, p->iCol); | |
| 121758 | 122886 | nTerm = pExpr->pPhrase->nToken; |
| 121759 | 122887 | if( pList ){ |
| 121760 | 122888 | fts3GetDeltaPosition(&pList, &iPos); |
| 121761 | 122889 | assert( iPos>=0 ); |
| 121762 | 122890 | } |
| @@ -121805,10 +122933,11 @@ | ||
| 121805 | 122933 | if( 0==sCtx.aTerm ){ |
| 121806 | 122934 | rc = SQLITE_NOMEM; |
| 121807 | 122935 | goto offsets_out; |
| 121808 | 122936 | } |
| 121809 | 122937 | sCtx.iDocid = pCsr->iPrevId; |
| 122938 | + sCtx.pCsr = pCsr; | |
| 121810 | 122939 | |
| 121811 | 122940 | /* Loop through the table columns, appending offset information to |
| 121812 | 122941 | ** string-buffer res for each column. |
| 121813 | 122942 | */ |
| 121814 | 122943 | for(iCol=0; iCol<pTab->nColumn; iCol++){ |
| @@ -121880,11 +123009,11 @@ | ||
| 121880 | 123009 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 121881 | 123010 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 121882 | 123011 | ); |
| 121883 | 123012 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 121884 | 123013 | }else if( rc==SQLITE_DONE ){ |
| 121885 | - rc = SQLITE_CORRUPT; | |
| 123014 | + rc = SQLITE_CORRUPT_VTAB; | |
| 121886 | 123015 | } |
| 121887 | 123016 | } |
| 121888 | 123017 | } |
| 121889 | 123018 | if( rc==SQLITE_DONE ){ |
| 121890 | 123019 | rc = SQLITE_OK; |
| @@ -122468,29 +123597,29 @@ | ||
| 122468 | 123597 | ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. |
| 122469 | 123598 | */ |
| 122470 | 123599 | if( pNode && iNode==1 ){ |
| 122471 | 123600 | pRtree->iDepth = readInt16(pNode->zData); |
| 122472 | 123601 | if( pRtree->iDepth>RTREE_MAX_DEPTH ){ |
| 122473 | - rc = SQLITE_CORRUPT; | |
| 123602 | + rc = SQLITE_CORRUPT_VTAB; | |
| 122474 | 123603 | } |
| 122475 | 123604 | } |
| 122476 | 123605 | |
| 122477 | 123606 | /* If no error has occurred so far, check if the "number of entries" |
| 122478 | 123607 | ** field on the node is too large. If so, set the return code to |
| 122479 | - ** SQLITE_CORRUPT. | |
| 123608 | + ** SQLITE_CORRUPT_VTAB. | |
| 122480 | 123609 | */ |
| 122481 | 123610 | if( pNode && rc==SQLITE_OK ){ |
| 122482 | 123611 | if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ |
| 122483 | - rc = SQLITE_CORRUPT; | |
| 123612 | + rc = SQLITE_CORRUPT_VTAB; | |
| 122484 | 123613 | } |
| 122485 | 123614 | } |
| 122486 | 123615 | |
| 122487 | 123616 | if( rc==SQLITE_OK ){ |
| 122488 | 123617 | if( pNode!=0 ){ |
| 122489 | 123618 | nodeHashInsert(pRtree, pNode); |
| 122490 | 123619 | }else{ |
| 122491 | - rc = SQLITE_CORRUPT; | |
| 123620 | + rc = SQLITE_CORRUPT_VTAB; | |
| 122492 | 123621 | } |
| 122493 | 123622 | *ppNode = pNode; |
| 122494 | 123623 | }else{ |
| 122495 | 123624 | sqlite3_free(pNode); |
| 122496 | 123625 | *ppNode = 0; |
| @@ -123013,11 +124142,11 @@ | ||
| 123013 | 124142 | if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ |
| 123014 | 124143 | *piIndex = ii; |
| 123015 | 124144 | return SQLITE_OK; |
| 123016 | 124145 | } |
| 123017 | 124146 | } |
| 123018 | - return SQLITE_CORRUPT; | |
| 124147 | + return SQLITE_CORRUPT_VTAB; | |
| 123019 | 124148 | } |
| 123020 | 124149 | |
| 123021 | 124150 | /* |
| 123022 | 124151 | ** Return the index of the cell containing a pointer to node pNode |
| 123023 | 124152 | ** in its parent. If pNode is the root node, return -1. |
| @@ -123608,11 +124737,11 @@ | ||
| 123608 | 124737 | RtreeNode *pParent = p->pParent; |
| 123609 | 124738 | RtreeCell cell; |
| 123610 | 124739 | int iCell; |
| 123611 | 124740 | |
| 123612 | 124741 | if( nodeParentIndex(pRtree, p, &iCell) ){ |
| 123613 | - return SQLITE_CORRUPT; | |
| 124742 | + return SQLITE_CORRUPT_VTAB; | |
| 123614 | 124743 | } |
| 123615 | 124744 | |
| 123616 | 124745 | nodeGetCell(pRtree, pParent, iCell, &cell); |
| 123617 | 124746 | if( !cellContains(pRtree, &cell, pCell) ){ |
| 123618 | 124747 | cellUnion(pRtree, &cell, pCell); |
| @@ -124280,11 +125409,11 @@ | ||
| 124280 | 125409 | rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); |
| 124281 | 125410 | } |
| 124282 | 125411 | } |
| 124283 | 125412 | rc = sqlite3_reset(pRtree->pReadParent); |
| 124284 | 125413 | if( rc==SQLITE_OK ) rc = rc2; |
| 124285 | - if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT; | |
| 125414 | + if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; | |
| 124286 | 125415 | pChild = pChild->pParent; |
| 124287 | 125416 | } |
| 124288 | 125417 | return rc; |
| 124289 | 125418 | } |
| 124290 | 125419 | |
| @@ -124575,10 +125704,94 @@ | ||
| 124575 | 125704 | sqlite3_step(pRtree->pWriteRowid); |
| 124576 | 125705 | rc = sqlite3_reset(pRtree->pWriteRowid); |
| 124577 | 125706 | *piRowid = sqlite3_last_insert_rowid(pRtree->db); |
| 124578 | 125707 | return rc; |
| 124579 | 125708 | } |
| 125709 | + | |
| 125710 | +/* | |
| 125711 | +** Remove the entry with rowid=iDelete from the r-tree structure. | |
| 125712 | +*/ | |
| 125713 | +static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ | |
| 125714 | + int rc; /* Return code */ | |
| 125715 | + RtreeNode *pLeaf; /* Leaf node containing record iDelete */ | |
| 125716 | + int iCell; /* Index of iDelete cell in pLeaf */ | |
| 125717 | + RtreeNode *pRoot; /* Root node of rtree structure */ | |
| 125718 | + | |
| 125719 | + | |
| 125720 | + /* Obtain a reference to the root node to initialise Rtree.iDepth */ | |
| 125721 | + rc = nodeAcquire(pRtree, 1, 0, &pRoot); | |
| 125722 | + | |
| 125723 | + /* Obtain a reference to the leaf node that contains the entry | |
| 125724 | + ** about to be deleted. | |
| 125725 | + */ | |
| 125726 | + if( rc==SQLITE_OK ){ | |
| 125727 | + rc = findLeafNode(pRtree, iDelete, &pLeaf); | |
| 125728 | + } | |
| 125729 | + | |
| 125730 | + /* Delete the cell in question from the leaf node. */ | |
| 125731 | + if( rc==SQLITE_OK ){ | |
| 125732 | + int rc2; | |
| 125733 | + rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); | |
| 125734 | + if( rc==SQLITE_OK ){ | |
| 125735 | + rc = deleteCell(pRtree, pLeaf, iCell, 0); | |
| 125736 | + } | |
| 125737 | + rc2 = nodeRelease(pRtree, pLeaf); | |
| 125738 | + if( rc==SQLITE_OK ){ | |
| 125739 | + rc = rc2; | |
| 125740 | + } | |
| 125741 | + } | |
| 125742 | + | |
| 125743 | + /* Delete the corresponding entry in the <rtree>_rowid table. */ | |
| 125744 | + if( rc==SQLITE_OK ){ | |
| 125745 | + sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); | |
| 125746 | + sqlite3_step(pRtree->pDeleteRowid); | |
| 125747 | + rc = sqlite3_reset(pRtree->pDeleteRowid); | |
| 125748 | + } | |
| 125749 | + | |
| 125750 | + /* Check if the root node now has exactly one child. If so, remove | |
| 125751 | + ** it, schedule the contents of the child for reinsertion and | |
| 125752 | + ** reduce the tree height by one. | |
| 125753 | + ** | |
| 125754 | + ** This is equivalent to copying the contents of the child into | |
| 125755 | + ** the root node (the operation that Gutman's paper says to perform | |
| 125756 | + ** in this scenario). | |
| 125757 | + */ | |
| 125758 | + if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ | |
| 125759 | + int rc2; | |
| 125760 | + RtreeNode *pChild; | |
| 125761 | + i64 iChild = nodeGetRowid(pRtree, pRoot, 0); | |
| 125762 | + rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); | |
| 125763 | + if( rc==SQLITE_OK ){ | |
| 125764 | + rc = removeNode(pRtree, pChild, pRtree->iDepth-1); | |
| 125765 | + } | |
| 125766 | + rc2 = nodeRelease(pRtree, pChild); | |
| 125767 | + if( rc==SQLITE_OK ) rc = rc2; | |
| 125768 | + if( rc==SQLITE_OK ){ | |
| 125769 | + pRtree->iDepth--; | |
| 125770 | + writeInt16(pRoot->zData, pRtree->iDepth); | |
| 125771 | + pRoot->isDirty = 1; | |
| 125772 | + } | |
| 125773 | + } | |
| 125774 | + | |
| 125775 | + /* Re-insert the contents of any underfull nodes removed from the tree. */ | |
| 125776 | + for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ | |
| 125777 | + if( rc==SQLITE_OK ){ | |
| 125778 | + rc = reinsertNodeContent(pRtree, pLeaf); | |
| 125779 | + } | |
| 125780 | + pRtree->pDeleted = pLeaf->pNext; | |
| 125781 | + sqlite3_free(pLeaf); | |
| 125782 | + } | |
| 125783 | + | |
| 125784 | + /* Release the reference to the root node. */ | |
| 125785 | + if( rc==SQLITE_OK ){ | |
| 125786 | + rc = nodeRelease(pRtree, pRoot); | |
| 125787 | + }else{ | |
| 125788 | + nodeRelease(pRtree, pRoot); | |
| 125789 | + } | |
| 125790 | + | |
| 125791 | + return rc; | |
| 125792 | +} | |
| 124580 | 125793 | |
| 124581 | 125794 | /* |
| 124582 | 125795 | ** The xUpdate method for rtree module virtual tables. |
| 124583 | 125796 | */ |
| 124584 | 125797 | static int rtreeUpdate( |
| @@ -124587,107 +125800,29 @@ | ||
| 124587 | 125800 | sqlite3_value **azData, |
| 124588 | 125801 | sqlite_int64 *pRowid |
| 124589 | 125802 | ){ |
| 124590 | 125803 | Rtree *pRtree = (Rtree *)pVtab; |
| 124591 | 125804 | int rc = SQLITE_OK; |
| 125805 | + RtreeCell cell; /* New cell to insert if nData>1 */ | |
| 125806 | + int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ | |
| 124592 | 125807 | |
| 124593 | 125808 | rtreeReference(pRtree); |
| 124594 | - | |
| 124595 | 125809 | assert(nData>=1); |
| 124596 | 125810 | |
| 124597 | - /* If azData[0] is not an SQL NULL value, it is the rowid of a | |
| 124598 | - ** record to delete from the r-tree table. The following block does | |
| 124599 | - ** just that. | |
| 124600 | - */ | |
| 124601 | - if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ | |
| 124602 | - i64 iDelete; /* The rowid to delete */ | |
| 124603 | - RtreeNode *pLeaf; /* Leaf node containing record iDelete */ | |
| 124604 | - int iCell; /* Index of iDelete cell in pLeaf */ | |
| 124605 | - RtreeNode *pRoot; | |
| 124606 | - | |
| 124607 | - /* Obtain a reference to the root node to initialise Rtree.iDepth */ | |
| 124608 | - rc = nodeAcquire(pRtree, 1, 0, &pRoot); | |
| 124609 | - | |
| 124610 | - /* Obtain a reference to the leaf node that contains the entry | |
| 124611 | - ** about to be deleted. | |
| 124612 | - */ | |
| 124613 | - if( rc==SQLITE_OK ){ | |
| 124614 | - iDelete = sqlite3_value_int64(azData[0]); | |
| 124615 | - rc = findLeafNode(pRtree, iDelete, &pLeaf); | |
| 124616 | - } | |
| 124617 | - | |
| 124618 | - /* Delete the cell in question from the leaf node. */ | |
| 124619 | - if( rc==SQLITE_OK ){ | |
| 124620 | - int rc2; | |
| 124621 | - rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); | |
| 124622 | - if( rc==SQLITE_OK ){ | |
| 124623 | - rc = deleteCell(pRtree, pLeaf, iCell, 0); | |
| 124624 | - } | |
| 124625 | - rc2 = nodeRelease(pRtree, pLeaf); | |
| 124626 | - if( rc==SQLITE_OK ){ | |
| 124627 | - rc = rc2; | |
| 124628 | - } | |
| 124629 | - } | |
| 124630 | - | |
| 124631 | - /* Delete the corresponding entry in the <rtree>_rowid table. */ | |
| 124632 | - if( rc==SQLITE_OK ){ | |
| 124633 | - sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); | |
| 124634 | - sqlite3_step(pRtree->pDeleteRowid); | |
| 124635 | - rc = sqlite3_reset(pRtree->pDeleteRowid); | |
| 124636 | - } | |
| 124637 | - | |
| 124638 | - /* Check if the root node now has exactly one child. If so, remove | |
| 124639 | - ** it, schedule the contents of the child for reinsertion and | |
| 124640 | - ** reduce the tree height by one. | |
| 124641 | - ** | |
| 124642 | - ** This is equivalent to copying the contents of the child into | |
| 124643 | - ** the root node (the operation that Gutman's paper says to perform | |
| 124644 | - ** in this scenario). | |
| 124645 | - */ | |
| 124646 | - if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ | |
| 124647 | - int rc2; | |
| 124648 | - RtreeNode *pChild; | |
| 124649 | - i64 iChild = nodeGetRowid(pRtree, pRoot, 0); | |
| 124650 | - rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); | |
| 124651 | - if( rc==SQLITE_OK ){ | |
| 124652 | - rc = removeNode(pRtree, pChild, pRtree->iDepth-1); | |
| 124653 | - } | |
| 124654 | - rc2 = nodeRelease(pRtree, pChild); | |
| 124655 | - if( rc==SQLITE_OK ) rc = rc2; | |
| 124656 | - if( rc==SQLITE_OK ){ | |
| 124657 | - pRtree->iDepth--; | |
| 124658 | - writeInt16(pRoot->zData, pRtree->iDepth); | |
| 124659 | - pRoot->isDirty = 1; | |
| 124660 | - } | |
| 124661 | - } | |
| 124662 | - | |
| 124663 | - /* Re-insert the contents of any underfull nodes removed from the tree. */ | |
| 124664 | - for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ | |
| 124665 | - if( rc==SQLITE_OK ){ | |
| 124666 | - rc = reinsertNodeContent(pRtree, pLeaf); | |
| 124667 | - } | |
| 124668 | - pRtree->pDeleted = pLeaf->pNext; | |
| 124669 | - sqlite3_free(pLeaf); | |
| 124670 | - } | |
| 124671 | - | |
| 124672 | - /* Release the reference to the root node. */ | |
| 124673 | - if( rc==SQLITE_OK ){ | |
| 124674 | - rc = nodeRelease(pRtree, pRoot); | |
| 124675 | - }else{ | |
| 124676 | - nodeRelease(pRtree, pRoot); | |
| 124677 | - } | |
| 124678 | - } | |
| 124679 | - | |
| 124680 | - /* If the azData[] array contains more than one element, elements | |
| 124681 | - ** (azData[2]..azData[argc-1]) contain a new record to insert into | |
| 124682 | - ** the r-tree structure. | |
| 124683 | - */ | |
| 124684 | - if( rc==SQLITE_OK && nData>1 ){ | |
| 124685 | - /* Insert a new record into the r-tree */ | |
| 124686 | - RtreeCell cell; | |
| 124687 | - int ii; | |
| 124688 | - RtreeNode *pLeaf; | |
| 125811 | + /* Constraint handling. A write operation on an r-tree table may return | |
| 125812 | + ** SQLITE_CONSTRAINT for two reasons: | |
| 125813 | + ** | |
| 125814 | + ** 1. A duplicate rowid value, or | |
| 125815 | + ** 2. The supplied data violates the "x2>=x1" constraint. | |
| 125816 | + ** | |
| 125817 | + ** In the first case, if the conflict-handling mode is REPLACE, then | |
| 125818 | + ** the conflicting row can be removed before proceeding. In the second | |
| 125819 | + ** case, SQLITE_CONSTRAINT must be returned regardless of the | |
| 125820 | + ** conflict-handling mode specified by the user. | |
| 125821 | + */ | |
| 125822 | + if( nData>1 ){ | |
| 125823 | + int ii; | |
| 124689 | 125824 | |
| 124690 | 125825 | /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ |
| 124691 | 125826 | assert( nData==(pRtree->nDim*2 + 3) ); |
| 124692 | 125827 | if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ |
| 124693 | 125828 | for(ii=0; ii<(pRtree->nDim*2); ii+=2){ |
| @@ -124707,22 +125842,53 @@ | ||
| 124707 | 125842 | goto constraint; |
| 124708 | 125843 | } |
| 124709 | 125844 | } |
| 124710 | 125845 | } |
| 124711 | 125846 | |
| 124712 | - /* Figure out the rowid of the new row. */ | |
| 124713 | - if( sqlite3_value_type(azData[2])==SQLITE_NULL ){ | |
| 124714 | - rc = newRowid(pRtree, &cell.iRowid); | |
| 124715 | - }else{ | |
| 125847 | + /* If a rowid value was supplied, check if it is already present in | |
| 125848 | + ** the table. If so, the constraint has failed. */ | |
| 125849 | + if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ | |
| 124716 | 125850 | cell.iRowid = sqlite3_value_int64(azData[2]); |
| 124717 | - sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); | |
| 124718 | - if( SQLITE_ROW==sqlite3_step(pRtree->pReadRowid) ){ | |
| 124719 | - sqlite3_reset(pRtree->pReadRowid); | |
| 124720 | - rc = SQLITE_CONSTRAINT; | |
| 124721 | - goto constraint; | |
| 125851 | + if( sqlite3_value_type(azData[0])==SQLITE_NULL | |
| 125852 | + || sqlite3_value_int64(azData[0])!=cell.iRowid | |
| 125853 | + ){ | |
| 125854 | + int steprc; | |
| 125855 | + sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); | |
| 125856 | + steprc = sqlite3_step(pRtree->pReadRowid); | |
| 125857 | + rc = sqlite3_reset(pRtree->pReadRowid); | |
| 125858 | + if( SQLITE_ROW==steprc ){ | |
| 125859 | + if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ | |
| 125860 | + rc = rtreeDeleteRowid(pRtree, cell.iRowid); | |
| 125861 | + }else{ | |
| 125862 | + rc = SQLITE_CONSTRAINT; | |
| 125863 | + goto constraint; | |
| 125864 | + } | |
| 125865 | + } | |
| 124722 | 125866 | } |
| 124723 | - rc = sqlite3_reset(pRtree->pReadRowid); | |
| 125867 | + bHaveRowid = 1; | |
| 125868 | + } | |
| 125869 | + } | |
| 125870 | + | |
| 125871 | + /* If azData[0] is not an SQL NULL value, it is the rowid of a | |
| 125872 | + ** record to delete from the r-tree table. The following block does | |
| 125873 | + ** just that. | |
| 125874 | + */ | |
| 125875 | + if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ | |
| 125876 | + rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); | |
| 125877 | + } | |
| 125878 | + | |
| 125879 | + /* If the azData[] array contains more than one element, elements | |
| 125880 | + ** (azData[2]..azData[argc-1]) contain a new record to insert into | |
| 125881 | + ** the r-tree structure. | |
| 125882 | + */ | |
| 125883 | + if( rc==SQLITE_OK && nData>1 ){ | |
| 125884 | + /* Insert the new record into the r-tree */ | |
| 125885 | + RtreeNode *pLeaf; | |
| 125886 | + | |
| 125887 | + /* Figure out the rowid of the new row. */ | |
| 125888 | + if( bHaveRowid==0 ){ | |
| 125889 | + rc = newRowid(pRtree, &cell.iRowid); | |
| 124724 | 125890 | } |
| 124725 | 125891 | *pRowid = cell.iRowid; |
| 124726 | 125892 | |
| 124727 | 125893 | if( rc==SQLITE_OK ){ |
| 124728 | 125894 | rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); |
| @@ -124958,10 +126124,12 @@ | ||
| 124958 | 126124 | int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; |
| 124959 | 126125 | if( aErrMsg[iErr] ){ |
| 124960 | 126126 | *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); |
| 124961 | 126127 | return SQLITE_ERROR; |
| 124962 | 126128 | } |
| 126129 | + | |
| 126130 | + sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); | |
| 124963 | 126131 | |
| 124964 | 126132 | /* Allocate the sqlite3_vtab structure */ |
| 124965 | 126133 | nDb = strlen(argv[1]); |
| 124966 | 126134 | nName = strlen(argv[2]); |
| 124967 | 126135 | pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); |
| 124968 | 126136 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | /****************************************************************************** |
| 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | ** version 3.7.6. By combining all the individual C code files into this |
| 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | ** translation unit. |
| @@ -648,13 +648,13 @@ | |
| 648 | ** |
| 649 | ** See also: [sqlite3_libversion()], |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.6" |
| 654 | #define SQLITE_VERSION_NUMBER 3007006 |
| 655 | #define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -916,11 +916,12 @@ | |
| 916 | ** Many SQLite functions return an integer result code from the set shown |
| 917 | ** here in order to indicates success or failure. |
| 918 | ** |
| 919 | ** New error codes may be added in future versions of SQLite. |
| 920 | ** |
| 921 | ** See also: [SQLITE_IOERR_READ | extended result codes] |
| 922 | */ |
| 923 | #define SQLITE_OK 0 /* Successful result */ |
| 924 | /* beginning-of-error-codes */ |
| 925 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 926 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -993,28 +994,31 @@ | |
| 993 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 994 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 995 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 996 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 997 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 998 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 999 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 1000 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 1001 | |
| 1002 | /* |
| 1003 | ** CAPI3REF: Flags For File Open Operations |
| 1004 | ** |
| 1005 | ** These bit values are intended for use in the |
| 1006 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 1007 | ** in the 4th parameter to the xOpen method of the |
| 1008 | ** [sqlite3_vfs] object. |
| 1009 | */ |
| 1010 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 1011 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 1012 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 1013 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 1014 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 1015 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 1016 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 1017 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 1018 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 1019 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 1020 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -1121,21 +1125,22 @@ | |
| 1121 | }; |
| 1122 | |
| 1123 | /* |
| 1124 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 1125 | ** |
| 1126 | ** Every file opened by the [sqlite3_vfs] xOpen method populates an |
| 1127 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 1128 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 1129 | ** This object defines the methods used to perform various operations |
| 1130 | ** against the open file represented by the [sqlite3_file] object. |
| 1131 | ** |
| 1132 | ** If the xOpen method sets the sqlite3_file.pMethods element |
| 1133 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 1134 | ** may be invoked even if the xOpen reported that it failed. The |
| 1135 | ** only way to prevent a call to xClose following a failed xOpen |
| 1136 | ** is for the xOpen to set the sqlite3_file.pMethods element to NULL. |
| 1137 | ** |
| 1138 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 1139 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 1140 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 1141 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -1300,10 +1305,11 @@ | |
| 1300 | */ |
| 1301 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 1302 | |
| 1303 | /* |
| 1304 | ** CAPI3REF: OS Interface Object |
| 1305 | ** |
| 1306 | ** An instance of the sqlite3_vfs object defines the interface between |
| 1307 | ** the SQLite core and the underlying operating system. The "vfs" |
| 1308 | ** in the name of the object stands for "virtual file system". |
| 1309 | ** |
| @@ -1332,10 +1338,11 @@ | |
| 1332 | ** object once the object has been registered. |
| 1333 | ** |
| 1334 | ** The zName field holds the name of the VFS module. The name must |
| 1335 | ** be unique across all VFS modules. |
| 1336 | ** |
| 1337 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 1338 | ** is either a NULL pointer or string obtained |
| 1339 | ** from xFullPathname() with an optional suffix added. |
| 1340 | ** ^If a suffix is added to the zFilename parameter, it will |
| 1341 | ** consist of a single "-" character followed by no more than |
| @@ -1409,10 +1416,11 @@ | |
| 1409 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 1410 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 1411 | ** element will be valid after xOpen returns regardless of the success |
| 1412 | ** or failure of the xOpen call. |
| 1413 | ** |
| 1414 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 1415 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 1416 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 1417 | ** to test whether a file is at least readable. The file can be a |
| 1418 | ** directory. |
| @@ -1655,13 +1663,13 @@ | |
| 1655 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1656 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1657 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1658 | ** |
| 1659 | ** The first argument to sqlite3_config() is an integer |
| 1660 | ** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines |
| 1661 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1662 | ** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] |
| 1663 | ** in the first argument. |
| 1664 | ** |
| 1665 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1666 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1667 | ** then this routine returns a non-zero [error code]. |
| @@ -1767,10 +1775,11 @@ | |
| 1767 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1768 | }; |
| 1769 | |
| 1770 | /* |
| 1771 | ** CAPI3REF: Configuration Options |
| 1772 | ** |
| 1773 | ** These constants are the available integer configuration options that |
| 1774 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1775 | ** |
| 1776 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1779,11 +1788,11 @@ | |
| 1779 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1780 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1781 | ** is invoked. |
| 1782 | ** |
| 1783 | ** <dl> |
| 1784 | ** <dt>SQLITE_CONFIG_SINGLETHREAD</dt> |
| 1785 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1786 | ** [threading mode] to Single-thread. In other words, it disables |
| 1787 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1788 | ** by a single thread. ^If SQLite is compiled with |
| 1789 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1790,11 +1799,11 @@ | |
| 1790 | ** it is not possible to change the [threading mode] from its default |
| 1791 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1792 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1793 | ** configuration option.</dd> |
| 1794 | ** |
| 1795 | ** <dt>SQLITE_CONFIG_MULTITHREAD</dt> |
| 1796 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1797 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1798 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1799 | ** The application is responsible for serializing access to |
| 1800 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1804,11 +1813,11 @@ | |
| 1804 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1805 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1806 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1807 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1808 | ** |
| 1809 | ** <dt>SQLITE_CONFIG_SERIALIZED</dt> |
| 1810 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1811 | ** [threading mode] to Serialized. In other words, this option enables |
| 1812 | ** all mutexes including the recursive |
| 1813 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1814 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1820,27 +1829,27 @@ | |
| 1820 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1821 | ** it is not possible to set the Serialized [threading mode] and |
| 1822 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1823 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1824 | ** |
| 1825 | ** <dt>SQLITE_CONFIG_MALLOC</dt> |
| 1826 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1827 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1828 | ** alternative low-level memory allocation routines to be used in place of |
| 1829 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1830 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1831 | ** before the [sqlite3_config()] call returns.</dd> |
| 1832 | ** |
| 1833 | ** <dt>SQLITE_CONFIG_GETMALLOC</dt> |
| 1834 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1835 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1836 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1837 | ** This option can be used to overload the default memory allocation |
| 1838 | ** routines with a wrapper that simulations memory allocation failure or |
| 1839 | ** tracks memory usage, for example. </dd> |
| 1840 | ** |
| 1841 | ** <dt>SQLITE_CONFIG_MEMSTATUS</dt> |
| 1842 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1843 | ** boolean, which enables or disables the collection of memory allocation |
| 1844 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1845 | ** following SQLite interfaces become non-operational: |
| 1846 | ** <ul> |
| @@ -1852,11 +1861,11 @@ | |
| 1852 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1853 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1854 | ** allocation statistics are disabled by default. |
| 1855 | ** </dd> |
| 1856 | ** |
| 1857 | ** <dt>SQLITE_CONFIG_SCRATCH</dt> |
| 1858 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1859 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1860 | ** aligned memory buffer from which the scratch allocations will be |
| 1861 | ** drawn, the size of each scratch allocation (sz), |
| 1862 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1868,11 +1877,11 @@ | |
| 1868 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1869 | ** times the database page size. ^If SQLite needs needs additional |
| 1870 | ** scratch memory beyond what is provided by this configuration option, then |
| 1871 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1872 | ** |
| 1873 | ** <dt>SQLITE_CONFIG_PAGECACHE</dt> |
| 1874 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1875 | ** the database page cache with the default page cache implemenation. |
| 1876 | ** This configuration should not be used if an application-define page |
| 1877 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1878 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1889,11 +1898,11 @@ | |
| 1889 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1890 | ** The pointer in the first argument must |
| 1891 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1892 | ** will be undefined.</dd> |
| 1893 | ** |
| 1894 | ** <dt>SQLITE_CONFIG_HEAP</dt> |
| 1895 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1896 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1897 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1898 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1899 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1906,11 +1915,11 @@ | |
| 1906 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1907 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1908 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1909 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1910 | ** |
| 1911 | ** <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1912 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1913 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1914 | ** alternative low-level mutex routines to be used in place |
| 1915 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1916 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1918,11 +1927,11 @@ | |
| 1918 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1919 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1920 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1921 | ** return [SQLITE_ERROR].</dd> |
| 1922 | ** |
| 1923 | ** <dt>SQLITE_CONFIG_GETMUTEX</dt> |
| 1924 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1925 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1926 | ** [sqlite3_mutex_methods] |
| 1927 | ** structure is filled with the currently defined mutex routines.)^ |
| 1928 | ** This option can be used to overload the default mutex allocation |
| @@ -1931,32 +1940,32 @@ | |
| 1931 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1932 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1933 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1934 | ** return [SQLITE_ERROR].</dd> |
| 1935 | ** |
| 1936 | ** <dt>SQLITE_CONFIG_LOOKASIDE</dt> |
| 1937 | ** <dd> ^(This option takes two arguments that determine the default |
| 1938 | ** memory allocation for the lookaside memory allocator on each |
| 1939 | ** [database connection]. The first argument is the |
| 1940 | ** size of each lookaside buffer slot and the second is the number of |
| 1941 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1942 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1943 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1944 | ** configuration on individual connections.)^ </dd> |
| 1945 | ** |
| 1946 | ** <dt>SQLITE_CONFIG_PCACHE</dt> |
| 1947 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1948 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1949 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1950 | ** object and uses it for page cache memory allocations.</dd> |
| 1951 | ** |
| 1952 | ** <dt>SQLITE_CONFIG_GETPCACHE</dt> |
| 1953 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1954 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1955 | ** page cache implementation into that object.)^ </dd> |
| 1956 | ** |
| 1957 | ** <dt>SQLITE_CONFIG_LOG</dt> |
| 1958 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1959 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1960 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1961 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1962 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1970,10 +1979,22 @@ | |
| 1970 | ** The SQLite logging interface is not reentrant; the logger function |
| 1971 | ** supplied by the application must not invoke any SQLite interface. |
| 1972 | ** In a multi-threaded application, the application-defined logger |
| 1973 | ** function must be threadsafe. </dd> |
| 1974 | ** |
| 1975 | ** </dl> |
| 1976 | */ |
| 1977 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1978 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 1979 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1988,10 +2009,11 @@ | |
| 1988 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 1989 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 1990 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 1991 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 1992 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 1993 | |
| 1994 | /* |
| 1995 | ** CAPI3REF: Database Connection Configuration Options |
| 1996 | ** |
| 1997 | ** These constants are the available integer configuration options that |
| @@ -2073,17 +2095,21 @@ | |
| 2073 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 2074 | ** is another alias for the rowid. |
| 2075 | ** |
| 2076 | ** ^This routine returns the [rowid] of the most recent |
| 2077 | ** successful [INSERT] into the database from the [database connection] |
| 2078 | ** in the first argument. ^If no successful [INSERT]s |
| 2079 | ** have ever occurred on that database connection, zero is returned. |
| 2080 | ** |
| 2081 | ** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted |
| 2082 | ** row is returned by this routine as long as the trigger is running. |
| 2083 | ** But once the trigger terminates, the value returned by this routine |
| 2084 | ** reverts to the last value inserted before the trigger fired.)^ |
| 2085 | ** |
| 2086 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 2087 | ** successful [INSERT] and does not change the value returned by this |
| 2088 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 2089 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2742,10 +2768,13 @@ | |
| 2742 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2743 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2744 | ** to signal SQLite whether or not the action is permitted. See the |
| 2745 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2746 | ** information. |
| 2747 | */ |
| 2748 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2749 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2750 | |
| 2751 | /* |
| @@ -2864,11 +2893,11 @@ | |
| 2864 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2865 | |
| 2866 | /* |
| 2867 | ** CAPI3REF: Opening A New Database Connection |
| 2868 | ** |
| 2869 | ** ^These routines open an SQLite database file whose name is given by the |
| 2870 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2871 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2872 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2873 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2874 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2891,11 +2920,11 @@ | |
| 2891 | ** except that it accepts two additional parameters for additional control |
| 2892 | ** over the new database connection. ^(The flags parameter to |
| 2893 | ** sqlite3_open_v2() can take one of |
| 2894 | ** the following three values, optionally combined with the |
| 2895 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2896 | ** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ |
| 2897 | ** |
| 2898 | ** <dl> |
| 2899 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2900 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2901 | ** already exist, an error is returned.</dd>)^ |
| @@ -2910,13 +2939,12 @@ | |
| 2910 | ** it does not already exist. This is the behavior that is always used for |
| 2911 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2912 | ** </dl> |
| 2913 | ** |
| 2914 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2915 | ** combinations shown above or one of the combinations shown above combined |
| 2916 | ** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], |
| 2917 | ** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, |
| 2918 | ** then the behavior is undefined. |
| 2919 | ** |
| 2920 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2921 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2922 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2926,10 +2954,15 @@ | |
| 2926 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2927 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2928 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2929 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2930 | ** participate in [shared cache mode] even if it is enabled. |
| 2931 | ** |
| 2932 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2933 | ** is created for the connection. ^This in-memory database will vanish when |
| 2934 | ** the database connection is closed. Future versions of SQLite might |
| 2935 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2939,14 +2972,115 @@ | |
| 2939 | ** |
| 2940 | ** ^If the filename is an empty string, then a private, temporary |
| 2941 | ** on-disk database will be created. ^This private database will be |
| 2942 | ** automatically deleted as soon as the database connection is closed. |
| 2943 | ** |
| 2944 | ** ^The fourth parameter to sqlite3_open_v2() is the name of the |
| 2945 | ** [sqlite3_vfs] object that defines the operating system interface that |
| 2946 | ** the new database connection should use. ^If the fourth parameter is |
| 2947 | ** a NULL pointer then the default [sqlite3_vfs] object is used. |
| 2948 | ** |
| 2949 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 2950 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 2951 | ** codepage is currently defined. Filenames containing international |
| 2952 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2964,10 +3098,30 @@ | |
| 2964 | const char *filename, /* Database filename (UTF-8) */ |
| 2965 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 2966 | int flags, /* Flags */ |
| 2967 | const char *zVfs /* Name of VFS module to use */ |
| 2968 | ); |
| 2969 | |
| 2970 | /* |
| 2971 | ** CAPI3REF: Error Codes And Messages |
| 2972 | ** |
| 2973 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -3080,47 +3234,49 @@ | |
| 3080 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 3081 | ** The synopsis of the meanings of the various limits is shown below. |
| 3082 | ** Additional information is available at [limits | Limits in SQLite]. |
| 3083 | ** |
| 3084 | ** <dl> |
| 3085 | ** ^(<dt>SQLITE_LIMIT_LENGTH</dt> |
| 3086 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 3087 | ** |
| 3088 | ** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> |
| 3089 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 3090 | ** |
| 3091 | ** ^(<dt>SQLITE_LIMIT_COLUMN</dt> |
| 3092 | ** <dd>The maximum number of columns in a table definition or in the |
| 3093 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 3094 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 3095 | ** |
| 3096 | ** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 3097 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 3098 | ** |
| 3099 | ** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> |
| 3100 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 3101 | ** |
| 3102 | ** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> |
| 3103 | ** <dd>The maximum number of instructions in a virtual machine program |
| 3104 | ** used to implement an SQL statement. This limit is not currently |
| 3105 | ** enforced, though that might be added in some future release of |
| 3106 | ** SQLite.</dd>)^ |
| 3107 | ** |
| 3108 | ** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> |
| 3109 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 3110 | ** |
| 3111 | ** ^(<dt>SQLITE_LIMIT_ATTACHED</dt> |
| 3112 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 3113 | ** |
| 3114 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 3115 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 3116 | ** [GLOB] operators.</dd>)^ |
| 3117 | ** |
| 3118 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 3119 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 3120 | ** |
| 3121 | ** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 3122 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 3123 | ** </dl> |
| 3124 | */ |
| 3125 | #define SQLITE_LIMIT_LENGTH 0 |
| 3126 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -5151,10 +5307,15 @@ | |
| 5151 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 5152 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 5153 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 5154 | void **ppArg); |
| 5155 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 5156 | }; |
| 5157 | |
| 5158 | /* |
| 5159 | ** CAPI3REF: Virtual Table Indexing Information |
| 5160 | ** KEYWORDS: sqlite3_index_info |
| @@ -5965,11 +6126,11 @@ | |
| 5965 | ** |
| 5966 | ** ^This interface is used to retrieve runtime status information |
| 5967 | ** about the performance of SQLite, and optionally to reset various |
| 5968 | ** highwater marks. ^The first argument is an integer code for |
| 5969 | ** the specific parameter to measure. ^(Recognized integer codes |
| 5970 | ** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ |
| 5971 | ** ^The current value of the parameter is returned into *pCurrent. |
| 5972 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 5973 | ** resetFlag is true, then the highest record value is reset after |
| 5974 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 5975 | ** value. For those parameters |
| @@ -5992,82 +6153,84 @@ | |
| 5992 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 5993 | |
| 5994 | |
| 5995 | /* |
| 5996 | ** CAPI3REF: Status Parameters |
| 5997 | ** |
| 5998 | ** These integer constants designate various run-time status parameters |
| 5999 | ** that can be returned by [sqlite3_status()]. |
| 6000 | ** |
| 6001 | ** <dl> |
| 6002 | ** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> |
| 6003 | ** <dd>This parameter is the current amount of memory checked out |
| 6004 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 6005 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 6006 | ** and internal memory usage by the SQLite library. Scratch memory |
| 6007 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 6008 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 6009 | ** this parameter. The amount returned is the sum of the allocation |
| 6010 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 6011 | ** |
| 6012 | ** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> |
| 6013 | ** <dd>This parameter records the largest memory allocation request |
| 6014 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 6015 | ** internal equivalents). Only the value returned in the |
| 6016 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6017 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6018 | ** |
| 6019 | ** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> |
| 6020 | ** <dd>This parameter records the number of separate memory allocations |
| 6021 | ** currently checked out.</dd>)^ |
| 6022 | ** |
| 6023 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> |
| 6024 | ** <dd>This parameter returns the number of pages used out of the |
| 6025 | ** [pagecache memory allocator] that was configured using |
| 6026 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 6027 | ** value returned is in pages, not in bytes.</dd>)^ |
| 6028 | ** |
| 6029 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 6030 | ** <dd>This parameter returns the number of bytes of page cache |
| 6031 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 6032 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 6033 | ** returned value includes allocations that overflowed because they |
| 6034 | ** where too large (they were larger than the "sz" parameter to |
| 6035 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 6036 | ** no space was left in the page cache.</dd>)^ |
| 6037 | ** |
| 6038 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> |
| 6039 | ** <dd>This parameter records the largest memory allocation request |
| 6040 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 6041 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6042 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6043 | ** |
| 6044 | ** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> |
| 6045 | ** <dd>This parameter returns the number of allocations used out of the |
| 6046 | ** [scratch memory allocator] configured using |
| 6047 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 6048 | ** in bytes. Since a single thread may only have one scratch allocation |
| 6049 | ** outstanding at time, this parameter also reports the number of threads |
| 6050 | ** using scratch memory at the same time.</dd>)^ |
| 6051 | ** |
| 6052 | ** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> |
| 6053 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 6054 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 6055 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 6056 | ** returned include overflows because the requested allocation was too |
| 6057 | ** larger (that is, because the requested allocation was larger than the |
| 6058 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 6059 | ** slots were available. |
| 6060 | ** </dd>)^ |
| 6061 | ** |
| 6062 | ** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> |
| 6063 | ** <dd>This parameter records the largest memory allocation request |
| 6064 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 6065 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6066 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6067 | ** |
| 6068 | ** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> |
| 6069 | ** <dd>This parameter records the deepest parser stack. It is only |
| 6070 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 6071 | ** </dl> |
| 6072 | ** |
| 6073 | ** New status parameters may be added from time to time. |
| @@ -6088,13 +6251,13 @@ | |
| 6088 | ** |
| 6089 | ** ^This interface is used to retrieve runtime status information |
| 6090 | ** about a single [database connection]. ^The first argument is the |
| 6091 | ** database connection object to be interrogated. ^The second argument |
| 6092 | ** is an integer constant, taken from the set of |
| 6093 | ** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that |
| 6094 | ** determines the parameter to interrogate. The set of |
| 6095 | ** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely |
| 6096 | ** to grow in future releases of SQLite. |
| 6097 | ** |
| 6098 | ** ^The current value of the requested parameter is written into *pCur |
| 6099 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 6100 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -6107,10 +6270,11 @@ | |
| 6107 | */ |
| 6108 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 6109 | |
| 6110 | /* |
| 6111 | ** CAPI3REF: Status Parameters for database connections |
| 6112 | ** |
| 6113 | ** These constants are the available integer "verbs" that can be passed as |
| 6114 | ** the second argument to the [sqlite3_db_status()] interface. |
| 6115 | ** |
| 6116 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -6118,48 +6282,50 @@ | |
| 6118 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 6119 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 6120 | ** if a discontinued or unsupported verb is invoked. |
| 6121 | ** |
| 6122 | ** <dl> |
| 6123 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> |
| 6124 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 6125 | ** checked out.</dd>)^ |
| 6126 | ** |
| 6127 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> |
| 6128 | ** <dd>This parameter returns the number malloc attempts that were |
| 6129 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 6130 | ** the current value is always zero.)^ |
| 6131 | ** |
| 6132 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 6133 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6134 | ** been satisfied using lookaside memory but failed due to the amount of |
| 6135 | ** memory requested being larger than the lookaside slot size. |
| 6136 | ** Only the high-water value is meaningful; |
| 6137 | ** the current value is always zero.)^ |
| 6138 | ** |
| 6139 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 6140 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6141 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 6142 | ** memory already being in use. |
| 6143 | ** Only the high-water value is meaningful; |
| 6144 | ** the current value is always zero.)^ |
| 6145 | ** |
| 6146 | ** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> |
| 6147 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6148 | ** memory used by all pager caches associated with the database connection.)^ |
| 6149 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 6150 | ** |
| 6151 | ** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> |
| 6152 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6153 | ** memory used to store the schema for all databases associated |
| 6154 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 6155 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 6156 | ** schema memory is shared with other database connections due to |
| 6157 | ** [shared cache mode] being enabled. |
| 6158 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 6159 | ** |
| 6160 | ** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> |
| 6161 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6162 | ** and lookaside memory used by all prepared statements associated with |
| 6163 | ** the database connection.)^ |
| 6164 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 6165 | ** </dd> |
| @@ -6177,11 +6343,11 @@ | |
| 6177 | |
| 6178 | /* |
| 6179 | ** CAPI3REF: Prepared Statement Status |
| 6180 | ** |
| 6181 | ** ^(Each prepared statement maintains various |
| 6182 | ** [SQLITE_STMTSTATUS_SORT | counters] that measure the number |
| 6183 | ** of times it has performed specific operations.)^ These counters can |
| 6184 | ** be used to monitor the performance characteristics of the prepared |
| 6185 | ** statements. For example, if the number of table steps greatly exceeds |
| 6186 | ** the number of table searches or result rows, that would tend to indicate |
| 6187 | ** that the prepared statement is using a full table scan rather than |
| @@ -6188,11 +6354,11 @@ | |
| 6188 | ** an index. |
| 6189 | ** |
| 6190 | ** ^(This interface is used to retrieve and reset counter values from |
| 6191 | ** a [prepared statement]. The first argument is the prepared statement |
| 6192 | ** object to be interrogated. The second argument |
| 6193 | ** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] |
| 6194 | ** to be interrogated.)^ |
| 6195 | ** ^The current value of the requested counter is returned. |
| 6196 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 6197 | ** interface call returns. |
| 6198 | ** |
| @@ -6200,28 +6366,29 @@ | |
| 6200 | */ |
| 6201 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 6202 | |
| 6203 | /* |
| 6204 | ** CAPI3REF: Status Parameters for prepared statements |
| 6205 | ** |
| 6206 | ** These preprocessor macros define integer codes that name counter |
| 6207 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 6208 | ** The meanings of the various counters are as follows: |
| 6209 | ** |
| 6210 | ** <dl> |
| 6211 | ** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> |
| 6212 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 6213 | ** a table as part of a full table scan. Large numbers for this counter |
| 6214 | ** may indicate opportunities for performance improvement through |
| 6215 | ** careful use of indices.</dd> |
| 6216 | ** |
| 6217 | ** <dt>SQLITE_STMTSTATUS_SORT</dt> |
| 6218 | ** <dd>^This is the number of sort operations that have occurred. |
| 6219 | ** A non-zero value in this counter may indicate an opportunity to |
| 6220 | ** improvement performance through careful use of indices.</dd> |
| 6221 | ** |
| 6222 | ** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> |
| 6223 | ** <dd>^This is the number of rows inserted into transient indices that |
| 6224 | ** were created automatically in order to help joins run faster. |
| 6225 | ** A non-zero value in this counter may indicate an opportunity to |
| 6226 | ** improvement performance by adding permanent indices that do not |
| 6227 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -6268,10 +6435,11 @@ | |
| 6268 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 6269 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 6270 | ** the application may discard the parameter after the call to |
| 6271 | ** [sqlite3_config()] returns.)^ |
| 6272 | ** |
| 6273 | ** ^(The xInit() method is called once for each effective |
| 6274 | ** call to [sqlite3_initialize()])^ |
| 6275 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 6276 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 6277 | ** The intent of the xInit() method is to set up global data structures |
| @@ -6278,10 +6446,11 @@ | |
| 6278 | ** required by the custom page cache implementation. |
| 6279 | ** ^(If the xInit() method is NULL, then the |
| 6280 | ** built-in default page cache is used instead of the application defined |
| 6281 | ** page cache.)^ |
| 6282 | ** |
| 6283 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 6284 | ** It can be used to clean up |
| 6285 | ** any outstanding resources before process shutdown, if required. |
| 6286 | ** ^The xShutdown() method may be NULL. |
| 6287 | ** |
| @@ -6292,10 +6461,11 @@ | |
| 6292 | ** in multithreaded applications. |
| 6293 | ** |
| 6294 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 6295 | ** call to xShutdown(). |
| 6296 | ** |
| 6297 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 6298 | ** SQLite will typically create one cache instance for each open database file, |
| 6299 | ** though this is not guaranteed. ^The |
| 6300 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 6301 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -6316,20 +6486,23 @@ | |
| 6316 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 6317 | ** false will always have the "discard" flag set to true. |
| 6318 | ** ^Hence, a cache created with bPurgeable false will |
| 6319 | ** never contain any unpinned pages. |
| 6320 | ** |
| 6321 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 6322 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 6323 | ** instance passed as the first argument. This is the value configured using |
| 6324 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 6325 | ** parameter, the implementation is not required to do anything with this |
| 6326 | ** value; it is advisory only. |
| 6327 | ** |
| 6328 | ** The xPagecount() method must return the number of pages currently |
| 6329 | ** stored in the cache, both pinned and unpinned. |
| 6330 | ** |
| 6331 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 6332 | ** the page, or a NULL pointer. |
| 6333 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 6334 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 6335 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -6354,10 +6527,11 @@ | |
| 6354 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 6355 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 6356 | ** attempt to unpin one or more cache pages by spilling the content of |
| 6357 | ** pinned pages to disk and synching the operating system disk cache. |
| 6358 | ** |
| 6359 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 6360 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 6361 | ** then the page must be evicted from the cache. |
| 6362 | ** ^If the discard parameter is |
| 6363 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -6366,10 +6540,11 @@ | |
| 6366 | ** |
| 6367 | ** The cache must not perform any reference counting. A single |
| 6368 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 6369 | ** to xFetch(). |
| 6370 | ** |
| 6371 | ** The xRekey() method is used to change the key value associated with the |
| 6372 | ** page passed as the second argument. If the cache |
| 6373 | ** previously contains an entry associated with newKey, it must be |
| 6374 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 6375 | ** to be pinned. |
| @@ -6378,10 +6553,11 @@ | |
| 6378 | ** existing cache entries with page numbers (keys) greater than or equal |
| 6379 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 6380 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 6381 | ** they can be safely discarded. |
| 6382 | ** |
| 6383 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 6384 | ** All resources associated with the specified cache should be freed. ^After |
| 6385 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 6386 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 6387 | ** functions. |
| @@ -6440,11 +6616,11 @@ | |
| 6440 | ** associated with the backup operation. |
| 6441 | ** </ol>)^ |
| 6442 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 6443 | ** successful call to sqlite3_backup_init(). |
| 6444 | ** |
| 6445 | ** <b>sqlite3_backup_init()</b> |
| 6446 | ** |
| 6447 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 6448 | ** [database connection] associated with the destination database |
| 6449 | ** and the database name, respectively. |
| 6450 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -6467,11 +6643,11 @@ | |
| 6467 | ** [sqlite3_backup] object. |
| 6468 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 6469 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 6470 | ** operation. |
| 6471 | ** |
| 6472 | ** <b>sqlite3_backup_step()</b> |
| 6473 | ** |
| 6474 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 6475 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 6476 | ** ^If N is negative, all remaining source pages are copied. |
| 6477 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -6524,11 +6700,11 @@ | |
| 6524 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 6525 | ** database is modified by the using the same database connection as is used |
| 6526 | ** by the backup operation, then the backup database is automatically |
| 6527 | ** updated at the same time. |
| 6528 | ** |
| 6529 | ** <b>sqlite3_backup_finish()</b> |
| 6530 | ** |
| 6531 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 6532 | ** application wishes to abandon the backup operation, the application |
| 6533 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 6534 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6547,11 +6723,12 @@ | |
| 6547 | ** |
| 6548 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6549 | ** is not a permanent error and does not affect the return value of |
| 6550 | ** sqlite3_backup_finish(). |
| 6551 | ** |
| 6552 | ** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b> |
| 6553 | ** |
| 6554 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6555 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6556 | ** up and the total number of pages in the source database file. |
| 6557 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6932,10 +7109,97 @@ | |
| 6932 | ** each of these values. |
| 6933 | */ |
| 6934 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 6935 | #define SQLITE_CHECKPOINT_FULL 1 |
| 6936 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 6937 | |
| 6938 | |
| 6939 | /* |
| 6940 | ** Undo the hack that converts floating point types to integer for |
| 6941 | ** builds on processors without floating point support. |
| @@ -7599,10 +7863,11 @@ | |
| 7599 | typedef struct Trigger Trigger; |
| 7600 | typedef struct TriggerPrg TriggerPrg; |
| 7601 | typedef struct TriggerStep TriggerStep; |
| 7602 | typedef struct UnpackedRecord UnpackedRecord; |
| 7603 | typedef struct VTable VTable; |
| 7604 | typedef struct Walker Walker; |
| 7605 | typedef struct WherePlan WherePlan; |
| 7606 | typedef struct WhereInfo WhereInfo; |
| 7607 | typedef struct WhereLevel WhereLevel; |
| 7608 | |
| @@ -7655,10 +7920,11 @@ | |
| 7655 | typedef struct BtCursor BtCursor; |
| 7656 | typedef struct BtShared BtShared; |
| 7657 | |
| 7658 | |
| 7659 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 7660 | const char *zFilename, /* Name of database file to open */ |
| 7661 | sqlite3 *db, /* Associated database connection */ |
| 7662 | Btree **ppBtree, /* Return open Btree* here */ |
| 7663 | int flags, /* Flags */ |
| 7664 | int vfsFlags /* Flags passed through to VFS open */ |
| @@ -9134,19 +9400,20 @@ | |
| 9134 | struct sqlite3 { |
| 9135 | sqlite3_vfs *pVfs; /* OS Interface */ |
| 9136 | int nDb; /* Number of backends currently in use */ |
| 9137 | Db *aDb; /* All backends */ |
| 9138 | int flags; /* Miscellaneous flags. See below */ |
| 9139 | int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ |
| 9140 | int errCode; /* Most recent error code (SQLITE_*) */ |
| 9141 | int errMask; /* & result codes with this before returning */ |
| 9142 | u8 autoCommit; /* The auto-commit flag. */ |
| 9143 | u8 temp_store; /* 1: file 2: memory 0: default */ |
| 9144 | u8 mallocFailed; /* True if we have seen a malloc failure */ |
| 9145 | u8 dfltLockMode; /* Default locking-mode for attached dbs */ |
| 9146 | signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ |
| 9147 | u8 suppressErr; /* Do not issue error messages if true */ |
| 9148 | int nextPagesize; /* Pagesize after VACUUM if >0 */ |
| 9149 | int nTable; /* Number of tables in the database */ |
| 9150 | CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ |
| 9151 | i64 lastRowid; /* ROWID of most recent insert (see above) */ |
| 9152 | u32 magic; /* Magic number for detect library misuse */ |
| @@ -9201,11 +9468,11 @@ | |
| 9201 | void *pProgressArg; /* Argument to the progress callback */ |
| 9202 | int nProgressOps; /* Number of opcodes for progress callback */ |
| 9203 | #endif |
| 9204 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 9205 | Hash aModule; /* populated by sqlite3_create_module() */ |
| 9206 | Table *pVTab; /* vtab with active Connect/Create method */ |
| 9207 | VTable **aVTrans; /* Virtual tables with open transactions */ |
| 9208 | int nVTrans; /* Allocated size of aVTrans */ |
| 9209 | VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ |
| 9210 | #endif |
| 9211 | FuncDefHash aFunc; /* Hash table of connection functions */ |
| @@ -9564,10 +9831,11 @@ | |
| 9564 | struct VTable { |
| 9565 | sqlite3 *db; /* Database connection associated with this table */ |
| 9566 | Module *pMod; /* Pointer to module implementation */ |
| 9567 | sqlite3_vtab *pVtab; /* Pointer to vtab instance */ |
| 9568 | int nRef; /* Number of pointers to this structure */ |
| 9569 | VTable *pNext; /* Next in linked list (see above) */ |
| 9570 | }; |
| 9571 | |
| 9572 | /* |
| 9573 | ** Each SQL table is represented in memory by an instance of the |
| @@ -10752,10 +11020,11 @@ | |
| 10752 | */ |
| 10753 | struct Sqlite3Config { |
| 10754 | int bMemstat; /* True to enable memory status */ |
| 10755 | int bCoreMutex; /* True to enable core mutexing */ |
| 10756 | int bFullMutex; /* True to enable full mutexing */ |
| 10757 | int mxStrlen; /* Maximum string length */ |
| 10758 | int szLookaside; /* Default lookaside buffer size */ |
| 10759 | int nLookaside; /* Default lookaside buffer count */ |
| 10760 | sqlite3_mem_methods m; /* Low-level memory allocation interface */ |
| 10761 | sqlite3_mutex_methods mutex; /* Low-level mutex interface */ |
| @@ -11001,10 +11270,12 @@ | |
| 11001 | SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); |
| 11002 | SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); |
| 11003 | SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); |
| 11004 | SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); |
| 11005 | SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*); |
| 11006 | |
| 11007 | SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); |
| 11008 | SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); |
| 11009 | SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); |
| 11010 | SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); |
| @@ -11251,10 +11522,11 @@ | |
| 11251 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 11252 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 11253 | SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); |
| 11254 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 11255 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 11256 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 11257 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 11258 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| 11259 | SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); |
| 11260 | SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); |
| @@ -11266,10 +11538,16 @@ | |
| 11266 | SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); |
| 11267 | SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); |
| 11268 | SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); |
| 11269 | SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); |
| 11270 | SQLITE_PRIVATE int sqlite3AbsInt32(int); |
| 11271 | |
| 11272 | SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); |
| 11273 | SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); |
| 11274 | SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, |
| 11275 | void(*)(void*)); |
| @@ -11375,18 +11653,20 @@ | |
| 11375 | # define sqlite3VtabCommit(X) |
| 11376 | # define sqlite3VtabInSync(db) 0 |
| 11377 | # define sqlite3VtabLock(X) |
| 11378 | # define sqlite3VtabUnlock(X) |
| 11379 | # define sqlite3VtabUnlockList(X) |
| 11380 | #else |
| 11381 | SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); |
| 11382 | SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, char **); |
| 11383 | SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); |
| 11384 | SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); |
| 11385 | SQLITE_PRIVATE void sqlite3VtabLock(VTable *); |
| 11386 | SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); |
| 11387 | SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); |
| 11388 | # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) |
| 11389 | #endif |
| 11390 | SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); |
| 11391 | SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); |
| 11392 | SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); |
| @@ -11689,20 +11969,23 @@ | |
| 11689 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ |
| 11690 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ |
| 11691 | }; |
| 11692 | #endif |
| 11693 | |
| 11694 | |
| 11695 | |
| 11696 | /* |
| 11697 | ** The following singleton contains the global configuration for |
| 11698 | ** the SQLite library. |
| 11699 | */ |
| 11700 | SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { |
| 11701 | SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ |
| 11702 | 1, /* bCoreMutex */ |
| 11703 | SQLITE_THREADSAFE==1, /* bFullMutex */ |
| 11704 | 0x7ffffffe, /* mxStrlen */ |
| 11705 | 100, /* szLookaside */ |
| 11706 | 500, /* nLookaside */ |
| 11707 | {0,0,0,0,0,0,0,0}, /* m */ |
| 11708 | {0,0,0,0,0,0,0,0,0}, /* mutex */ |
| @@ -17948,11 +18231,11 @@ | |
| 17948 | assert( sqlite3_mutex_held(mem0.mutex) ); |
| 17949 | nFull = sqlite3GlobalConfig.m.xRoundup(n); |
| 17950 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); |
| 17951 | if( mem0.alarmCallback!=0 ){ |
| 17952 | int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); |
| 17953 | if( nUsed+nFull >= mem0.alarmThreshold ){ |
| 17954 | mem0.nearlyFull = 1; |
| 17955 | sqlite3MallocAlarm(nFull); |
| 17956 | }else{ |
| 17957 | mem0.nearlyFull = 0; |
| 17958 | } |
| @@ -18189,11 +18472,11 @@ | |
| 18189 | |
| 18190 | /* |
| 18191 | ** Change the size of an existing memory allocation |
| 18192 | */ |
| 18193 | SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ |
| 18194 | int nOld, nNew; |
| 18195 | void *pNew; |
| 18196 | if( pOld==0 ){ |
| 18197 | return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ |
| 18198 | } |
| 18199 | if( nBytes<=0 ){ |
| @@ -18212,13 +18495,14 @@ | |
| 18212 | if( nOld==nNew ){ |
| 18213 | pNew = pOld; |
| 18214 | }else if( sqlite3GlobalConfig.bMemstat ){ |
| 18215 | sqlite3_mutex_enter(mem0.mutex); |
| 18216 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); |
| 18217 | if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED)+nNew-nOld >= |
| 18218 | mem0.alarmThreshold ){ |
| 18219 | sqlite3MallocAlarm(nNew-nOld); |
| 18220 | } |
| 18221 | assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); |
| 18222 | assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); |
| 18223 | pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
| 18224 | if( pNew==0 && mem0.alarmCallback ){ |
| @@ -21180,27 +21464,25 @@ | |
| 21180 | p[3] = (u8)v; |
| 21181 | } |
| 21182 | |
| 21183 | |
| 21184 | |
| 21185 | #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) |
| 21186 | /* |
| 21187 | ** Translate a single byte of Hex into an integer. |
| 21188 | ** This routine only works if h really is a valid hexadecimal |
| 21189 | ** character: 0..9a..fA..F |
| 21190 | */ |
| 21191 | static u8 hexToInt(int h){ |
| 21192 | assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); |
| 21193 | #ifdef SQLITE_ASCII |
| 21194 | h += 9*(1&(h>>6)); |
| 21195 | #endif |
| 21196 | #ifdef SQLITE_EBCDIC |
| 21197 | h += 9*(1&~(h>>4)); |
| 21198 | #endif |
| 21199 | return (u8)(h & 0xf); |
| 21200 | } |
| 21201 | #endif /* !SQLITE_OMIT_BLOB_LITERAL || SQLITE_HAS_CODEC */ |
| 21202 | |
| 21203 | #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) |
| 21204 | /* |
| 21205 | ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary |
| 21206 | ** value. Return a pointer to its binary value. Space to hold the |
| @@ -21213,11 +21495,11 @@ | |
| 21213 | |
| 21214 | zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1); |
| 21215 | n--; |
| 21216 | if( zBlob ){ |
| 21217 | for(i=0; i<n; i+=2){ |
| 21218 | zBlob[i/2] = (hexToInt(z[i])<<4) | hexToInt(z[i+1]); |
| 21219 | } |
| 21220 | zBlob[i/2] = 0; |
| 21221 | } |
| 21222 | return zBlob; |
| 21223 | } |
| @@ -21345,10 +21627,36 @@ | |
| 21345 | SQLITE_PRIVATE int sqlite3AbsInt32(int x){ |
| 21346 | if( x>=0 ) return x; |
| 21347 | if( x==(int)0x80000000 ) return 0x7fffffff; |
| 21348 | return -x; |
| 21349 | } |
| 21350 | |
| 21351 | /************** End of util.c ************************************************/ |
| 21352 | /************** Begin file hash.c ********************************************/ |
| 21353 | /* |
| 21354 | ** 2001 September 22 |
| @@ -24398,10 +24706,22 @@ | |
| 24398 | #if SQLITE_THREADSAFE |
| 24399 | #define threadid pthread_self() |
| 24400 | #else |
| 24401 | #define threadid 0 |
| 24402 | #endif |
| 24403 | |
| 24404 | /* |
| 24405 | ** Many system calls are accessed through pointer-to-functions so that |
| 24406 | ** they may be overridden at runtime to facilitate fault injection during |
| 24407 | ** testing and sandboxing. The following array holds the names and pointers |
| @@ -24410,11 +24730,11 @@ | |
| 24410 | static struct unix_syscall { |
| 24411 | const char *zName; /* Name of the sytem call */ |
| 24412 | sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ |
| 24413 | sqlite3_syscall_ptr pDefault; /* Default value */ |
| 24414 | } aSyscall[] = { |
| 24415 | { "open", (sqlite3_syscall_ptr)open, 0 }, |
| 24416 | #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) |
| 24417 | |
| 24418 | { "close", (sqlite3_syscall_ptr)close, 0 }, |
| 24419 | #define osClose ((int(*)(int))aSyscall[1].pCurrent) |
| 24420 | |
| @@ -24448,11 +24768,11 @@ | |
| 24448 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 24449 | |
| 24450 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 24451 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 24452 | |
| 24453 | #if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) |
| 24454 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 24455 | #else |
| 24456 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 24457 | #endif |
| 24458 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -24465,11 +24785,11 @@ | |
| 24465 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 24466 | |
| 24467 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 24468 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 24469 | |
| 24470 | #if defined(USE_PREAD) || defined(SQLITE_ENABLE_LOCKING_STYLE) |
| 24471 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 24472 | #else |
| 24473 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 24474 | #endif |
| 24475 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -24483,12 +24803,14 @@ | |
| 24483 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 24484 | aSyscall[13].pCurrent) |
| 24485 | |
| 24486 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 24487 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 24488 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 24489 | #endif |
| 24490 | |
| 24491 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 24492 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 24493 | #else |
| 24494 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -25049,11 +25371,11 @@ | |
| 25049 | unixShmNode *pShmNode; /* Shared memory associated with this inode */ |
| 25050 | int nLock; /* Number of outstanding file locks */ |
| 25051 | UnixUnusedFd *pUnused; /* Unused file descriptors to close */ |
| 25052 | unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ |
| 25053 | unixInodeInfo *pPrev; /* .... doubly linked */ |
| 25054 | #if defined(SQLITE_ENABLE_LOCKING_STYLE) |
| 25055 | unsigned long long sharedByte; /* for AFP simulated shared lock */ |
| 25056 | #endif |
| 25057 | #if OS_VXWORKS |
| 25058 | sem_t *pSem; /* Named POSIX semaphore */ |
| 25059 | char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ |
| @@ -27206,11 +27528,11 @@ | |
| 27206 | } |
| 27207 | SimulateIOError(( wrote=(-1), amt=1 )); |
| 27208 | SimulateDiskfullError(( wrote=0, amt=1 )); |
| 27209 | |
| 27210 | if( amt>0 ){ |
| 27211 | if( wrote<0 ){ |
| 27212 | /* lastErrno set by seekAndWrite */ |
| 27213 | return SQLITE_IOERR_WRITE; |
| 27214 | }else{ |
| 27215 | pFile->lastErrno = 0; /* not a system error */ |
| 27216 | return SQLITE_FULL; |
| @@ -27873,10 +28195,11 @@ | |
| 27873 | sqlite3_snprintf(nShmFilename, zShmFilename, |
| 27874 | SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", |
| 27875 | (u32)sStat.st_ino, (u32)sStat.st_dev); |
| 27876 | #else |
| 27877 | sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); |
| 27878 | #endif |
| 27879 | pShmNode->h = -1; |
| 27880 | pDbFd->pInode->pShmNode = pShmNode; |
| 27881 | pShmNode->pInode = pDbFd->pInode; |
| 27882 | pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| @@ -28031,11 +28354,11 @@ | |
| 28031 | if( pShmNode->h>=0 ){ |
| 28032 | pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, |
| 28033 | MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion |
| 28034 | ); |
| 28035 | if( pMem==MAP_FAILED ){ |
| 28036 | rc = SQLITE_IOERR; |
| 28037 | goto shmpage_out; |
| 28038 | } |
| 28039 | }else{ |
| 28040 | pMem = sqlite3_malloc(szRegion); |
| 28041 | if( pMem==0 ){ |
| @@ -28906,17 +29229,23 @@ | |
| 28906 | ** Finally, if the file being opened is a WAL or regular journal file, then |
| 28907 | ** this function queries the file-system for the permissions on the |
| 28908 | ** corresponding database file and sets *pMode to this value. Whenever |
| 28909 | ** possible, WAL and journal files are created using the same permissions |
| 28910 | ** as the associated database file. |
| 28911 | */ |
| 28912 | static int findCreateFileMode( |
| 28913 | const char *zPath, /* Path of file (possibly) being created */ |
| 28914 | int flags, /* Flags passed as 4th argument to xOpen() */ |
| 28915 | mode_t *pMode /* OUT: Permissions to open file with */ |
| 28916 | ){ |
| 28917 | int rc = SQLITE_OK; /* Return Code */ |
| 28918 | if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
| 28919 | char zDb[MAX_PATHNAME+1]; /* Database file path */ |
| 28920 | int nDb; /* Number of valid bytes in zDb */ |
| 28921 | struct stat sStat; /* Output of stat() on database file */ |
| 28922 | |
| @@ -28924,19 +29253,19 @@ | |
| 28924 | ** the path to the associated database file from zPath. This block handles |
| 28925 | ** the following naming conventions: |
| 28926 | ** |
| 28927 | ** "<path to db>-journal" |
| 28928 | ** "<path to db>-wal" |
| 28929 | ** "<path to db>-journal-NNNN" |
| 28930 | ** "<path to db>-wal-NNNN" |
| 28931 | ** |
| 28932 | ** where NNNN is a 4 digit decimal number. The NNNN naming schemes are |
| 28933 | ** used by the test_multiplex.c module. |
| 28934 | */ |
| 28935 | nDb = sqlite3Strlen30(zPath) - 1; |
| 28936 | while( nDb>0 && zPath[nDb]!='l' ) nDb--; |
| 28937 | nDb -= ((flags & SQLITE_OPEN_WAL) ? 3 : 7); |
| 28938 | memcpy(zDb, zPath, nDb); |
| 28939 | zDb[nDb] = '\0'; |
| 28940 | |
| 28941 | if( 0==stat(zDb, &sStat) ){ |
| 28942 | *pMode = sStat.st_mode & 0777; |
| @@ -28943,12 +29272,10 @@ | |
| 28943 | }else{ |
| 28944 | rc = SQLITE_IOERR_FSTAT; |
| 28945 | } |
| 28946 | }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
| 28947 | *pMode = 0600; |
| 28948 | }else{ |
| 28949 | *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; |
| 28950 | } |
| 28951 | return rc; |
| 28952 | } |
| 28953 | |
| 28954 | /* |
| @@ -30801,10 +31128,14 @@ | |
| 30801 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 30802 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| 30803 | #endif |
| 30804 | }; |
| 30805 | unsigned int i; /* Loop counter */ |
| 30806 | |
| 30807 | /* Register all VFSes defined in the aVfs[] array */ |
| 30808 | for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ |
| 30809 | sqlite3_vfs_register(&aVfs[i], i==0); |
| 30810 | } |
| @@ -31147,10 +31478,11 @@ | |
| 31147 | HANDLE hShared; /* Shared memory segment used for locking */ |
| 31148 | winceLock local; /* Locks obtained by this instance of winFile */ |
| 31149 | winceLock *shared; /* Global shared lock memory for the file */ |
| 31150 | #endif |
| 31151 | }; |
| 31152 | |
| 31153 | /* |
| 31154 | ** Forward prototypes. |
| 31155 | */ |
| 31156 | static int getSectorSize( |
| @@ -31315,11 +31647,11 @@ | |
| 31315 | |
| 31316 | /* |
| 31317 | ** Convert UTF-8 to multibyte character string. Space to hold the |
| 31318 | ** returned string is obtained from malloc(). |
| 31319 | */ |
| 31320 | static char *utf8ToMbcs(const char *zFilename){ |
| 31321 | char *zFilenameMbcs; |
| 31322 | WCHAR *zTmpWide; |
| 31323 | |
| 31324 | zTmpWide = utf8ToUnicode(zFilename); |
| 31325 | if( zTmpWide==0 ){ |
| @@ -31328,10 +31660,113 @@ | |
| 31328 | zFilenameMbcs = unicodeToMbcs(zTmpWide); |
| 31329 | free(zTmpWide); |
| 31330 | return zFilenameMbcs; |
| 31331 | } |
| 31332 | |
| 31333 | #if SQLITE_OS_WINCE |
| 31334 | /************************************************************************* |
| 31335 | ** This section contains code for WinCE only. |
| 31336 | */ |
| 31337 | /* |
| @@ -31404,10 +31839,11 @@ | |
| 31404 | |
| 31405 | /* Create/open the named mutex */ |
| 31406 | pFile->hMutex = CreateMutexW(NULL, FALSE, zName); |
| 31407 | if (!pFile->hMutex){ |
| 31408 | pFile->lastErrno = GetLastError(); |
| 31409 | free(zName); |
| 31410 | return FALSE; |
| 31411 | } |
| 31412 | |
| 31413 | /* Acquire the mutex before continuing */ |
| @@ -31435,10 +31871,11 @@ | |
| 31435 | pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, |
| 31436 | FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); |
| 31437 | /* If mapping failed, close the shared memory handle and erase it */ |
| 31438 | if (!pFile->shared){ |
| 31439 | pFile->lastErrno = GetLastError(); |
| 31440 | CloseHandle(pFile->hShared); |
| 31441 | pFile->hShared = NULL; |
| 31442 | } |
| 31443 | } |
| 31444 | |
| @@ -31680,10 +32117,11 @@ | |
| 31680 | ** GetLastError(). |
| 31681 | */ |
| 31682 | dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
| 31683 | if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ |
| 31684 | pFile->lastErrno = GetLastError(); |
| 31685 | return 1; |
| 31686 | } |
| 31687 | |
| 31688 | return 0; |
| 31689 | } |
| @@ -31725,11 +32163,12 @@ | |
| 31725 | free(pFile->zDeleteOnClose); |
| 31726 | } |
| 31727 | #endif |
| 31728 | OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed")); |
| 31729 | OpenCounter(-1); |
| 31730 | return rc ? SQLITE_OK : SQLITE_IOERR; |
| 31731 | } |
| 31732 | |
| 31733 | /* |
| 31734 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| 31735 | ** bytes were read successfully and SQLITE_IOERR if anything goes |
| @@ -31751,11 +32190,11 @@ | |
| 31751 | if( seekWinFile(pFile, offset) ){ |
| 31752 | return SQLITE_FULL; |
| 31753 | } |
| 31754 | if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ |
| 31755 | pFile->lastErrno = GetLastError(); |
| 31756 | return SQLITE_IOERR_READ; |
| 31757 | } |
| 31758 | if( nRead<(DWORD)amt ){ |
| 31759 | /* Unread parts of the buffer must be zero-filled */ |
| 31760 | memset(&((char*)pBuf)[nRead], 0, amt-nRead); |
| 31761 | return SQLITE_IOERR_SHORT_READ; |
| @@ -31802,11 +32241,11 @@ | |
| 31802 | |
| 31803 | if( rc ){ |
| 31804 | if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){ |
| 31805 | return SQLITE_FULL; |
| 31806 | } |
| 31807 | return SQLITE_IOERR_WRITE; |
| 31808 | } |
| 31809 | return SQLITE_OK; |
| 31810 | } |
| 31811 | |
| 31812 | /* |
| @@ -31830,14 +32269,14 @@ | |
| 31830 | nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
| 31831 | } |
| 31832 | |
| 31833 | /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ |
| 31834 | if( seekWinFile(pFile, nByte) ){ |
| 31835 | rc = SQLITE_IOERR_TRUNCATE; |
| 31836 | }else if( 0==SetEndOfFile(pFile->h) ){ |
| 31837 | pFile->lastErrno = GetLastError(); |
| 31838 | rc = SQLITE_IOERR_TRUNCATE; |
| 31839 | } |
| 31840 | |
| 31841 | OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok")); |
| 31842 | return rc; |
| 31843 | } |
| @@ -31855,10 +32294,11 @@ | |
| 31855 | ** Make sure all writes to a particular file are committed to disk. |
| 31856 | */ |
| 31857 | static int winSync(sqlite3_file *id, int flags){ |
| 31858 | #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG) |
| 31859 | winFile *pFile = (winFile*)id; |
| 31860 | #else |
| 31861 | UNUSED_PARAMETER(id); |
| 31862 | #endif |
| 31863 | |
| 31864 | assert( pFile ); |
| @@ -31867,36 +32307,37 @@ | |
| 31867 | || (flags&0x0F)==SQLITE_SYNC_FULL |
| 31868 | ); |
| 31869 | |
| 31870 | OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype)); |
| 31871 | |
| 31872 | #ifndef SQLITE_TEST |
| 31873 | UNUSED_PARAMETER(flags); |
| 31874 | #else |
| 31875 | if( flags & SQLITE_SYNC_FULL ){ |
| 31876 | sqlite3_fullsync_count++; |
| 31877 | } |
| 31878 | sqlite3_sync_count++; |
| 31879 | #endif |
| 31880 | |
| 31881 | /* Unix cannot, but some systems may return SQLITE_FULL from here. This |
| 31882 | ** line is to test that doing so does not cause any problems. |
| 31883 | */ |
| 31884 | SimulateDiskfullError( return SQLITE_FULL ); |
| 31885 | SimulateIOError( return SQLITE_IOERR; ); |
| 31886 | |
| 31887 | /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a |
| 31888 | ** no-op |
| 31889 | */ |
| 31890 | #ifdef SQLITE_NO_SYNC |
| 31891 | return SQLITE_OK; |
| 31892 | #else |
| 31893 | if( FlushFileBuffers(pFile->h) ){ |
| 31894 | return SQLITE_OK; |
| 31895 | }else{ |
| 31896 | pFile->lastErrno = GetLastError(); |
| 31897 | return SQLITE_IOERR; |
| 31898 | } |
| 31899 | #endif |
| 31900 | } |
| 31901 | |
| 31902 | /* |
| @@ -31913,11 +32354,11 @@ | |
| 31913 | lowerBits = GetFileSize(pFile->h, &upperBits); |
| 31914 | if( (lowerBits == INVALID_FILE_SIZE) |
| 31915 | && ((error = GetLastError()) != NO_ERROR) ) |
| 31916 | { |
| 31917 | pFile->lastErrno = error; |
| 31918 | return SQLITE_IOERR_FSTAT; |
| 31919 | } |
| 31920 | *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; |
| 31921 | return SQLITE_OK; |
| 31922 | } |
| 31923 | |
| @@ -31952,10 +32393,11 @@ | |
| 31952 | res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
| 31953 | #endif |
| 31954 | } |
| 31955 | if( res == 0 ){ |
| 31956 | pFile->lastErrno = GetLastError(); |
| 31957 | } |
| 31958 | return res; |
| 31959 | } |
| 31960 | |
| 31961 | /* |
| @@ -31970,12 +32412,13 @@ | |
| 31970 | #if SQLITE_OS_WINCE==0 |
| 31971 | }else{ |
| 31972 | res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); |
| 31973 | #endif |
| 31974 | } |
| 31975 | if( res == 0 ){ |
| 31976 | pFile->lastErrno = GetLastError(); |
| 31977 | } |
| 31978 | return res; |
| 31979 | } |
| 31980 | |
| 31981 | /* |
| @@ -32172,11 +32615,11 @@ | |
| 32172 | if( type>=EXCLUSIVE_LOCK ){ |
| 32173 | UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
| 32174 | if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ |
| 32175 | /* This should never happen. We should always be able to |
| 32176 | ** reacquire the read lock */ |
| 32177 | rc = SQLITE_IOERR_UNLOCK; |
| 32178 | } |
| 32179 | } |
| 32180 | if( type>=RESERVED_LOCK ){ |
| 32181 | UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
| 32182 | } |
| @@ -32487,10 +32930,11 @@ | |
| 32487 | return SQLITE_NOMEM; |
| 32488 | } |
| 32489 | memset(pNew, 0, sizeof(*pNew)); |
| 32490 | pNew->zFilename = (char*)&pNew[1]; |
| 32491 | sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); |
| 32492 | |
| 32493 | /* Look to see if there is an existing winShmNode that can be used. |
| 32494 | ** If no matching winShmNode currently exists, create a new one. |
| 32495 | */ |
| 32496 | winShmEnterMutex(); |
| @@ -32529,11 +32973,11 @@ | |
| 32529 | ** If not, truncate the file to zero length. |
| 32530 | */ |
| 32531 | if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ |
| 32532 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); |
| 32533 | if( rc!=SQLITE_OK ){ |
| 32534 | rc = SQLITE_IOERR_SHMOPEN; |
| 32535 | } |
| 32536 | } |
| 32537 | if( rc==SQLITE_OK ){ |
| 32538 | winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); |
| 32539 | rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); |
| @@ -32788,11 +33232,11 @@ | |
| 32788 | ** Check to see if it has been allocated (i.e. if the wal-index file is |
| 32789 | ** large enough to contain the requested region). |
| 32790 | */ |
| 32791 | rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); |
| 32792 | if( rc!=SQLITE_OK ){ |
| 32793 | rc = SQLITE_IOERR_SHMSIZE; |
| 32794 | goto shmpage_out; |
| 32795 | } |
| 32796 | |
| 32797 | if( sz<nByte ){ |
| 32798 | /* The requested memory region does not exist. If isWrite is set to |
| @@ -32802,11 +33246,11 @@ | |
| 32802 | ** the requested memory region. |
| 32803 | */ |
| 32804 | if( !isWrite ) goto shmpage_out; |
| 32805 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); |
| 32806 | if( rc!=SQLITE_OK ){ |
| 32807 | rc = SQLITE_IOERR_SHMSIZE; |
| 32808 | goto shmpage_out; |
| 32809 | } |
| 32810 | } |
| 32811 | |
| 32812 | /* Map the requested memory region into this processes address space. */ |
| @@ -32839,11 +33283,11 @@ | |
| 32839 | (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, |
| 32840 | pMap ? "ok" : "failed")); |
| 32841 | } |
| 32842 | if( !pMap ){ |
| 32843 | pShmNode->lastErrno = GetLastError(); |
| 32844 | rc = SQLITE_IOERR; |
| 32845 | if( hMap ) CloseHandle(hMap); |
| 32846 | goto shmpage_out; |
| 32847 | } |
| 32848 | |
| 32849 | pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; |
| @@ -32921,11 +33365,11 @@ | |
| 32921 | zConverted = utf8ToUnicode(zFilename); |
| 32922 | /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. |
| 32923 | */ |
| 32924 | #if SQLITE_OS_WINCE==0 |
| 32925 | }else{ |
| 32926 | zConverted = utf8ToMbcs(zFilename); |
| 32927 | #endif |
| 32928 | } |
| 32929 | /* caller will handle out of memory */ |
| 32930 | return zConverted; |
| 32931 | } |
| @@ -33001,72 +33445,10 @@ | |
| 33001 | |
| 33002 | OSTRACE(("TEMP FILENAME: %s\n", zBuf)); |
| 33003 | return SQLITE_OK; |
| 33004 | } |
| 33005 | |
| 33006 | /* |
| 33007 | ** The return value of getLastErrorMsg |
| 33008 | ** is zero if the error message fits in the buffer, or non-zero |
| 33009 | ** otherwise (if the message was truncated). |
| 33010 | */ |
| 33011 | static int getLastErrorMsg(int nBuf, char *zBuf){ |
| 33012 | /* FormatMessage returns 0 on failure. Otherwise it |
| 33013 | ** returns the number of TCHARs written to the output |
| 33014 | ** buffer, excluding the terminating null char. |
| 33015 | */ |
| 33016 | DWORD error = GetLastError(); |
| 33017 | DWORD dwLen = 0; |
| 33018 | char *zOut = 0; |
| 33019 | |
| 33020 | if( isNT() ){ |
| 33021 | WCHAR *zTempWide = NULL; |
| 33022 | dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
| 33023 | NULL, |
| 33024 | error, |
| 33025 | 0, |
| 33026 | (LPWSTR) &zTempWide, |
| 33027 | 0, |
| 33028 | 0); |
| 33029 | if( dwLen > 0 ){ |
| 33030 | /* allocate a buffer and convert to UTF8 */ |
| 33031 | zOut = unicodeToUtf8(zTempWide); |
| 33032 | /* free the system buffer allocated by FormatMessage */ |
| 33033 | LocalFree(zTempWide); |
| 33034 | } |
| 33035 | /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. |
| 33036 | ** Since the ASCII version of these Windows API do not exist for WINCE, |
| 33037 | ** it's important to not reference them for WINCE builds. |
| 33038 | */ |
| 33039 | #if SQLITE_OS_WINCE==0 |
| 33040 | }else{ |
| 33041 | char *zTemp = NULL; |
| 33042 | dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
| 33043 | NULL, |
| 33044 | error, |
| 33045 | 0, |
| 33046 | (LPSTR) &zTemp, |
| 33047 | 0, |
| 33048 | 0); |
| 33049 | if( dwLen > 0 ){ |
| 33050 | /* allocate a buffer and convert to UTF8 */ |
| 33051 | zOut = sqlite3_win32_mbcs_to_utf8(zTemp); |
| 33052 | /* free the system buffer allocated by FormatMessage */ |
| 33053 | LocalFree(zTemp); |
| 33054 | } |
| 33055 | #endif |
| 33056 | } |
| 33057 | if( 0 == dwLen ){ |
| 33058 | sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); |
| 33059 | }else{ |
| 33060 | /* copy a maximum of nBuf chars to output buffer */ |
| 33061 | sqlite3_snprintf(nBuf, zBuf, "%s", zOut); |
| 33062 | /* free the UTF8 buffer */ |
| 33063 | free(zOut); |
| 33064 | } |
| 33065 | return 0; |
| 33066 | } |
| 33067 | |
| 33068 | /* |
| 33069 | ** Open a file. |
| 33070 | */ |
| 33071 | static int winOpen( |
| 33072 | sqlite3_vfs *pVfs, /* Not used */ |
| @@ -33234,10 +33616,11 @@ | |
| 33234 | h, zName, dwDesiredAccess, |
| 33235 | h==INVALID_HANDLE_VALUE ? "failed" : "ok")); |
| 33236 | |
| 33237 | if( h==INVALID_HANDLE_VALUE ){ |
| 33238 | pFile->lastErrno = GetLastError(); |
| 33239 | free(zConverted); |
| 33240 | if( isReadWrite ){ |
| 33241 | return winOpen(pVfs, zName, id, |
| 33242 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); |
| 33243 | }else{ |
| @@ -33337,11 +33720,12 @@ | |
| 33337 | OSTRACE(("DELETE \"%s\" %s\n", zFilename, |
| 33338 | ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ? |
| 33339 | "ok" : "failed" )); |
| 33340 | |
| 33341 | return ( (rc == INVALID_FILE_ATTRIBUTES) |
| 33342 | && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : SQLITE_IOERR_DELETE; |
| 33343 | } |
| 33344 | |
| 33345 | /* |
| 33346 | ** Check the existance and status of a file. |
| 33347 | */ |
| @@ -33377,10 +33761,11 @@ | |
| 33377 | }else{ |
| 33378 | attr = sAttrData.dwFileAttributes; |
| 33379 | } |
| 33380 | }else{ |
| 33381 | if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ |
| 33382 | free(zConverted); |
| 33383 | return SQLITE_IOERR_ACCESS; |
| 33384 | }else{ |
| 33385 | attr = INVALID_FILE_ATTRIBUTES; |
| 33386 | } |
| @@ -33440,10 +33825,17 @@ | |
| 33440 | |
| 33441 | #if !SQLITE_OS_WINCE && !defined(__CYGWIN__) |
| 33442 | int nByte; |
| 33443 | void *zConverted; |
| 33444 | char *zOut; |
| 33445 | |
| 33446 | /* It's odd to simulate an io-error here, but really this is just |
| 33447 | ** using the io-error infrastructure to test that SQLite handles this |
| 33448 | ** function failing. This function could fail if, for example, the |
| 33449 | ** current working directory has been unlinked. |
| @@ -36252,10 +36644,11 @@ | |
| 36252 | #define _WAL_H_ |
| 36253 | |
| 36254 | |
| 36255 | #ifdef SQLITE_OMIT_WAL |
| 36256 | # define sqlite3WalOpen(x,y,z) 0 |
| 36257 | # define sqlite3WalClose(w,x,y,z) 0 |
| 36258 | # define sqlite3WalBeginReadTransaction(y,z) 0 |
| 36259 | # define sqlite3WalEndReadTransaction(z) |
| 36260 | # define sqlite3WalRead(v,w,x,y,z) 0 |
| 36261 | # define sqlite3WalDbsize(y) 0 |
| @@ -36277,13 +36670,16 @@ | |
| 36277 | ** There is one object of this type for each pager. |
| 36278 | */ |
| 36279 | typedef struct Wal Wal; |
| 36280 | |
| 36281 | /* Open and close a connection to a write-ahead log. */ |
| 36282 | SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *zName, int, Wal**); |
| 36283 | SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); |
| 36284 | |
| 36285 | /* Used by readers to open (lock) and close (unlock) a snapshot. A |
| 36286 | ** snapshot is like a read-transaction. It is the state of the database |
| 36287 | ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and |
| 36288 | ** preserves the current state even if the other threads or processes |
| 36289 | ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the |
| @@ -40628,10 +41024,12 @@ | |
| 40628 | int nPathname = 0; /* Number of bytes in zPathname */ |
| 40629 | int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ |
| 40630 | int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */ |
| 40631 | int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ |
| 40632 | u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ |
| 40633 | |
| 40634 | /* Figure out how much space is required for each journal file-handle |
| 40635 | ** (there are two of them, the main journal and the sub-journal). This |
| 40636 | ** is the maximum space required for an in-memory journal file handle |
| 40637 | ** and a regular journal file-handle. Note that a "regular journal-handle" |
| @@ -40658,18 +41056,25 @@ | |
| 40658 | /* Compute and store the full pathname in an allocated buffer pointed |
| 40659 | ** to by zPathname, length nPathname. Or, if this is a temporary file, |
| 40660 | ** leave both nPathname and zPathname set to 0. |
| 40661 | */ |
| 40662 | if( zFilename && zFilename[0] ){ |
| 40663 | nPathname = pVfs->mxPathname+1; |
| 40664 | zPathname = sqlite3Malloc(nPathname*2); |
| 40665 | if( zPathname==0 ){ |
| 40666 | return SQLITE_NOMEM; |
| 40667 | } |
| 40668 | zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ |
| 40669 | rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); |
| 40670 | nPathname = sqlite3Strlen30(zPathname); |
| 40671 | if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ |
| 40672 | /* This branch is taken when the journal path required by |
| 40673 | ** the database being opened will be more than pVfs->mxPathname |
| 40674 | ** bytes in length. This means the database cannot be opened, |
| 40675 | ** as it will not be possible to open the journal file or even |
| @@ -40698,11 +41103,11 @@ | |
| 40698 | pPtr = (u8 *)sqlite3MallocZero( |
| 40699 | ROUND8(sizeof(*pPager)) + /* Pager structure */ |
| 40700 | ROUND8(pcacheSize) + /* PCache object */ |
| 40701 | ROUND8(pVfs->szOsFile) + /* The main db file */ |
| 40702 | journalFileSize * 2 + /* The two journal files */ |
| 40703 | nPathname + 1 + /* zFilename */ |
| 40704 | nPathname + 8 + 1 /* zJournal */ |
| 40705 | #ifndef SQLITE_OMIT_WAL |
| 40706 | + nPathname + 4 + 1 /* zWal */ |
| 40707 | #endif |
| 40708 | ); |
| @@ -40720,18 +41125,21 @@ | |
| 40720 | assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); |
| 40721 | |
| 40722 | /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ |
| 40723 | if( zPathname ){ |
| 40724 | assert( nPathname>0 ); |
| 40725 | pPager->zJournal = (char*)(pPtr += nPathname + 1); |
| 40726 | memcpy(pPager->zFilename, zPathname, nPathname); |
| 40727 | memcpy(pPager->zJournal, zPathname, nPathname); |
| 40728 | memcpy(&pPager->zJournal[nPathname], "-journal", 8); |
| 40729 | #ifndef SQLITE_OMIT_WAL |
| 40730 | pPager->zWal = &pPager->zJournal[nPathname+8+1]; |
| 40731 | memcpy(pPager->zWal, zPathname, nPathname); |
| 40732 | memcpy(&pPager->zWal[nPathname], "-wal", 4); |
| 40733 | #endif |
| 40734 | sqlite3_free(zPathname); |
| 40735 | } |
| 40736 | pPager->pVfs = pVfs; |
| 40737 | pPager->vfsFlags = vfsFlags; |
| @@ -42064,15 +42472,25 @@ | |
| 42064 | */ |
| 42065 | sqlite3BackupRestart(pPager->pBackup); |
| 42066 | }else{ |
| 42067 | if( pagerUseWal(pPager) ){ |
| 42068 | PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); |
| 42069 | if( pList ){ |
| 42070 | rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, |
| 42071 | (pPager->fullSync ? pPager->syncFlags : 0) |
| 42072 | ); |
| 42073 | } |
| 42074 | if( rc==SQLITE_OK ){ |
| 42075 | sqlite3PcacheCleanAll(pPager->pPCache); |
| 42076 | } |
| 42077 | }else{ |
| 42078 | /* The following block updates the change-counter. Exactly how it |
| @@ -42926,10 +43344,11 @@ | |
| 42926 | ** An attempt to set a limit smaller than -1 is a no-op. |
| 42927 | */ |
| 42928 | SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ |
| 42929 | if( iLimit>=-1 ){ |
| 42930 | pPager->journalSizeLimit = iLimit; |
| 42931 | } |
| 42932 | return pPager->journalSizeLimit; |
| 42933 | } |
| 42934 | |
| 42935 | /* |
| @@ -43017,11 +43436,12 @@ | |
| 43017 | /* Open the connection to the log file. If this operation fails, |
| 43018 | ** (e.g. due to malloc() failure), return an error code. |
| 43019 | */ |
| 43020 | if( rc==SQLITE_OK ){ |
| 43021 | rc = sqlite3WalOpen(pPager->pVfs, |
| 43022 | pPager->fd, pPager->zWal, pPager->exclusiveMode, &pPager->pWal |
| 43023 | ); |
| 43024 | } |
| 43025 | |
| 43026 | return rc; |
| 43027 | } |
| @@ -43549,10 +43969,11 @@ | |
| 43549 | struct Wal { |
| 43550 | sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ |
| 43551 | sqlite3_file *pDbFd; /* File handle for the database file */ |
| 43552 | sqlite3_file *pWalFd; /* File handle for WAL file */ |
| 43553 | u32 iCallback; /* Value to pass to log callback (or 0) */ |
| 43554 | int nWiData; /* Size of array apWiData */ |
| 43555 | volatile u32 **apWiData; /* Pointer to wal-index content in memory */ |
| 43556 | u32 szPage; /* Database page size */ |
| 43557 | i16 readLock; /* Which read lock is being held. -1 for none */ |
| 43558 | u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */ |
| @@ -44371,10 +44792,11 @@ | |
| 44371 | SQLITE_PRIVATE int sqlite3WalOpen( |
| 44372 | sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ |
| 44373 | sqlite3_file *pDbFd, /* The open database file */ |
| 44374 | const char *zWalName, /* Name of the WAL file */ |
| 44375 | int bNoShm, /* True to run in heap-memory mode */ |
| 44376 | Wal **ppWal /* OUT: Allocated Wal handle */ |
| 44377 | ){ |
| 44378 | int rc; /* Return Code */ |
| 44379 | Wal *pRet; /* Object to allocate and return */ |
| 44380 | int flags; /* Flags passed to OsOpen() */ |
| @@ -44403,10 +44825,11 @@ | |
| 44403 | |
| 44404 | pRet->pVfs = pVfs; |
| 44405 | pRet->pWalFd = (sqlite3_file *)&pRet[1]; |
| 44406 | pRet->pDbFd = pDbFd; |
| 44407 | pRet->readLock = -1; |
| 44408 | pRet->zWalName = zWalName; |
| 44409 | pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); |
| 44410 | |
| 44411 | /* Open file handle on the write-ahead log file. */ |
| 44412 | flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); |
| @@ -44423,10 +44846,17 @@ | |
| 44423 | *ppWal = pRet; |
| 44424 | WALTRACE(("WAL%d: opened\n", pRet)); |
| 44425 | } |
| 44426 | return rc; |
| 44427 | } |
| 44428 | |
| 44429 | /* |
| 44430 | ** Find the smallest page number out of all pages held in the WAL that |
| 44431 | ** has not been returned by any prior invocation of this method on the |
| 44432 | ** same WalIterator object. Write into *piFrame the frame index where |
| @@ -45659,10 +46089,26 @@ | |
| 45659 | ** safe and means there is no special case for sqlite3WalUndo() |
| 45660 | ** to handle if this transaction is rolled back. |
| 45661 | */ |
| 45662 | int i; /* Loop counter */ |
| 45663 | u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ |
| 45664 | pWal->nCkpt++; |
| 45665 | pWal->hdr.mxFrame = 0; |
| 45666 | sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); |
| 45667 | aSalt[1] = salt1; |
| 45668 | walIndexWriteHdr(pWal); |
| @@ -47764,10 +48210,11 @@ | |
| 47764 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 47765 | if( offset<0 ){ |
| 47766 | *pRC = SQLITE_CORRUPT_BKPT; |
| 47767 | goto ptrmap_exit; |
| 47768 | } |
| 47769 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 47770 | |
| 47771 | if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ |
| 47772 | TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); |
| 47773 | *pRC= rc = sqlite3PagerWrite(pDbPage); |
| @@ -47803,10 +48250,15 @@ | |
| 47803 | return rc; |
| 47804 | } |
| 47805 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 47806 | |
| 47807 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 47808 | assert( pEType!=0 ); |
| 47809 | *pEType = pPtrmap[offset]; |
| 47810 | if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); |
| 47811 | |
| 47812 | sqlite3PagerUnref(pDbPage); |
| @@ -48664,17 +49116,17 @@ | |
| 48664 | ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared |
| 48665 | ** objects in the same database connection since doing so will lead |
| 48666 | ** to problems with locking. |
| 48667 | */ |
| 48668 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 48669 | const char *zFilename, /* Name of the file containing the BTree database */ |
| 48670 | sqlite3 *db, /* Associated database handle */ |
| 48671 | Btree **ppBtree, /* Pointer to new Btree object written here */ |
| 48672 | int flags, /* Options */ |
| 48673 | int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ |
| 48674 | ){ |
| 48675 | sqlite3_vfs *pVfs; /* The VFS to use for this btree */ |
| 48676 | BtShared *pBt = 0; /* Shared part of btree structure */ |
| 48677 | Btree *p; /* Handle to return */ |
| 48678 | sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ |
| 48679 | int rc = SQLITE_OK; /* Result code from this function */ |
| 48680 | u8 nReserve; /* Byte of unused space on each page */ |
| @@ -48692,10 +49144,11 @@ | |
| 48692 | const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) |
| 48693 | || (isTempDb && sqlite3TempInMemory(db)); |
| 48694 | #endif |
| 48695 | |
| 48696 | assert( db!=0 ); |
| 48697 | assert( sqlite3_mutex_held(db->mutex) ); |
| 48698 | assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ |
| 48699 | |
| 48700 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ |
| 48701 | assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); |
| @@ -48710,11 +49163,10 @@ | |
| 48710 | flags |= BTREE_MEMORY; |
| 48711 | } |
| 48712 | if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ |
| 48713 | vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; |
| 48714 | } |
| 48715 | pVfs = db->pVfs; |
| 48716 | p = sqlite3MallocZero(sizeof(Btree)); |
| 48717 | if( !p ){ |
| 48718 | return SQLITE_NOMEM; |
| 48719 | } |
| 48720 | p->inTrans = TRANS_NONE; |
| @@ -58781,10 +59233,11 @@ | |
| 58781 | sqlite3_randomness(sizeof(iRandom), &iRandom); |
| 58782 | zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff); |
| 58783 | if( !zMaster ){ |
| 58784 | return SQLITE_NOMEM; |
| 58785 | } |
| 58786 | rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); |
| 58787 | }while( rc==SQLITE_OK && res ); |
| 58788 | if( rc==SQLITE_OK ){ |
| 58789 | /* Open the master journal. */ |
| 58790 | rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, |
| @@ -58994,10 +59447,19 @@ | |
| 58994 | } |
| 58995 | } |
| 58996 | } |
| 58997 | db->nStatement--; |
| 58998 | p->iStatement = 0; |
| 58999 | |
| 59000 | /* If the statement transaction is being rolled back, also restore the |
| 59001 | ** database handles deferred constraint counter to the value it had when |
| 59002 | ** the statement transaction was opened. */ |
| 59003 | if( eOp==SAVEPOINT_ROLLBACK ){ |
| @@ -59911,11 +60373,11 @@ | |
| 59911 | /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ |
| 59912 | VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ |
| 59913 | |
| 59914 | /* Compilers may complain that mem1.u.i is potentially uninitialized. |
| 59915 | ** We could initialize it, as shown here, to silence those complaints. |
| 59916 | ** But in fact, mem1.u.i will never actually be used initialized, and doing |
| 59917 | ** the unnecessary initialization has a measurable negative performance |
| 59918 | ** impact, since this routine is a very high runner. And so, we choose |
| 59919 | ** to ignore the compiler warnings and leave this variable uninitialized. |
| 59920 | */ |
| 59921 | /* mem1.u.i = 0; // not needed, here to silence compiler warning */ |
| @@ -62326,10 +62788,11 @@ | |
| 62326 | Mem *pIn2 = 0; /* 2nd input operand */ |
| 62327 | Mem *pIn3 = 0; /* 3rd input operand */ |
| 62328 | Mem *pOut = 0; /* Output operand */ |
| 62329 | int iCompare = 0; /* Result of last OP_Compare operation */ |
| 62330 | int *aPermute = 0; /* Permutation of columns for OP_Compare */ |
| 62331 | #ifdef VDBE_PROFILE |
| 62332 | u64 start; /* CPU clock count at start of opcode */ |
| 62333 | int origPc; /* Program counter at start of opcode */ |
| 62334 | #endif |
| 62335 | /******************************************************************** |
| @@ -63004,10 +63467,11 @@ | |
| 63004 | VdbeFrame *pFrame = p->pFrame; |
| 63005 | p->pFrame = pFrame->pParent; |
| 63006 | p->nFrame--; |
| 63007 | sqlite3VdbeSetChanges(db, p->nChange); |
| 63008 | pc = sqlite3VdbeFrameRestore(pFrame); |
| 63009 | if( pOp->p2==OE_Ignore ){ |
| 63010 | /* Instruction pc is the OP_Program that invoked the sub-program |
| 63011 | ** currently being halted. If the p2 instruction of this OP_Halt |
| 63012 | ** instruction is set to OE_Ignore, then the sub-program is throwing |
| 63013 | ** an IGNORE exception. In this case jump to the address specified |
| @@ -63576,11 +64040,13 @@ | |
| 63576 | assert( pOp>aOp ); |
| 63577 | assert( pOp[-1].p4type==P4_COLLSEQ ); |
| 63578 | assert( pOp[-1].opcode==OP_CollSeq ); |
| 63579 | u.ag.ctx.pColl = pOp[-1].p4.pColl; |
| 63580 | } |
| 63581 | (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */ |
| 63582 | if( db->mallocFailed ){ |
| 63583 | /* Even though a malloc() has failed, the implementation of the |
| 63584 | ** user function may have called an sqlite3_result_XXX() function |
| 63585 | ** to return a value. The following call releases any resources |
| 63586 | ** associated with such a value. |
| @@ -64783,10 +65249,18 @@ | |
| 64783 | "SQL statements in progress"); |
| 64784 | rc = SQLITE_BUSY; |
| 64785 | }else{ |
| 64786 | u.aq.nName = sqlite3Strlen30(u.aq.zName); |
| 64787 | |
| 64788 | /* Create a new savepoint structure. */ |
| 64789 | u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1); |
| 64790 | if( u.aq.pNew ){ |
| 64791 | u.aq.pNew->zName = (char *)&u.aq.pNew[1]; |
| 64792 | memcpy(u.aq.pNew->zName, u.aq.zName, u.aq.nName+1); |
| @@ -64889,10 +65363,15 @@ | |
| 64889 | db->nSavepoint--; |
| 64890 | } |
| 64891 | }else{ |
| 64892 | db->nDeferredCons = u.aq.pSavepoint->nDeferredCons; |
| 64893 | } |
| 64894 | } |
| 64895 | } |
| 64896 | |
| 64897 | break; |
| 64898 | } |
| @@ -65028,11 +65507,15 @@ | |
| 65028 | if( p->iStatement==0 ){ |
| 65029 | assert( db->nStatement>=0 && db->nSavepoint>=0 ); |
| 65030 | db->nStatement++; |
| 65031 | p->iStatement = db->nSavepoint + db->nStatement; |
| 65032 | } |
| 65033 | rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement); |
| 65034 | |
| 65035 | /* Store the current value of the database handles deferred constraint |
| 65036 | ** counter. If the statement transaction needs to be rolled back, |
| 65037 | ** the value of this counter needs to be restored too. */ |
| 65038 | p->nStmtDefCons = db->nDeferredCons; |
| @@ -65349,11 +65832,11 @@ | |
| 65349 | |
| 65350 | assert( pOp->p1>=0 ); |
| 65351 | u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); |
| 65352 | if( u.ax.pCx==0 ) goto no_mem; |
| 65353 | u.ax.pCx->nullRow = 1; |
| 65354 | rc = sqlite3BtreeOpen(0, db, &u.ax.pCx->pBt, |
| 65355 | BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); |
| 65356 | if( rc==SQLITE_OK ){ |
| 65357 | rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1); |
| 65358 | } |
| 65359 | if( rc==SQLITE_OK ){ |
| @@ -66023,11 +66506,11 @@ | |
| 66023 | ** engine starts picking positive candidate ROWIDs at random until |
| 66024 | ** it finds one that is not previously used. */ |
| 66025 | assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is |
| 66026 | ** an AUTOINCREMENT table. */ |
| 66027 | /* on the first attempt, simply do one more than previous */ |
| 66028 | u.be.v = db->lastRowid; |
| 66029 | u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ |
| 66030 | u.be.v++; /* ensure non-zero */ |
| 66031 | u.be.cnt = 0; |
| 66032 | while( ((rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v, |
| 66033 | 0, &u.be.res))==SQLITE_OK) |
| @@ -66135,11 +66618,11 @@ | |
| 66135 | assert( pOp->opcode==OP_InsertInt ); |
| 66136 | u.bf.iKey = pOp->p3; |
| 66137 | } |
| 66138 | |
| 66139 | if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
| 66140 | if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = u.bf.iKey; |
| 66141 | if( u.bf.pData->flags & MEM_Null ){ |
| 66142 | u.bf.pData->z = 0; |
| 66143 | u.bf.pData->n = 0; |
| 66144 | }else{ |
| 66145 | assert( u.bf.pData->flags & (MEM_Blob|MEM_Str) ); |
| @@ -67261,11 +67744,11 @@ | |
| 67261 | assert( pc==u.by.pFrame->pc ); |
| 67262 | } |
| 67263 | |
| 67264 | p->nFrame++; |
| 67265 | u.by.pFrame->pParent = p->pFrame; |
| 67266 | u.by.pFrame->lastRowid = db->lastRowid; |
| 67267 | u.by.pFrame->nChange = p->nChange; |
| 67268 | p->nChange = 0; |
| 67269 | p->pFrame = u.by.pFrame; |
| 67270 | p->aMem = aMem = &VdbeFrameMem(u.by.pFrame)[-1]; |
| 67271 | p->nMem = u.by.pFrame->nChildMem; |
| @@ -68072,31 +68555,45 @@ | |
| 68072 | sqlite_int64 rowid; |
| 68073 | Mem **apArg; |
| 68074 | Mem *pX; |
| 68075 | #endif /* local variables moved into u.cm */ |
| 68076 | |
| 68077 | u.cm.pVtab = pOp->p4.pVtab->pVtab; |
| 68078 | u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule; |
| 68079 | u.cm.nArg = pOp->p2; |
| 68080 | assert( pOp->p4type==P4_VTAB ); |
| 68081 | if( ALWAYS(u.cm.pModule->xUpdate) ){ |
| 68082 | u.cm.apArg = p->apArg; |
| 68083 | u.cm.pX = &aMem[pOp->p3]; |
| 68084 | for(u.cm.i=0; u.cm.i<u.cm.nArg; u.cm.i++){ |
| 68085 | assert( memIsValid(u.cm.pX) ); |
| 68086 | memAboutToChange(p, u.cm.pX); |
| 68087 | sqlite3VdbeMemStoreType(u.cm.pX); |
| 68088 | u.cm.apArg[u.cm.i] = u.cm.pX; |
| 68089 | u.cm.pX++; |
| 68090 | } |
| 68091 | rc = u.cm.pModule->xUpdate(u.cm.pVtab, u.cm.nArg, u.cm.apArg, &u.cm.rowid); |
| 68092 | importVtabErrMsg(p, u.cm.pVtab); |
| 68093 | if( rc==SQLITE_OK && pOp->p1 ){ |
| 68094 | assert( u.cm.nArg>1 && u.cm.apArg[0] && (u.cm.apArg[0]->flags&MEM_Null) ); |
| 68095 | db->lastRowid = u.cm.rowid; |
| 68096 | } |
| 68097 | p->nChange++; |
| 68098 | } |
| 68099 | break; |
| 68100 | } |
| 68101 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 68102 | |
| @@ -68242,10 +68739,11 @@ | |
| 68242 | |
| 68243 | /* This is the only way out of this procedure. We have to |
| 68244 | ** release the mutexes on btrees that were acquired at the |
| 68245 | ** top. */ |
| 68246 | vdbe_return: |
| 68247 | sqlite3VdbeLeave(p); |
| 68248 | return rc; |
| 68249 | |
| 68250 | /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH |
| 68251 | ** is encountered. |
| @@ -75970,12 +76468,16 @@ | |
| 75970 | int i; |
| 75971 | int rc = 0; |
| 75972 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 75973 | const char *zName; |
| 75974 | const char *zFile; |
| 75975 | Db *aNew; |
| 75976 | char *zErrDyn = 0; |
| 75977 | |
| 75978 | UNUSED_PARAMETER(NotUsed); |
| 75979 | |
| 75980 | zFile = (const char *)sqlite3_value_text(argv[0]); |
| 75981 | zName = (const char *)sqlite3_value_text(argv[1]); |
| @@ -76024,12 +76526,22 @@ | |
| 76024 | |
| 76025 | /* Open the database file. If the btree is successfully opened, use |
| 76026 | ** it to obtain the database schema. At this point the schema may |
| 76027 | ** or may not be initialised. |
| 76028 | */ |
| 76029 | rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0, |
| 76030 | db->openFlags | SQLITE_OPEN_MAIN_DB); |
| 76031 | db->nDb++; |
| 76032 | if( rc==SQLITE_CONSTRAINT ){ |
| 76033 | rc = SQLITE_ERROR; |
| 76034 | zErrDyn = sqlite3MPrintf(db, "database is already attached"); |
| 76035 | }else if( rc==SQLITE_OK ){ |
| @@ -80139,11 +80651,11 @@ | |
| 80139 | SQLITE_OPEN_CREATE | |
| 80140 | SQLITE_OPEN_EXCLUSIVE | |
| 80141 | SQLITE_OPEN_DELETEONCLOSE | |
| 80142 | SQLITE_OPEN_TEMP_DB; |
| 80143 | |
| 80144 | rc = sqlite3BtreeOpen(0, db, &pBt, 0, flags); |
| 80145 | if( rc!=SQLITE_OK ){ |
| 80146 | sqlite3ErrorMsg(pParse, "unable to open a temporary database " |
| 80147 | "file for storing temporary tables"); |
| 80148 | pParse->rc = rc; |
| 80149 | return 1; |
| @@ -82329,10 +82841,25 @@ | |
| 82329 | UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| 82330 | /* IMP: R-24470-31136 This function is an SQL wrapper around the |
| 82331 | ** sqlite3_sourceid() C interface. */ |
| 82332 | sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); |
| 82333 | } |
| 82334 | |
| 82335 | /* |
| 82336 | ** Implementation of the sqlite_compileoption_used() function. |
| 82337 | ** The result is an integer that identifies if the compiler option |
| 82338 | ** was used to build SQLite. |
| @@ -83097,10 +83624,11 @@ | |
| 83097 | FUNCTION(random, 0, 0, 0, randomFunc ), |
| 83098 | FUNCTION(randomblob, 1, 0, 0, randomBlob ), |
| 83099 | FUNCTION(nullif, 2, 0, 1, nullifFunc ), |
| 83100 | FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), |
| 83101 | FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), |
| 83102 | #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| 83103 | FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), |
| 83104 | FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), |
| 83105 | #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
| 83106 | FUNCTION(quote, 1, 0, 0, quoteFunc ), |
| @@ -85309,10 +85837,11 @@ | |
| 85309 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 85310 | if( IsVirtual(pTab) ){ |
| 85311 | const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); |
| 85312 | sqlite3VtabMakeWritable(pParse, pTab); |
| 85313 | sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); |
| 85314 | sqlite3MayAbort(pParse); |
| 85315 | }else |
| 85316 | #endif |
| 85317 | { |
| 85318 | int isReplace; /* Set to true if constraints may cause a replace */ |
| @@ -86073,10 +86602,22 @@ | |
| 86073 | } |
| 86074 | #ifndef SQLITE_OMIT_CHECK |
| 86075 | if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){ |
| 86076 | return 0; /* Tables have different CHECK constraints. Ticket #2252 */ |
| 86077 | } |
| 86078 | #endif |
| 86079 | |
| 86080 | /* If we get this far, it means either: |
| 86081 | ** |
| 86082 | ** * We can always do the transfer if the table contains an |
| @@ -87442,11 +87983,11 @@ | |
| 87442 | } |
| 87443 | |
| 87444 | /* |
| 87445 | ** Interpret the given string as a boolean value. |
| 87446 | */ |
| 87447 | static u8 getBoolean(const char *z){ |
| 87448 | return getSafetyLevel(z)&1; |
| 87449 | } |
| 87450 | |
| 87451 | /* |
| 87452 | ** Interpret the given string as a locking mode value. |
| @@ -87612,11 +88153,11 @@ | |
| 87612 | /* Foreign key support may not be enabled or disabled while not |
| 87613 | ** in auto-commit mode. */ |
| 87614 | mask &= ~(SQLITE_ForeignKeys); |
| 87615 | } |
| 87616 | |
| 87617 | if( getBoolean(zRight) ){ |
| 87618 | db->flags |= mask; |
| 87619 | }else{ |
| 87620 | db->flags &= ~mask; |
| 87621 | } |
| 87622 | |
| @@ -87826,11 +88367,11 @@ | |
| 87826 | if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){ |
| 87827 | Btree *pBt = pDb->pBt; |
| 87828 | int b = -1; |
| 87829 | assert( pBt!=0 ); |
| 87830 | if( zRight ){ |
| 87831 | b = getBoolean(zRight); |
| 87832 | } |
| 87833 | if( pId2->n==0 && b>=0 ){ |
| 87834 | int ii; |
| 87835 | for(ii=0; ii<db->nDb; ii++){ |
| 87836 | sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b); |
| @@ -88426,11 +88967,11 @@ | |
| 88426 | #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ |
| 88427 | |
| 88428 | #ifndef NDEBUG |
| 88429 | if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ |
| 88430 | if( zRight ){ |
| 88431 | if( getBoolean(zRight) ){ |
| 88432 | sqlite3ParserTrace(stderr, "parser: "); |
| 88433 | }else{ |
| 88434 | sqlite3ParserTrace(0, 0); |
| 88435 | } |
| 88436 | } |
| @@ -88440,11 +88981,11 @@ | |
| 88440 | /* Reinstall the LIKE and GLOB functions. The variant of LIKE |
| 88441 | ** used will be case sensitive or not depending on the RHS. |
| 88442 | */ |
| 88443 | if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ |
| 88444 | if( zRight ){ |
| 88445 | sqlite3RegisterLikeFunctions(db, getBoolean(zRight)); |
| 88446 | } |
| 88447 | }else |
| 88448 | |
| 88449 | #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX |
| 88450 | # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 |
| @@ -94017,16 +94558,18 @@ | |
| 94017 | ** does, then we can assume that it consumes less space on disk and |
| 94018 | ** will therefore be cheaper to scan to determine the query result. |
| 94019 | ** In this case set iRoot to the root page number of the index b-tree |
| 94020 | ** and pKeyInfo to the KeyInfo structure required to navigate the |
| 94021 | ** index. |
| 94022 | ** |
| 94023 | ** In practice the KeyInfo structure will not be used. It is only |
| 94024 | ** passed to keep OP_OpenRead happy. |
| 94025 | */ |
| 94026 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 94027 | if( !pBest || pIdx->nColumn<pBest->nColumn ){ |
| 94028 | pBest = pIdx; |
| 94029 | } |
| 94030 | } |
| 94031 | if( pBest && pBest->nColumn<pTab->nCol ){ |
| 94032 | iRoot = pBest->tnum; |
| @@ -95579,11 +96122,12 @@ | |
| 95579 | SrcList *pSrc, /* The virtual table to be modified */ |
| 95580 | Table *pTab, /* The virtual table */ |
| 95581 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 95582 | Expr *pRowidExpr, /* Expression used to recompute the rowid */ |
| 95583 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 95584 | Expr *pWhere /* WHERE clause of the UPDATE statement */ |
| 95585 | ); |
| 95586 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 95587 | |
| 95588 | /* |
| 95589 | ** The most recently coded instruction was an OP_Column to retrieve the |
| @@ -95823,11 +96367,11 @@ | |
| 95823 | |
| 95824 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 95825 | /* Virtual tables must be handled separately */ |
| 95826 | if( IsVirtual(pTab) ){ |
| 95827 | updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, |
| 95828 | pWhere); |
| 95829 | pWhere = 0; |
| 95830 | pTabList = 0; |
| 95831 | goto update_cleanup; |
| 95832 | } |
| 95833 | #endif |
| @@ -96153,11 +96697,12 @@ | |
| 96153 | SrcList *pSrc, /* The virtual table to be modified */ |
| 96154 | Table *pTab, /* The virtual table */ |
| 96155 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 96156 | Expr *pRowid, /* Expression used to recompute the rowid */ |
| 96157 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 96158 | Expr *pWhere /* WHERE clause of the UPDATE statement */ |
| 96159 | ){ |
| 96160 | Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ |
| 96161 | ExprList *pEList = 0; /* The result set of the SELECT statement */ |
| 96162 | Select *pSelect = 0; /* The SELECT statement */ |
| 96163 | Expr *pExpr; /* Temporary expression */ |
| @@ -96210,10 +96755,11 @@ | |
| 96210 | for(i=0; i<pTab->nCol; i++){ |
| 96211 | sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); |
| 96212 | } |
| 96213 | sqlite3VtabMakeWritable(pParse, pTab); |
| 96214 | sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); |
| 96215 | sqlite3MayAbort(pParse); |
| 96216 | sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); |
| 96217 | sqlite3VdbeJumpHere(v, addr); |
| 96218 | sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); |
| 96219 | |
| @@ -96583,10 +97129,22 @@ | |
| 96583 | ************************************************************************* |
| 96584 | ** This file contains code used to help implement virtual tables. |
| 96585 | */ |
| 96586 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 96587 | |
| 96588 | /* |
| 96589 | ** The actual function that does the work of creating a new module. |
| 96590 | ** This function implements the sqlite3_create_module() and |
| 96591 | ** sqlite3_create_module_v2() interfaces. |
| 96592 | */ |
| @@ -96611,17 +97169,17 @@ | |
| 96611 | pMod->pModule = pModule; |
| 96612 | pMod->pAux = pAux; |
| 96613 | pMod->xDestroy = xDestroy; |
| 96614 | pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); |
| 96615 | if( pDel && pDel->xDestroy ){ |
| 96616 | pDel->xDestroy(pDel->pAux); |
| 96617 | } |
| 96618 | sqlite3DbFree(db, pDel); |
| 96619 | if( pDel==pMod ){ |
| 96620 | db->mallocFailed = 1; |
| 96621 | } |
| 96622 | sqlite3ResetInternalSchema(db, -1); |
| 96623 | }else if( xDestroy ){ |
| 96624 | xDestroy(pAux); |
| 96625 | } |
| 96626 | rc = sqlite3ApiExit(db, SQLITE_OK); |
| 96627 | sqlite3_mutex_leave(db->mutex); |
| @@ -97003,10 +97561,11 @@ | |
| 97003 | Table *pTab, |
| 97004 | Module *pMod, |
| 97005 | int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), |
| 97006 | char **pzErr |
| 97007 | ){ |
| 97008 | VTable *pVTable; |
| 97009 | int rc; |
| 97010 | const char *const*azArg = (const char *const*)pTab->azModuleArg; |
| 97011 | int nArg = pTab->nModuleArg; |
| 97012 | char *zErr = 0; |
| @@ -97022,16 +97581,18 @@ | |
| 97022 | return SQLITE_NOMEM; |
| 97023 | } |
| 97024 | pVTable->db = db; |
| 97025 | pVTable->pMod = pMod; |
| 97026 | |
| 97027 | assert( !db->pVTab ); |
| 97028 | assert( xConstruct ); |
| 97029 | db->pVTab = pTab; |
| 97030 | |
| 97031 | /* Invoke the virtual table constructor */ |
| 97032 | rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); |
| 97033 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 97034 | |
| 97035 | if( SQLITE_OK!=rc ){ |
| 97036 | if( zErr==0 ){ |
| 97037 | *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); |
| @@ -97043,11 +97604,11 @@ | |
| 97043 | }else if( ALWAYS(pVTable->pVtab) ){ |
| 97044 | /* Justification of ALWAYS(): A correct vtab constructor must allocate |
| 97045 | ** the sqlite3_vtab object if successful. */ |
| 97046 | pVTable->pVtab->pModule = pMod->pModule; |
| 97047 | pVTable->nRef = 1; |
| 97048 | if( db->pVTab ){ |
| 97049 | const char *zFormat = "vtable constructor did not declare schema: %s"; |
| 97050 | *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); |
| 97051 | sqlite3VtabUnlock(pVTable); |
| 97052 | rc = SQLITE_ERROR; |
| 97053 | }else{ |
| @@ -97091,11 +97652,10 @@ | |
| 97091 | } |
| 97092 | } |
| 97093 | } |
| 97094 | |
| 97095 | sqlite3DbFree(db, zModuleName); |
| 97096 | db->pVTab = 0; |
| 97097 | return rc; |
| 97098 | } |
| 97099 | |
| 97100 | /* |
| 97101 | ** This function is invoked by the parser to call the xConnect() method |
| @@ -97211,12 +97771,11 @@ | |
| 97211 | int rc = SQLITE_OK; |
| 97212 | Table *pTab; |
| 97213 | char *zErr = 0; |
| 97214 | |
| 97215 | sqlite3_mutex_enter(db->mutex); |
| 97216 | pTab = db->pVTab; |
| 97217 | if( !pTab ){ |
| 97218 | sqlite3Error(db, SQLITE_MISUSE, 0); |
| 97219 | sqlite3_mutex_leave(db->mutex); |
| 97220 | return SQLITE_MISUSE_BKPT; |
| 97221 | } |
| 97222 | assert( (pTab->tabFlags & TF_Virtual)!=0 ); |
| @@ -97239,11 +97798,11 @@ | |
| 97239 | pTab->aCol = pParse->pNewTable->aCol; |
| 97240 | pTab->nCol = pParse->pNewTable->nCol; |
| 97241 | pParse->pNewTable->nCol = 0; |
| 97242 | pParse->pNewTable->aCol = 0; |
| 97243 | } |
| 97244 | db->pVTab = 0; |
| 97245 | }else{ |
| 97246 | sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); |
| 97247 | sqlite3DbFree(db, zErr); |
| 97248 | rc = SQLITE_ERROR; |
| 97249 | } |
| @@ -97391,11 +97950,10 @@ | |
| 97391 | pModule = pVTab->pVtab->pModule; |
| 97392 | |
| 97393 | if( pModule->xBegin ){ |
| 97394 | int i; |
| 97395 | |
| 97396 | |
| 97397 | /* If pVtab is already in the aVTrans array, return early */ |
| 97398 | for(i=0; i<db->nVTrans; i++){ |
| 97399 | if( db->aVTrans[i]==pVTab ){ |
| 97400 | return SQLITE_OK; |
| 97401 | } |
| @@ -97404,10 +97962,53 @@ | |
| 97404 | /* Invoke the xBegin method */ |
| 97405 | rc = pModule->xBegin(pVTab->pVtab); |
| 97406 | if( rc==SQLITE_OK ){ |
| 97407 | rc = addToVTrans(db, pVTab); |
| 97408 | } |
| 97409 | } |
| 97410 | return rc; |
| 97411 | } |
| 97412 | |
| 97413 | /* |
| @@ -97505,10 +98106,61 @@ | |
| 97505 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; |
| 97506 | }else{ |
| 97507 | pToplevel->db->mallocFailed = 1; |
| 97508 | } |
| 97509 | } |
| 97510 | |
| 97511 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 97512 | |
| 97513 | /************** End of vtab.c ************************************************/ |
| 97514 | /************** Begin file where.c *******************************************/ |
| @@ -107527,10 +108179,15 @@ | |
| 107527 | typedef void(*LOGFUNC_t)(void*,int,const char*); |
| 107528 | sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); |
| 107529 | sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); |
| 107530 | break; |
| 107531 | } |
| 107532 | |
| 107533 | default: { |
| 107534 | rc = SQLITE_ERROR; |
| 107535 | break; |
| 107536 | } |
| @@ -108886,25 +109543,257 @@ | |
| 108886 | } |
| 108887 | db->aLimit[limitId] = newLimit; |
| 108888 | } |
| 108889 | return oldLimit; /* IMP: R-53341-35419 */ |
| 108890 | } |
| 108891 | |
| 108892 | /* |
| 108893 | ** This routine does the work of opening a database on behalf of |
| 108894 | ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" |
| 108895 | ** is UTF-8 encoded. |
| 108896 | */ |
| 108897 | static int openDatabase( |
| 108898 | const char *zFilename, /* Database filename UTF-8 encoded */ |
| 108899 | sqlite3 **ppDb, /* OUT: Returned database handle */ |
| 108900 | unsigned flags, /* Operational flags */ |
| 108901 | const char *zVfs /* Name of the VFS to use */ |
| 108902 | ){ |
| 108903 | sqlite3 *db; |
| 108904 | int rc; |
| 108905 | int isThreadsafe; |
| 108906 | |
| 108907 | *ppDb = 0; |
| 108908 | #ifndef SQLITE_OMIT_AUTOINIT |
| 108909 | rc = sqlite3_initialize(); |
| 108910 | if( rc ) return rc; |
| @@ -108924,11 +109813,11 @@ | |
| 108924 | assert( SQLITE_OPEN_READWRITE == 0x02 ); |
| 108925 | assert( SQLITE_OPEN_CREATE == 0x04 ); |
| 108926 | testcase( (1<<(flags&7))==0x02 ); /* READONLY */ |
| 108927 | testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ |
| 108928 | testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ |
| 108929 | if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE; |
| 108930 | |
| 108931 | if( sqlite3GlobalConfig.bCoreMutex==0 ){ |
| 108932 | isThreadsafe = 0; |
| 108933 | }else if( flags & SQLITE_OPEN_NOMUTEX ){ |
| 108934 | isThreadsafe = 0; |
| @@ -109005,17 +109894,10 @@ | |
| 109005 | sqlite3HashInit(&db->aCollSeq); |
| 109006 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 109007 | sqlite3HashInit(&db->aModule); |
| 109008 | #endif |
| 109009 | |
| 109010 | db->pVfs = sqlite3_vfs_find(zVfs); |
| 109011 | if( !db->pVfs ){ |
| 109012 | rc = SQLITE_ERROR; |
| 109013 | sqlite3Error(db, rc, "no such vfs: %s", zVfs); |
| 109014 | goto opendb_out; |
| 109015 | } |
| 109016 | |
| 109017 | /* Add the default collation sequence BINARY. BINARY works for both UTF-8 |
| 109018 | ** and UTF-16, so add a version for each to avoid any unnecessary |
| 109019 | ** conversions. The only error that can occur here is a malloc() failure. |
| 109020 | */ |
| 109021 | createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0, |
| @@ -109034,13 +109916,22 @@ | |
| 109034 | |
| 109035 | /* Also add a UTF-8 case-insensitive collation sequence. */ |
| 109036 | createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0, |
| 109037 | nocaseCollatingFunc, 0); |
| 109038 | |
| 109039 | /* Open the backend database driver */ |
| 109040 | db->openFlags = flags; |
| 109041 | rc = sqlite3BtreeOpen(zFilename, db, &db->aDb[0].pBt, 0, |
| 109042 | flags | SQLITE_OPEN_MAIN_DB); |
| 109043 | if( rc!=SQLITE_OK ){ |
| 109044 | if( rc==SQLITE_IOERR_NOMEM ){ |
| 109045 | rc = SQLITE_NOMEM; |
| 109046 | } |
| @@ -109129,10 +110020,11 @@ | |
| 109129 | sqlite3GlobalConfig.nLookaside); |
| 109130 | |
| 109131 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 109132 | |
| 109133 | opendb_out: |
| 109134 | if( db ){ |
| 109135 | assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); |
| 109136 | sqlite3_mutex_leave(db->mutex); |
| 109137 | } |
| 109138 | rc = sqlite3_errcode(db); |
| @@ -109160,11 +110052,11 @@ | |
| 109160 | const char *filename, /* Database filename (UTF-8) */ |
| 109161 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 109162 | int flags, /* Flags */ |
| 109163 | const char *zVfs /* Name of VFS module to use */ |
| 109164 | ){ |
| 109165 | return openDatabase(filename, ppDb, flags, zVfs); |
| 109166 | } |
| 109167 | |
| 109168 | #ifndef SQLITE_OMIT_UTF16 |
| 109169 | /* |
| 109170 | ** Open a new database handle. |
| @@ -109770,10 +110662,32 @@ | |
| 109770 | } |
| 109771 | va_end(ap); |
| 109772 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 109773 | return rc; |
| 109774 | } |
| 109775 | |
| 109776 | /************** End of main.c ************************************************/ |
| 109777 | /************** Begin file notify.c ******************************************/ |
| 109778 | /* |
| 109779 | ** 2009 March 3 |
| @@ -110851,10 +111765,11 @@ | |
| 110851 | Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ |
| 110852 | sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ |
| 110853 | char *pNextId; /* Pointer into the body of aDoclist */ |
| 110854 | char *aDoclist; /* List of docids for full-text queries */ |
| 110855 | int nDoclist; /* Size of buffer at aDoclist */ |
| 110856 | int eEvalmode; /* An FTS3_EVAL_XX constant */ |
| 110857 | int nRowAvg; /* Average size of database rows, in pages */ |
| 110858 | |
| 110859 | int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ |
| 110860 | u32 *aMatchinfo; /* Information about most recent match */ |
| @@ -111033,11 +111948,11 @@ | |
| 111033 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 111034 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 111035 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 111036 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 111037 | |
| 111038 | SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Expr *, sqlite3_int64, int); |
| 111039 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *); |
| 111040 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *); |
| 111041 | SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int); |
| 111042 | |
| 111043 | /* fts3_tokenizer.c */ |
| @@ -111060,10 +111975,11 @@ | |
| 111060 | char **, int, int, const char *, int, Fts3Expr ** |
| 111061 | ); |
| 111062 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 111063 | #ifdef SQLITE_TEST |
| 111064 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 111065 | #endif |
| 111066 | |
| 111067 | /* fts3_aux.c */ |
| 111068 | SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); |
| 111069 | |
| @@ -111180,10 +112096,38 @@ | |
| 111180 | static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ |
| 111181 | sqlite3_int64 iVal; |
| 111182 | *pp += sqlite3Fts3GetVarint(*pp, &iVal); |
| 111183 | *pVal += iVal; |
| 111184 | } |
| 111185 | |
| 111186 | /* |
| 111187 | ** As long as *pp has not reached its end (pEnd), then do the same |
| 111188 | ** as fts3GetDeltaVarint(): read a single varint and add it to *pVal. |
| 111189 | ** But if we have reached the end of the varint, just set *pp=0 and |
| @@ -111285,10 +112229,12 @@ | |
| 111285 | if( *pRc==SQLITE_OK ){ |
| 111286 | int i; /* Iterator variable */ |
| 111287 | int rc; /* Return code */ |
| 111288 | char *zSql; /* SQL statement passed to declare_vtab() */ |
| 111289 | char *zCols; /* List of user defined columns */ |
| 111290 | |
| 111291 | /* Create a list of user columns for the virtual table */ |
| 111292 | zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); |
| 111293 | for(i=1; zCols && i<p->nColumn; i++){ |
| 111294 | zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); |
| @@ -111854,10 +112800,26 @@ | |
| 111854 | |
| 111855 | if( iCons>=0 ){ |
| 111856 | pInfo->aConstraintUsage[iCons].argvIndex = 1; |
| 111857 | pInfo->aConstraintUsage[iCons].omit = 1; |
| 111858 | } |
| 111859 | return SQLITE_OK; |
| 111860 | } |
| 111861 | |
| 111862 | /* |
| 111863 | ** Implementation of xOpen method. |
| @@ -111911,11 +112873,11 @@ | |
| 111911 | if( rc==SQLITE_OK ){ |
| 111912 | /* If no row was found and no error has occured, then the %_content |
| 111913 | ** table is missing a row that is present in the full-text index. |
| 111914 | ** The data structures are corrupt. |
| 111915 | */ |
| 111916 | rc = SQLITE_CORRUPT; |
| 111917 | } |
| 111918 | pCsr->isEof = 1; |
| 111919 | if( pContext ){ |
| 111920 | sqlite3_result_error_code(pContext, rc); |
| 111921 | } |
| @@ -111971,11 +112933,11 @@ | |
| 111971 | ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). |
| 111972 | */ |
| 111973 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 111974 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 111975 | if( zCsr>zEnd ){ |
| 111976 | return SQLITE_CORRUPT; |
| 111977 | } |
| 111978 | |
| 111979 | while( zCsr<zEnd && (piFirst || piLast) ){ |
| 111980 | int cmp; /* memcmp() result */ |
| 111981 | int nSuffix; /* Size of term suffix */ |
| @@ -111989,11 +112951,11 @@ | |
| 111989 | } |
| 111990 | isFirstTerm = 0; |
| 111991 | zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix); |
| 111992 | |
| 111993 | if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){ |
| 111994 | rc = SQLITE_CORRUPT; |
| 111995 | goto finish_scan; |
| 111996 | } |
| 111997 | if( nPrefix+nSuffix>nAlloc ){ |
| 111998 | char *zNew; |
| 111999 | nAlloc = (nPrefix+nSuffix) * 2; |
| @@ -113758,16 +114720,24 @@ | |
| 113758 | rc = sqlite3_reset(pCsr->pStmt); |
| 113759 | break; |
| 113760 | } |
| 113761 | pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); |
| 113762 | }else{ |
| 113763 | if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ |
| 113764 | pCsr->isEof = 1; |
| 113765 | break; |
| 113766 | } |
| 113767 | sqlite3_reset(pCsr->pStmt); |
| 113768 | fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); |
| 113769 | pCsr->isRequireSeek = 1; |
| 113770 | pCsr->isMatchinfoNeeded = 1; |
| 113771 | } |
| 113772 | }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 ); |
| 113773 | |
| @@ -113796,12 +114766,12 @@ | |
| 113796 | const char *idxStr, /* Unused */ |
| 113797 | int nVal, /* Number of elements in apVal */ |
| 113798 | sqlite3_value **apVal /* Arguments for the indexing scheme */ |
| 113799 | ){ |
| 113800 | const char *azSql[] = { |
| 113801 | "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ |
| 113802 | "SELECT %s FROM %Q.'%q_content' AS x ", /* full-scan */ |
| 113803 | }; |
| 113804 | int rc; /* Return code */ |
| 113805 | char *zSql; /* SQL statement used to access %_content */ |
| 113806 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; |
| 113807 | Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; |
| @@ -113853,11 +114823,13 @@ | |
| 113853 | ** statement loops through all rows of the %_content table. For a |
| 113854 | ** full-text query or docid lookup, the statement retrieves a single |
| 113855 | ** row by docid. |
| 113856 | */ |
| 113857 | zSql = (char *)azSql[idxNum==FTS3_FULLSCAN_SEARCH]; |
| 113858 | zSql = sqlite3_mprintf(zSql, p->zReadExprlist, p->zDb, p->zName); |
| 113859 | if( !zSql ){ |
| 113860 | rc = SQLITE_NOMEM; |
| 113861 | }else{ |
| 113862 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 113863 | sqlite3_free(zSql); |
| @@ -113865,11 +114837,26 @@ | |
| 113865 | if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){ |
| 113866 | rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); |
| 113867 | } |
| 113868 | pCsr->eSearch = (i16)idxNum; |
| 113869 | |
| 113870 | if( rc!=SQLITE_OK ) return rc; |
| 113871 | return fts3NextMethod(pCursor); |
| 113872 | } |
| 113873 | |
| 113874 | /* |
| 113875 | ** This is the xEof method of the virtual table. SQLite calls this |
| @@ -114017,17 +115004,37 @@ | |
| 114017 | pCsr->eEvalmode = FTS3_EVAL_MATCHINFO; |
| 114018 | rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1); |
| 114019 | pCsr->eEvalmode = FTS3_EVAL_NEXT; |
| 114020 | return rc; |
| 114021 | } |
| 114022 | |
| 114023 | /* |
| 114024 | ** After ExprLoadDoclist() (see above) has been called, this function is |
| 114025 | ** used to iterate/search through the position lists that make up the doclist |
| 114026 | ** stored in pExpr->aDoclist. |
| 114027 | */ |
| 114028 | SQLITE_PRIVATE char *sqlite3Fts3FindPositions( |
| 114029 | Fts3Expr *pExpr, /* Access this expressions doclist */ |
| 114030 | sqlite3_int64 iDocid, /* Docid associated with requested pos-list */ |
| 114031 | int iCol /* Column of requested pos-list */ |
| 114032 | ){ |
| 114033 | assert( pExpr->isLoaded ); |
| @@ -114034,23 +115041,39 @@ | |
| 114034 | if( pExpr->aDoclist ){ |
| 114035 | char *pEnd = &pExpr->aDoclist[pExpr->nDoclist]; |
| 114036 | char *pCsr; |
| 114037 | |
| 114038 | if( pExpr->pCurrent==0 ){ |
| 114039 | pExpr->pCurrent = pExpr->aDoclist; |
| 114040 | pExpr->iCurrent = 0; |
| 114041 | pExpr->pCurrent += sqlite3Fts3GetVarint(pExpr->pCurrent,&pExpr->iCurrent); |
| 114042 | } |
| 114043 | pCsr = pExpr->pCurrent; |
| 114044 | assert( pCsr ); |
| 114045 | |
| 114046 | while( pCsr<pEnd ){ |
| 114047 | if( pExpr->iCurrent<iDocid ){ |
| 114048 | fts3PoslistCopy(0, &pCsr); |
| 114049 | if( pCsr<pEnd ){ |
| 114050 | fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent); |
| 114051 | } |
| 114052 | pExpr->pCurrent = pCsr; |
| 114053 | }else{ |
| 114054 | if( pExpr->iCurrent==iDocid ){ |
| 114055 | int iThis = 0; |
| 114056 | if( iCol<0 ){ |
| @@ -114303,13 +115326,24 @@ | |
| 114303 | "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", |
| 114304 | p->zDb, p->zName, zName |
| 114305 | ); |
| 114306 | return rc; |
| 114307 | } |
| 114308 | |
| 114309 | static const sqlite3_module fts3Module = { |
| 114310 | /* iVersion */ 0, |
| 114311 | /* xCreate */ fts3CreateMethod, |
| 114312 | /* xConnect */ fts3ConnectMethod, |
| 114313 | /* xBestIndex */ fts3BestIndexMethod, |
| 114314 | /* xDisconnect */ fts3DisconnectMethod, |
| 114315 | /* xDestroy */ fts3DestroyMethod, |
| @@ -114325,10 +115359,13 @@ | |
| 114325 | /* xSync */ fts3SyncMethod, |
| 114326 | /* xCommit */ fts3CommitMethod, |
| 114327 | /* xRollback */ fts3RollbackMethod, |
| 114328 | /* xFindFunction */ fts3FindFunctionMethod, |
| 114329 | /* xRename */ fts3RenameMethod, |
| 114330 | }; |
| 114331 | |
| 114332 | /* |
| 114333 | ** This function is registered as the module destructor (called when an |
| 114334 | ** FTS3 enabled database connection is closed). It frees the memory |
| @@ -114370,10 +115407,15 @@ | |
| 114370 | |
| 114371 | #ifdef SQLITE_ENABLE_ICU |
| 114372 | const sqlite3_tokenizer_module *pIcu = 0; |
| 114373 | sqlite3Fts3IcuTokenizerModule(&pIcu); |
| 114374 | #endif |
| 114375 | |
| 114376 | rc = sqlite3Fts3InitAux(db); |
| 114377 | if( rc!=SQLITE_OK ) return rc; |
| 114378 | |
| 114379 | sqlite3Fts3SimpleTokenizerModule(&pSimple); |
| @@ -117891,11 +118933,11 @@ | |
| 117891 | sqlite3_bind_int64(pStmt, 1, iDocid); |
| 117892 | } |
| 117893 | rc = sqlite3_step(pStmt); |
| 117894 | if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ |
| 117895 | rc = sqlite3_reset(pStmt); |
| 117896 | if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT; |
| 117897 | pStmt = 0; |
| 117898 | }else{ |
| 117899 | rc = SQLITE_OK; |
| 117900 | } |
| 117901 | } |
| @@ -118141,10 +119183,18 @@ | |
| 118141 | sqlite3_tokenizer_cursor *pCsr; |
| 118142 | int (*xNext)(sqlite3_tokenizer_cursor *pCursor, |
| 118143 | const char**,int*,int*,int*,int*); |
| 118144 | |
| 118145 | assert( pTokenizer && pModule ); |
| 118146 | |
| 118147 | rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr); |
| 118148 | if( rc!=SQLITE_OK ){ |
| 118149 | return rc; |
| 118150 | } |
| @@ -118232,15 +119282,13 @@ | |
| 118232 | */ |
| 118233 | static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){ |
| 118234 | int i; /* Iterator variable */ |
| 118235 | for(i=2; i<p->nColumn+2; i++){ |
| 118236 | const char *zText = (const char *)sqlite3_value_text(apVal[i]); |
| 118237 | if( zText ){ |
| 118238 | int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); |
| 118239 | if( rc!=SQLITE_OK ){ |
| 118240 | return rc; |
| 118241 | } |
| 118242 | } |
| 118243 | aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); |
| 118244 | } |
| 118245 | return SQLITE_OK; |
| 118246 | } |
| @@ -118341,18 +119389,18 @@ | |
| 118341 | ** full-text index. |
| 118342 | */ |
| 118343 | static void fts3DeleteTerms( |
| 118344 | int *pRC, /* Result code */ |
| 118345 | Fts3Table *p, /* The FTS table to delete from */ |
| 118346 | sqlite3_value **apVal, /* apVal[] contains the docid to be deleted */ |
| 118347 | u32 *aSz /* Sizes of deleted document written here */ |
| 118348 | ){ |
| 118349 | int rc; |
| 118350 | sqlite3_stmt *pSelect; |
| 118351 | |
| 118352 | if( *pRC ) return; |
| 118353 | rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, apVal); |
| 118354 | if( rc==SQLITE_OK ){ |
| 118355 | if( SQLITE_ROW==sqlite3_step(pSelect) ){ |
| 118356 | int i; |
| 118357 | for(i=1; i<=p->nColumn; i++){ |
| 118358 | const char *zText = (const char *)sqlite3_column_text(pSelect, i); |
| @@ -118566,11 +119614,11 @@ | |
| 118566 | pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix); |
| 118567 | pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix); |
| 118568 | if( nPrefix<0 || nSuffix<=0 |
| 118569 | || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] |
| 118570 | ){ |
| 118571 | return SQLITE_CORRUPT; |
| 118572 | } |
| 118573 | |
| 118574 | if( nPrefix+nSuffix>pReader->nTermAlloc ){ |
| 118575 | int nNew = (nPrefix+nSuffix)*2; |
| 118576 | char *zNew = sqlite3_realloc(pReader->zTerm, nNew); |
| @@ -118592,11 +119640,11 @@ | |
| 118592 | ** of these statements is untrue, then the data structure is corrupt. |
| 118593 | */ |
| 118594 | if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] |
| 118595 | || pReader->aDoclist[pReader->nDoclist-1] |
| 118596 | ){ |
| 118597 | return SQLITE_CORRUPT; |
| 118598 | } |
| 118599 | return SQLITE_OK; |
| 118600 | } |
| 118601 | |
| 118602 | /* |
| @@ -118717,11 +119765,11 @@ | |
| 118717 | while( a<pEnd ){ |
| 118718 | a += sqlite3Fts3GetVarint(a, &nByte); |
| 118719 | } |
| 118720 | if( nDoc==0 || nByte==0 ){ |
| 118721 | sqlite3_reset(pStmt); |
| 118722 | return SQLITE_CORRUPT; |
| 118723 | } |
| 118724 | |
| 118725 | pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz); |
| 118726 | assert( pCsr->nRowAvg>0 ); |
| 118727 | rc = sqlite3_reset(pStmt); |
| @@ -119488,20 +120536,20 @@ | |
| 119488 | |
| 119489 | /* |
| 119490 | ** The first value in the apVal[] array is assumed to contain an integer. |
| 119491 | ** This function tests if there exist any documents with docid values that |
| 119492 | ** are different from that integer. i.e. if deleting the document with docid |
| 119493 | ** apVal[0] would mean the FTS3 table were empty. |
| 119494 | ** |
| 119495 | ** If successful, *pisEmpty is set to true if the table is empty except for |
| 119496 | ** document apVal[0], or false otherwise, and SQLITE_OK is returned. If an |
| 119497 | ** error occurs, an SQLite error code is returned. |
| 119498 | */ |
| 119499 | static int fts3IsEmpty(Fts3Table *p, sqlite3_value **apVal, int *pisEmpty){ |
| 119500 | sqlite3_stmt *pStmt; |
| 119501 | int rc; |
| 119502 | rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, apVal); |
| 119503 | if( rc==SQLITE_OK ){ |
| 119504 | if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 119505 | *pisEmpty = sqlite3_column_int(pStmt, 0); |
| 119506 | } |
| 119507 | rc = sqlite3_reset(pStmt); |
| @@ -120221,10 +121269,44 @@ | |
| 120221 | pToken->pDeferred = pDeferred; |
| 120222 | |
| 120223 | return SQLITE_OK; |
| 120224 | } |
| 120225 | |
| 120226 | |
| 120227 | /* |
| 120228 | ** This function does the work for the xUpdate method of FTS3 virtual |
| 120229 | ** tables. |
| 120230 | */ |
| @@ -120239,50 +121321,95 @@ | |
| 120239 | int isRemove = 0; /* True for an UPDATE or DELETE */ |
| 120240 | sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */ |
| 120241 | u32 *aSzIns; /* Sizes of inserted documents */ |
| 120242 | u32 *aSzDel; /* Sizes of deleted documents */ |
| 120243 | int nChng = 0; /* Net change in number of documents */ |
| 120244 | |
| 120245 | assert( p->pSegments==0 ); |
| 120246 | |
| 120247 | /* Allocate space to hold the change in document sizes */ |
| 120248 | aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 ); |
| 120249 | if( aSzIns==0 ) return SQLITE_NOMEM; |
| 120250 | aSzDel = &aSzIns[p->nColumn+1]; |
| 120251 | memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2); |
| 120252 | |
| 120253 | /* If this is a DELETE or UPDATE operation, remove the old record. */ |
| 120254 | if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 120255 | int isEmpty = 0; |
| 120256 | rc = fts3IsEmpty(p, apVal, &isEmpty); |
| 120257 | if( rc==SQLITE_OK ){ |
| 120258 | if( isEmpty ){ |
| 120259 | /* Deleting this row means the whole table is empty. In this case |
| 120260 | ** delete the contents of all three tables and throw away any |
| 120261 | ** data in the pendingTerms hash table. |
| 120262 | */ |
| 120263 | rc = fts3DeleteAll(p); |
| 120264 | }else{ |
| 120265 | isRemove = 1; |
| 120266 | iRemove = sqlite3_value_int64(apVal[0]); |
| 120267 | rc = fts3PendingTermsDocid(p, iRemove); |
| 120268 | fts3DeleteTerms(&rc, p, apVal, aSzDel); |
| 120269 | fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, apVal); |
| 120270 | if( p->bHasDocsize ){ |
| 120271 | fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, apVal); |
| 120272 | } |
| 120273 | nChng--; |
| 120274 | } |
| 120275 | } |
| 120276 | }else if( sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL ){ |
| 120277 | sqlite3_free(aSzIns); |
| 120278 | return fts3SpecialInsert(p, apVal[p->nColumn+2]); |
| 120279 | } |
| 120280 | |
| 120281 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 120282 | if( nArg>1 && rc==SQLITE_OK ){ |
| 120283 | rc = fts3InsertData(p, apVal, pRowid); |
| 120284 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ |
| 120285 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 120286 | } |
| 120287 | if( rc==SQLITE_OK ){ |
| 120288 | rc = fts3InsertTerms(p, apVal, aSzIns); |
| @@ -120742,11 +121869,11 @@ | |
| 120742 | SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; |
| 120743 | char *pCsr; |
| 120744 | |
| 120745 | pPhrase->nToken = pExpr->pPhrase->nToken; |
| 120746 | |
| 120747 | pCsr = sqlite3Fts3FindPositions(pExpr, p->pCsr->iPrevId, p->iCol); |
| 120748 | if( pCsr ){ |
| 120749 | int iFirst = 0; |
| 120750 | pPhrase->pList = pCsr; |
| 120751 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 120752 | pPhrase->pHead = pCsr; |
| @@ -121215,11 +122342,11 @@ | |
| 121215 | for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0; |
| 121216 | |
| 121217 | if( pExpr->aDoclist ){ |
| 121218 | char *pCsr; |
| 121219 | |
| 121220 | pCsr = sqlite3Fts3FindPositions(pExpr, p->pCursor->iPrevId, -1); |
| 121221 | if( pCsr ){ |
| 121222 | fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0); |
| 121223 | } |
| 121224 | } |
| 121225 | |
| @@ -121287,11 +122414,11 @@ | |
| 121287 | pStmt = *ppStmt; |
| 121288 | assert( sqlite3_data_count(pStmt)==1 ); |
| 121289 | |
| 121290 | a = sqlite3_column_blob(pStmt, 0); |
| 121291 | a += sqlite3Fts3GetVarint(a, &nDoc); |
| 121292 | if( nDoc==0 ) return SQLITE_CORRUPT; |
| 121293 | *pnDoc = (u32)nDoc; |
| 121294 | |
| 121295 | if( paLen ) *paLen = a; |
| 121296 | return SQLITE_OK; |
| 121297 | } |
| @@ -121382,11 +122509,11 @@ | |
| 121382 | (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); |
| 121383 | for(i=0; i<pInfo->nPhrase; i++){ |
| 121384 | LcsIterator *pIter = &aIter[i]; |
| 121385 | nToken -= pIter->pExpr->pPhrase->nToken; |
| 121386 | pIter->iPosOffset = nToken; |
| 121387 | pIter->pRead = sqlite3Fts3FindPositions(pIter->pExpr, pCsr->iPrevId, -1); |
| 121388 | if( pIter->pRead ){ |
| 121389 | pIter->iPos = pIter->iPosOffset; |
| 121390 | fts3LcsIteratorAdvance(&aIter[i]); |
| 121391 | }else{ |
| 121392 | pIter->iCol = LCS_ITERATOR_FINISHED; |
| @@ -121735,10 +122862,11 @@ | |
| 121735 | int iPos; /* Position just read from pList */ |
| 121736 | int iOff; /* Offset of this term from read positions */ |
| 121737 | }; |
| 121738 | |
| 121739 | struct TermOffsetCtx { |
| 121740 | int iCol; /* Column of table to populate aTerm for */ |
| 121741 | int iTerm; |
| 121742 | sqlite3_int64 iDocid; |
| 121743 | TermOffset *aTerm; |
| 121744 | }; |
| @@ -121752,11 +122880,11 @@ | |
| 121752 | int iTerm; /* For looping through nTerm phrase terms */ |
| 121753 | char *pList; /* Pointer to position list for phrase */ |
| 121754 | int iPos = 0; /* First position in position-list */ |
| 121755 | |
| 121756 | UNUSED_PARAMETER(iPhrase); |
| 121757 | pList = sqlite3Fts3FindPositions(pExpr, p->iDocid, p->iCol); |
| 121758 | nTerm = pExpr->pPhrase->nToken; |
| 121759 | if( pList ){ |
| 121760 | fts3GetDeltaPosition(&pList, &iPos); |
| 121761 | assert( iPos>=0 ); |
| 121762 | } |
| @@ -121805,10 +122933,11 @@ | |
| 121805 | if( 0==sCtx.aTerm ){ |
| 121806 | rc = SQLITE_NOMEM; |
| 121807 | goto offsets_out; |
| 121808 | } |
| 121809 | sCtx.iDocid = pCsr->iPrevId; |
| 121810 | |
| 121811 | /* Loop through the table columns, appending offset information to |
| 121812 | ** string-buffer res for each column. |
| 121813 | */ |
| 121814 | for(iCol=0; iCol<pTab->nColumn; iCol++){ |
| @@ -121880,11 +123009,11 @@ | |
| 121880 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 121881 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 121882 | ); |
| 121883 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 121884 | }else if( rc==SQLITE_DONE ){ |
| 121885 | rc = SQLITE_CORRUPT; |
| 121886 | } |
| 121887 | } |
| 121888 | } |
| 121889 | if( rc==SQLITE_DONE ){ |
| 121890 | rc = SQLITE_OK; |
| @@ -122468,29 +123597,29 @@ | |
| 122468 | ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. |
| 122469 | */ |
| 122470 | if( pNode && iNode==1 ){ |
| 122471 | pRtree->iDepth = readInt16(pNode->zData); |
| 122472 | if( pRtree->iDepth>RTREE_MAX_DEPTH ){ |
| 122473 | rc = SQLITE_CORRUPT; |
| 122474 | } |
| 122475 | } |
| 122476 | |
| 122477 | /* If no error has occurred so far, check if the "number of entries" |
| 122478 | ** field on the node is too large. If so, set the return code to |
| 122479 | ** SQLITE_CORRUPT. |
| 122480 | */ |
| 122481 | if( pNode && rc==SQLITE_OK ){ |
| 122482 | if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ |
| 122483 | rc = SQLITE_CORRUPT; |
| 122484 | } |
| 122485 | } |
| 122486 | |
| 122487 | if( rc==SQLITE_OK ){ |
| 122488 | if( pNode!=0 ){ |
| 122489 | nodeHashInsert(pRtree, pNode); |
| 122490 | }else{ |
| 122491 | rc = SQLITE_CORRUPT; |
| 122492 | } |
| 122493 | *ppNode = pNode; |
| 122494 | }else{ |
| 122495 | sqlite3_free(pNode); |
| 122496 | *ppNode = 0; |
| @@ -123013,11 +124142,11 @@ | |
| 123013 | if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ |
| 123014 | *piIndex = ii; |
| 123015 | return SQLITE_OK; |
| 123016 | } |
| 123017 | } |
| 123018 | return SQLITE_CORRUPT; |
| 123019 | } |
| 123020 | |
| 123021 | /* |
| 123022 | ** Return the index of the cell containing a pointer to node pNode |
| 123023 | ** in its parent. If pNode is the root node, return -1. |
| @@ -123608,11 +124737,11 @@ | |
| 123608 | RtreeNode *pParent = p->pParent; |
| 123609 | RtreeCell cell; |
| 123610 | int iCell; |
| 123611 | |
| 123612 | if( nodeParentIndex(pRtree, p, &iCell) ){ |
| 123613 | return SQLITE_CORRUPT; |
| 123614 | } |
| 123615 | |
| 123616 | nodeGetCell(pRtree, pParent, iCell, &cell); |
| 123617 | if( !cellContains(pRtree, &cell, pCell) ){ |
| 123618 | cellUnion(pRtree, &cell, pCell); |
| @@ -124280,11 +125409,11 @@ | |
| 124280 | rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); |
| 124281 | } |
| 124282 | } |
| 124283 | rc = sqlite3_reset(pRtree->pReadParent); |
| 124284 | if( rc==SQLITE_OK ) rc = rc2; |
| 124285 | if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT; |
| 124286 | pChild = pChild->pParent; |
| 124287 | } |
| 124288 | return rc; |
| 124289 | } |
| 124290 | |
| @@ -124575,10 +125704,94 @@ | |
| 124575 | sqlite3_step(pRtree->pWriteRowid); |
| 124576 | rc = sqlite3_reset(pRtree->pWriteRowid); |
| 124577 | *piRowid = sqlite3_last_insert_rowid(pRtree->db); |
| 124578 | return rc; |
| 124579 | } |
| 124580 | |
| 124581 | /* |
| 124582 | ** The xUpdate method for rtree module virtual tables. |
| 124583 | */ |
| 124584 | static int rtreeUpdate( |
| @@ -124587,107 +125800,29 @@ | |
| 124587 | sqlite3_value **azData, |
| 124588 | sqlite_int64 *pRowid |
| 124589 | ){ |
| 124590 | Rtree *pRtree = (Rtree *)pVtab; |
| 124591 | int rc = SQLITE_OK; |
| 124592 | |
| 124593 | rtreeReference(pRtree); |
| 124594 | |
| 124595 | assert(nData>=1); |
| 124596 | |
| 124597 | /* If azData[0] is not an SQL NULL value, it is the rowid of a |
| 124598 | ** record to delete from the r-tree table. The following block does |
| 124599 | ** just that. |
| 124600 | */ |
| 124601 | if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ |
| 124602 | i64 iDelete; /* The rowid to delete */ |
| 124603 | RtreeNode *pLeaf; /* Leaf node containing record iDelete */ |
| 124604 | int iCell; /* Index of iDelete cell in pLeaf */ |
| 124605 | RtreeNode *pRoot; |
| 124606 | |
| 124607 | /* Obtain a reference to the root node to initialise Rtree.iDepth */ |
| 124608 | rc = nodeAcquire(pRtree, 1, 0, &pRoot); |
| 124609 | |
| 124610 | /* Obtain a reference to the leaf node that contains the entry |
| 124611 | ** about to be deleted. |
| 124612 | */ |
| 124613 | if( rc==SQLITE_OK ){ |
| 124614 | iDelete = sqlite3_value_int64(azData[0]); |
| 124615 | rc = findLeafNode(pRtree, iDelete, &pLeaf); |
| 124616 | } |
| 124617 | |
| 124618 | /* Delete the cell in question from the leaf node. */ |
| 124619 | if( rc==SQLITE_OK ){ |
| 124620 | int rc2; |
| 124621 | rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); |
| 124622 | if( rc==SQLITE_OK ){ |
| 124623 | rc = deleteCell(pRtree, pLeaf, iCell, 0); |
| 124624 | } |
| 124625 | rc2 = nodeRelease(pRtree, pLeaf); |
| 124626 | if( rc==SQLITE_OK ){ |
| 124627 | rc = rc2; |
| 124628 | } |
| 124629 | } |
| 124630 | |
| 124631 | /* Delete the corresponding entry in the <rtree>_rowid table. */ |
| 124632 | if( rc==SQLITE_OK ){ |
| 124633 | sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); |
| 124634 | sqlite3_step(pRtree->pDeleteRowid); |
| 124635 | rc = sqlite3_reset(pRtree->pDeleteRowid); |
| 124636 | } |
| 124637 | |
| 124638 | /* Check if the root node now has exactly one child. If so, remove |
| 124639 | ** it, schedule the contents of the child for reinsertion and |
| 124640 | ** reduce the tree height by one. |
| 124641 | ** |
| 124642 | ** This is equivalent to copying the contents of the child into |
| 124643 | ** the root node (the operation that Gutman's paper says to perform |
| 124644 | ** in this scenario). |
| 124645 | */ |
| 124646 | if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ |
| 124647 | int rc2; |
| 124648 | RtreeNode *pChild; |
| 124649 | i64 iChild = nodeGetRowid(pRtree, pRoot, 0); |
| 124650 | rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); |
| 124651 | if( rc==SQLITE_OK ){ |
| 124652 | rc = removeNode(pRtree, pChild, pRtree->iDepth-1); |
| 124653 | } |
| 124654 | rc2 = nodeRelease(pRtree, pChild); |
| 124655 | if( rc==SQLITE_OK ) rc = rc2; |
| 124656 | if( rc==SQLITE_OK ){ |
| 124657 | pRtree->iDepth--; |
| 124658 | writeInt16(pRoot->zData, pRtree->iDepth); |
| 124659 | pRoot->isDirty = 1; |
| 124660 | } |
| 124661 | } |
| 124662 | |
| 124663 | /* Re-insert the contents of any underfull nodes removed from the tree. */ |
| 124664 | for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ |
| 124665 | if( rc==SQLITE_OK ){ |
| 124666 | rc = reinsertNodeContent(pRtree, pLeaf); |
| 124667 | } |
| 124668 | pRtree->pDeleted = pLeaf->pNext; |
| 124669 | sqlite3_free(pLeaf); |
| 124670 | } |
| 124671 | |
| 124672 | /* Release the reference to the root node. */ |
| 124673 | if( rc==SQLITE_OK ){ |
| 124674 | rc = nodeRelease(pRtree, pRoot); |
| 124675 | }else{ |
| 124676 | nodeRelease(pRtree, pRoot); |
| 124677 | } |
| 124678 | } |
| 124679 | |
| 124680 | /* If the azData[] array contains more than one element, elements |
| 124681 | ** (azData[2]..azData[argc-1]) contain a new record to insert into |
| 124682 | ** the r-tree structure. |
| 124683 | */ |
| 124684 | if( rc==SQLITE_OK && nData>1 ){ |
| 124685 | /* Insert a new record into the r-tree */ |
| 124686 | RtreeCell cell; |
| 124687 | int ii; |
| 124688 | RtreeNode *pLeaf; |
| 124689 | |
| 124690 | /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ |
| 124691 | assert( nData==(pRtree->nDim*2 + 3) ); |
| 124692 | if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ |
| 124693 | for(ii=0; ii<(pRtree->nDim*2); ii+=2){ |
| @@ -124707,22 +125842,53 @@ | |
| 124707 | goto constraint; |
| 124708 | } |
| 124709 | } |
| 124710 | } |
| 124711 | |
| 124712 | /* Figure out the rowid of the new row. */ |
| 124713 | if( sqlite3_value_type(azData[2])==SQLITE_NULL ){ |
| 124714 | rc = newRowid(pRtree, &cell.iRowid); |
| 124715 | }else{ |
| 124716 | cell.iRowid = sqlite3_value_int64(azData[2]); |
| 124717 | sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); |
| 124718 | if( SQLITE_ROW==sqlite3_step(pRtree->pReadRowid) ){ |
| 124719 | sqlite3_reset(pRtree->pReadRowid); |
| 124720 | rc = SQLITE_CONSTRAINT; |
| 124721 | goto constraint; |
| 124722 | } |
| 124723 | rc = sqlite3_reset(pRtree->pReadRowid); |
| 124724 | } |
| 124725 | *pRowid = cell.iRowid; |
| 124726 | |
| 124727 | if( rc==SQLITE_OK ){ |
| 124728 | rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); |
| @@ -124958,10 +126124,12 @@ | |
| 124958 | int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; |
| 124959 | if( aErrMsg[iErr] ){ |
| 124960 | *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); |
| 124961 | return SQLITE_ERROR; |
| 124962 | } |
| 124963 | |
| 124964 | /* Allocate the sqlite3_vtab structure */ |
| 124965 | nDb = strlen(argv[1]); |
| 124966 | nName = strlen(argv[2]); |
| 124967 | pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); |
| 124968 |
| --- src/sqlite3.c | |
| +++ src/sqlite3.c | |
| @@ -1,8 +1,8 @@ | |
| 1 | /****************************************************************************** |
| 2 | ** This file is an amalgamation of many separate C source files from SQLite |
| 3 | ** version 3.7.7. By combining all the individual C code files into this |
| 4 | ** single large file, the entire code can be compiled as a single translation |
| 5 | ** unit. This allows many compilers to do optimizations that would not be |
| 6 | ** possible if the files were compiled separately. Performance improvements |
| 7 | ** of 5% or more are commonly seen when SQLite is compiled as a single |
| 8 | ** translation unit. |
| @@ -648,13 +648,13 @@ | |
| 648 | ** |
| 649 | ** See also: [sqlite3_libversion()], |
| 650 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 651 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 652 | */ |
| 653 | #define SQLITE_VERSION "3.7.7" |
| 654 | #define SQLITE_VERSION_NUMBER 3007007 |
| 655 | #define SQLITE_SOURCE_ID "2011-05-20 01:50:01 2018d4e108872f2436df046636401b89cfde589d" |
| 656 | |
| 657 | /* |
| 658 | ** CAPI3REF: Run-Time Library Version Numbers |
| 659 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 660 | ** |
| @@ -916,11 +916,12 @@ | |
| 916 | ** Many SQLite functions return an integer result code from the set shown |
| 917 | ** here in order to indicates success or failure. |
| 918 | ** |
| 919 | ** New error codes may be added in future versions of SQLite. |
| 920 | ** |
| 921 | ** See also: [SQLITE_IOERR_READ | extended result codes], |
| 922 | ** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. |
| 923 | */ |
| 924 | #define SQLITE_OK 0 /* Successful result */ |
| 925 | /* beginning-of-error-codes */ |
| 926 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 927 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -993,28 +994,31 @@ | |
| 994 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 995 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 996 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 997 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 998 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 999 | #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) |
| 1000 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) |
| 1001 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 1002 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 1003 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 1004 | #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) |
| 1005 | |
| 1006 | /* |
| 1007 | ** CAPI3REF: Flags For File Open Operations |
| 1008 | ** |
| 1009 | ** These bit values are intended for use in the |
| 1010 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 1011 | ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
| 1012 | */ |
| 1013 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 1014 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 1015 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 1016 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 1017 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 1018 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 1019 | #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ |
| 1020 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 1021 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 1022 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 1023 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 1024 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -1121,21 +1125,22 @@ | |
| 1125 | }; |
| 1126 | |
| 1127 | /* |
| 1128 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 1129 | ** |
| 1130 | ** Every file opened by the [sqlite3_vfs.xOpen] method populates an |
| 1131 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 1132 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 1133 | ** This object defines the methods used to perform various operations |
| 1134 | ** against the open file represented by the [sqlite3_file] object. |
| 1135 | ** |
| 1136 | ** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element |
| 1137 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 1138 | ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The |
| 1139 | ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] |
| 1140 | ** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element |
| 1141 | ** to NULL. |
| 1142 | ** |
| 1143 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 1144 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 1145 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 1146 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -1300,10 +1305,11 @@ | |
| 1305 | */ |
| 1306 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 1307 | |
| 1308 | /* |
| 1309 | ** CAPI3REF: OS Interface Object |
| 1310 | ** KEYWORDS: VFS VFSes |
| 1311 | ** |
| 1312 | ** An instance of the sqlite3_vfs object defines the interface between |
| 1313 | ** the SQLite core and the underlying operating system. The "vfs" |
| 1314 | ** in the name of the object stands for "virtual file system". |
| 1315 | ** |
| @@ -1332,10 +1338,11 @@ | |
| 1338 | ** object once the object has been registered. |
| 1339 | ** |
| 1340 | ** The zName field holds the name of the VFS module. The name must |
| 1341 | ** be unique across all VFS modules. |
| 1342 | ** |
| 1343 | ** [[sqlite3_vfs.xOpen]] |
| 1344 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 1345 | ** is either a NULL pointer or string obtained |
| 1346 | ** from xFullPathname() with an optional suffix added. |
| 1347 | ** ^If a suffix is added to the zFilename parameter, it will |
| 1348 | ** consist of a single "-" character followed by no more than |
| @@ -1409,10 +1416,11 @@ | |
| 1416 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 1417 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 1418 | ** element will be valid after xOpen returns regardless of the success |
| 1419 | ** or failure of the xOpen call. |
| 1420 | ** |
| 1421 | ** [[sqlite3_vfs.xAccess]] |
| 1422 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 1423 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 1424 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 1425 | ** to test whether a file is at least readable. The file can be a |
| 1426 | ** directory. |
| @@ -1655,13 +1663,13 @@ | |
| 1663 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1664 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1665 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1666 | ** |
| 1667 | ** The first argument to sqlite3_config() is an integer |
| 1668 | ** [configuration option] that determines |
| 1669 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1670 | ** vary depending on the [configuration option] |
| 1671 | ** in the first argument. |
| 1672 | ** |
| 1673 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1674 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1675 | ** then this routine returns a non-zero [error code]. |
| @@ -1767,10 +1775,11 @@ | |
| 1775 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1776 | }; |
| 1777 | |
| 1778 | /* |
| 1779 | ** CAPI3REF: Configuration Options |
| 1780 | ** KEYWORDS: {configuration option} |
| 1781 | ** |
| 1782 | ** These constants are the available integer configuration options that |
| 1783 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1784 | ** |
| 1785 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1779,11 +1788,11 @@ | |
| 1788 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1789 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1790 | ** is invoked. |
| 1791 | ** |
| 1792 | ** <dl> |
| 1793 | ** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt> |
| 1794 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1795 | ** [threading mode] to Single-thread. In other words, it disables |
| 1796 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1797 | ** by a single thread. ^If SQLite is compiled with |
| 1798 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1790,11 +1799,11 @@ | |
| 1799 | ** it is not possible to change the [threading mode] from its default |
| 1800 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1801 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1802 | ** configuration option.</dd> |
| 1803 | ** |
| 1804 | ** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt> |
| 1805 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1806 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1807 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1808 | ** The application is responsible for serializing access to |
| 1809 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1804,11 +1813,11 @@ | |
| 1813 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1814 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1815 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1816 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1817 | ** |
| 1818 | ** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt> |
| 1819 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1820 | ** [threading mode] to Serialized. In other words, this option enables |
| 1821 | ** all mutexes including the recursive |
| 1822 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1823 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1820,27 +1829,27 @@ | |
| 1829 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1830 | ** it is not possible to set the Serialized [threading mode] and |
| 1831 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1832 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1833 | ** |
| 1834 | ** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> |
| 1835 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1836 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1837 | ** alternative low-level memory allocation routines to be used in place of |
| 1838 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1839 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1840 | ** before the [sqlite3_config()] call returns.</dd> |
| 1841 | ** |
| 1842 | ** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt> |
| 1843 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1844 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1845 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1846 | ** This option can be used to overload the default memory allocation |
| 1847 | ** routines with a wrapper that simulations memory allocation failure or |
| 1848 | ** tracks memory usage, for example. </dd> |
| 1849 | ** |
| 1850 | ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> |
| 1851 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1852 | ** boolean, which enables or disables the collection of memory allocation |
| 1853 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1854 | ** following SQLite interfaces become non-operational: |
| 1855 | ** <ul> |
| @@ -1852,11 +1861,11 @@ | |
| 1861 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1862 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1863 | ** allocation statistics are disabled by default. |
| 1864 | ** </dd> |
| 1865 | ** |
| 1866 | ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> |
| 1867 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1868 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1869 | ** aligned memory buffer from which the scratch allocations will be |
| 1870 | ** drawn, the size of each scratch allocation (sz), |
| 1871 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1868,11 +1877,11 @@ | |
| 1877 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1878 | ** times the database page size. ^If SQLite needs needs additional |
| 1879 | ** scratch memory beyond what is provided by this configuration option, then |
| 1880 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1881 | ** |
| 1882 | ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> |
| 1883 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1884 | ** the database page cache with the default page cache implemenation. |
| 1885 | ** This configuration should not be used if an application-define page |
| 1886 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1887 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1889,11 +1898,11 @@ | |
| 1898 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1899 | ** The pointer in the first argument must |
| 1900 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1901 | ** will be undefined.</dd> |
| 1902 | ** |
| 1903 | ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> |
| 1904 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1905 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1906 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1907 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1908 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1906,11 +1915,11 @@ | |
| 1915 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1916 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1917 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1918 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1919 | ** |
| 1920 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1921 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1922 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1923 | ** alternative low-level mutex routines to be used in place |
| 1924 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1925 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1918,11 +1927,11 @@ | |
| 1927 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1928 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1929 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1930 | ** return [SQLITE_ERROR].</dd> |
| 1931 | ** |
| 1932 | ** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt> |
| 1933 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1934 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1935 | ** [sqlite3_mutex_methods] |
| 1936 | ** structure is filled with the currently defined mutex routines.)^ |
| 1937 | ** This option can be used to overload the default mutex allocation |
| @@ -1931,32 +1940,32 @@ | |
| 1940 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1941 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1942 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1943 | ** return [SQLITE_ERROR].</dd> |
| 1944 | ** |
| 1945 | ** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt> |
| 1946 | ** <dd> ^(This option takes two arguments that determine the default |
| 1947 | ** memory allocation for the lookaside memory allocator on each |
| 1948 | ** [database connection]. The first argument is the |
| 1949 | ** size of each lookaside buffer slot and the second is the number of |
| 1950 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1951 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1952 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1953 | ** configuration on individual connections.)^ </dd> |
| 1954 | ** |
| 1955 | ** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt> |
| 1956 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1957 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1958 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1959 | ** object and uses it for page cache memory allocations.</dd> |
| 1960 | ** |
| 1961 | ** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt> |
| 1962 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1963 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1964 | ** page cache implementation into that object.)^ </dd> |
| 1965 | ** |
| 1966 | ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> |
| 1967 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1968 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1969 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1970 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1971 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1970,10 +1979,22 @@ | |
| 1979 | ** The SQLite logging interface is not reentrant; the logger function |
| 1980 | ** supplied by the application must not invoke any SQLite interface. |
| 1981 | ** In a multi-threaded application, the application-defined logger |
| 1982 | ** function must be threadsafe. </dd> |
| 1983 | ** |
| 1984 | ** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI |
| 1985 | ** <dd> This option takes a single argument of type int. If non-zero, then |
| 1986 | ** URI handling is globally enabled. If the parameter is zero, then URI handling |
| 1987 | ** is globally disabled. If URI handling is globally enabled, all filenames |
| 1988 | ** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or |
| 1989 | ** specified as part of [ATTACH] commands are interpreted as URIs, regardless |
| 1990 | ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database |
| 1991 | ** connection is opened. If it is globally disabled, filenames are |
| 1992 | ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the |
| 1993 | ** database connection is opened. By default, URI handling is globally |
| 1994 | ** disabled. The default value may be changed by compiling with the |
| 1995 | ** [SQLITE_USE_URI] symbol defined. |
| 1996 | ** </dl> |
| 1997 | */ |
| 1998 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1999 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 2000 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1988,10 +2009,11 @@ | |
| 2009 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 2010 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 2011 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 2012 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 2013 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 2014 | #define SQLITE_CONFIG_URI 17 /* int */ |
| 2015 | |
| 2016 | /* |
| 2017 | ** CAPI3REF: Database Connection Configuration Options |
| 2018 | ** |
| 2019 | ** These constants are the available integer configuration options that |
| @@ -2073,17 +2095,21 @@ | |
| 2095 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 2096 | ** is another alias for the rowid. |
| 2097 | ** |
| 2098 | ** ^This routine returns the [rowid] of the most recent |
| 2099 | ** successful [INSERT] into the database from the [database connection] |
| 2100 | ** in the first argument. ^As of SQLite version 3.7.7, this routines |
| 2101 | ** records the last insert rowid of both ordinary tables and [virtual tables]. |
| 2102 | ** ^If no successful [INSERT]s |
| 2103 | ** have ever occurred on that database connection, zero is returned. |
| 2104 | ** |
| 2105 | ** ^(If an [INSERT] occurs within a trigger or within a [virtual table] |
| 2106 | ** method, then this routine will return the [rowid] of the inserted |
| 2107 | ** row as long as the trigger or virtual table method is running. |
| 2108 | ** But once the trigger or virtual table method ends, the value returned |
| 2109 | ** by this routine reverts to what it was before the trigger or virtual |
| 2110 | ** table method began.)^ |
| 2111 | ** |
| 2112 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 2113 | ** successful [INSERT] and does not change the value returned by this |
| 2114 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 2115 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2742,10 +2768,13 @@ | |
| 2768 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2769 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2770 | ** to signal SQLite whether or not the action is permitted. See the |
| 2771 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2772 | ** information. |
| 2773 | ** |
| 2774 | ** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] |
| 2775 | ** from the [sqlite3_vtab_on_conflict()] interface. |
| 2776 | */ |
| 2777 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2778 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2779 | |
| 2780 | /* |
| @@ -2864,11 +2893,11 @@ | |
| 2893 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2894 | |
| 2895 | /* |
| 2896 | ** CAPI3REF: Opening A New Database Connection |
| 2897 | ** |
| 2898 | ** ^These routines open an SQLite database file as specified by the |
| 2899 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2900 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2901 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2902 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2903 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2891,11 +2920,11 @@ | |
| 2920 | ** except that it accepts two additional parameters for additional control |
| 2921 | ** over the new database connection. ^(The flags parameter to |
| 2922 | ** sqlite3_open_v2() can take one of |
| 2923 | ** the following three values, optionally combined with the |
| 2924 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2925 | ** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ |
| 2926 | ** |
| 2927 | ** <dl> |
| 2928 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2929 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2930 | ** already exist, an error is returned.</dd>)^ |
| @@ -2910,13 +2939,12 @@ | |
| 2939 | ** it does not already exist. This is the behavior that is always used for |
| 2940 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2941 | ** </dl> |
| 2942 | ** |
| 2943 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2944 | ** combinations shown above optionally combined with other |
| 2945 | ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] |
| 2946 | ** then the behavior is undefined. |
| 2947 | ** |
| 2948 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2949 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2950 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2926,10 +2954,15 @@ | |
| 2954 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2955 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2956 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2957 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2958 | ** participate in [shared cache mode] even if it is enabled. |
| 2959 | ** |
| 2960 | ** ^The fourth parameter to sqlite3_open_v2() is the name of the |
| 2961 | ** [sqlite3_vfs] object that defines the operating system interface that |
| 2962 | ** the new database connection should use. ^If the fourth parameter is |
| 2963 | ** a NULL pointer then the default [sqlite3_vfs] object is used. |
| 2964 | ** |
| 2965 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2966 | ** is created for the connection. ^This in-memory database will vanish when |
| 2967 | ** the database connection is closed. Future versions of SQLite might |
| 2968 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2939,14 +2972,115 @@ | |
| 2972 | ** |
| 2973 | ** ^If the filename is an empty string, then a private, temporary |
| 2974 | ** on-disk database will be created. ^This private database will be |
| 2975 | ** automatically deleted as soon as the database connection is closed. |
| 2976 | ** |
| 2977 | ** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3> |
| 2978 | ** |
| 2979 | ** ^If [URI filename] interpretation is enabled, and the filename argument |
| 2980 | ** begins with "file:", then the filename is interpreted as a URI. ^URI |
| 2981 | ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is |
| 2982 | ** is set in the fourth argument to sqlite3_open_v2(), or if it has |
| 2983 | ** been enabled globally using the [SQLITE_CONFIG_URI] option with the |
| 2984 | ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. |
| 2985 | ** As of SQLite version 3.7.7, URI filename interpretation is turned off |
| 2986 | ** by default, but future releases of SQLite might enable URI filename |
| 2987 | ** intepretation by default. See "[URI filenames]" for additional |
| 2988 | ** information. |
| 2989 | ** |
| 2990 | ** URI filenames are parsed according to RFC 3986. ^If the URI contains an |
| 2991 | ** authority, then it must be either an empty string or the string |
| 2992 | ** "localhost". ^If the authority is not an empty string or "localhost", an |
| 2993 | ** error is returned to the caller. ^The fragment component of a URI, if |
| 2994 | ** present, is ignored. |
| 2995 | ** |
| 2996 | ** ^SQLite uses the path component of the URI as the name of the disk file |
| 2997 | ** which contains the database. ^If the path begins with a '/' character, |
| 2998 | ** then it is interpreted as an absolute path. ^If the path does not begin |
| 2999 | ** with a '/' (meaning that the authority section is omitted from the URI) |
| 3000 | ** then the path is interpreted as a relative path. |
| 3001 | ** ^On windows, the first component of an absolute path |
| 3002 | ** is a drive specification (e.g. "C:"). |
| 3003 | ** |
| 3004 | ** [[core URI query parameters]] |
| 3005 | ** The query component of a URI may contain parameters that are interpreted |
| 3006 | ** either by SQLite itself, or by a [VFS | custom VFS implementation]. |
| 3007 | ** SQLite interprets the following three query parameters: |
| 3008 | ** |
| 3009 | ** <ul> |
| 3010 | ** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of |
| 3011 | ** a VFS object that provides the operating system interface that should |
| 3012 | ** be used to access the database file on disk. ^If this option is set to |
| 3013 | ** an empty string the default VFS object is used. ^Specifying an unknown |
| 3014 | ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is |
| 3015 | ** present, then the VFS specified by the option takes precedence over |
| 3016 | ** the value passed as the fourth parameter to sqlite3_open_v2(). |
| 3017 | ** |
| 3018 | ** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or |
| 3019 | ** "rwc". Attempting to set it to any other value is an error)^. |
| 3020 | ** ^If "ro" is specified, then the database is opened for read-only |
| 3021 | ** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the |
| 3022 | ** third argument to sqlite3_prepare_v2(). ^If the mode option is set to |
| 3023 | ** "rw", then the database is opened for read-write (but not create) |
| 3024 | ** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had |
| 3025 | ** been set. ^Value "rwc" is equivalent to setting both |
| 3026 | ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is |
| 3027 | ** used, it is an error to specify a value for the mode parameter that is |
| 3028 | ** less restrictive than that specified by the flags passed as the third |
| 3029 | ** parameter. |
| 3030 | ** |
| 3031 | ** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or |
| 3032 | ** "private". ^Setting it to "shared" is equivalent to setting the |
| 3033 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to |
| 3034 | ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is |
| 3035 | ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. |
| 3036 | ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in |
| 3037 | ** a URI filename, its value overrides any behaviour requested by setting |
| 3038 | ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. |
| 3039 | ** </ul> |
| 3040 | ** |
| 3041 | ** ^Specifying an unknown parameter in the query component of a URI is not an |
| 3042 | ** error. Future versions of SQLite might understand additional query |
| 3043 | ** parameters. See "[query parameters with special meaning to SQLite]" for |
| 3044 | ** additional information. |
| 3045 | ** |
| 3046 | ** [[URI filename examples]] <h3>URI filename examples</h3> |
| 3047 | ** |
| 3048 | ** <table border="1" align=center cellpadding=5> |
| 3049 | ** <tr><th> URI filenames <th> Results |
| 3050 | ** <tr><td> file:data.db <td> |
| 3051 | ** Open the file "data.db" in the current directory. |
| 3052 | ** <tr><td> file:/home/fred/data.db<br> |
| 3053 | ** file:///home/fred/data.db <br> |
| 3054 | ** file://localhost/home/fred/data.db <br> <td> |
| 3055 | ** Open the database file "/home/fred/data.db". |
| 3056 | ** <tr><td> file://darkstar/home/fred/data.db <td> |
| 3057 | ** An error. "darkstar" is not a recognized authority. |
| 3058 | ** <tr><td style="white-space:nowrap"> |
| 3059 | ** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db |
| 3060 | ** <td> Windows only: Open the file "data.db" on fred's desktop on drive |
| 3061 | ** C:. Note that the %20 escaping in this example is not strictly |
| 3062 | ** necessary - space characters can be used literally |
| 3063 | ** in URI filenames. |
| 3064 | ** <tr><td> file:data.db?mode=ro&cache=private <td> |
| 3065 | ** Open file "data.db" in the current directory for read-only access. |
| 3066 | ** Regardless of whether or not shared-cache mode is enabled by |
| 3067 | ** default, use a private cache. |
| 3068 | ** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td> |
| 3069 | ** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". |
| 3070 | ** <tr><td> file:data.db?mode=readonly <td> |
| 3071 | ** An error. "readonly" is not a valid option for the "mode" parameter. |
| 3072 | ** </table> |
| 3073 | ** |
| 3074 | ** ^URI hexadecimal escape sequences (%HH) are supported within the path and |
| 3075 | ** query components of a URI. A hexadecimal escape sequence consists of a |
| 3076 | ** percent sign - "%" - followed by exactly two hexadecimal digits |
| 3077 | ** specifying an octet value. ^Before the path or query components of a |
| 3078 | ** URI filename are interpreted, they are encoded using UTF-8 and all |
| 3079 | ** hexadecimal escape sequences replaced by a single byte containing the |
| 3080 | ** corresponding octet. If this process generates an invalid UTF-8 encoding, |
| 3081 | ** the results are undefined. |
| 3082 | ** |
| 3083 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 3084 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 3085 | ** codepage is currently defined. Filenames containing international |
| 3086 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2964,10 +3098,30 @@ | |
| 3098 | const char *filename, /* Database filename (UTF-8) */ |
| 3099 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 3100 | int flags, /* Flags */ |
| 3101 | const char *zVfs /* Name of VFS module to use */ |
| 3102 | ); |
| 3103 | |
| 3104 | /* |
| 3105 | ** CAPI3REF: Obtain Values For URI Parameters |
| 3106 | ** |
| 3107 | ** This is a utility routine, useful to VFS implementations, that checks |
| 3108 | ** to see if a database file was a URI that contained a specific query |
| 3109 | ** parameter, and if so obtains the value of the query parameter. |
| 3110 | ** |
| 3111 | ** The zFilename argument is the filename pointer passed into the xOpen() |
| 3112 | ** method of a VFS implementation. The zParam argument is the name of the |
| 3113 | ** query parameter we seek. This routine returns the value of the zParam |
| 3114 | ** parameter if it exists. If the parameter does not exist, this routine |
| 3115 | ** returns a NULL pointer. |
| 3116 | ** |
| 3117 | ** If the zFilename argument to this function is not a pointer that SQLite |
| 3118 | ** passed into the xOpen VFS method, then the behavior of this routine |
| 3119 | ** is undefined and probably undesirable. |
| 3120 | */ |
| 3121 | SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); |
| 3122 | |
| 3123 | |
| 3124 | /* |
| 3125 | ** CAPI3REF: Error Codes And Messages |
| 3126 | ** |
| 3127 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -3080,47 +3234,49 @@ | |
| 3234 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 3235 | ** The synopsis of the meanings of the various limits is shown below. |
| 3236 | ** Additional information is available at [limits | Limits in SQLite]. |
| 3237 | ** |
| 3238 | ** <dl> |
| 3239 | ** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> |
| 3240 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 3241 | ** |
| 3242 | ** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> |
| 3243 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 3244 | ** |
| 3245 | ** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt> |
| 3246 | ** <dd>The maximum number of columns in a table definition or in the |
| 3247 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 3248 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 3249 | ** |
| 3250 | ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 3251 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 3252 | ** |
| 3253 | ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> |
| 3254 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 3255 | ** |
| 3256 | ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> |
| 3257 | ** <dd>The maximum number of instructions in a virtual machine program |
| 3258 | ** used to implement an SQL statement. This limit is not currently |
| 3259 | ** enforced, though that might be added in some future release of |
| 3260 | ** SQLite.</dd>)^ |
| 3261 | ** |
| 3262 | ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> |
| 3263 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 3264 | ** |
| 3265 | ** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt> |
| 3266 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 3267 | ** |
| 3268 | ** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] |
| 3269 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 3270 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 3271 | ** [GLOB] operators.</dd>)^ |
| 3272 | ** |
| 3273 | ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] |
| 3274 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 3275 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 3276 | ** |
| 3277 | ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 3278 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 3279 | ** </dl> |
| 3280 | */ |
| 3281 | #define SQLITE_LIMIT_LENGTH 0 |
| 3282 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -5151,10 +5307,15 @@ | |
| 5307 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 5308 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 5309 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 5310 | void **ppArg); |
| 5311 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 5312 | /* The methods above are in version 1 of the sqlite_module object. Those |
| 5313 | ** below are for version 2 and greater. */ |
| 5314 | int (*xSavepoint)(sqlite3_vtab *pVTab, int); |
| 5315 | int (*xRelease)(sqlite3_vtab *pVTab, int); |
| 5316 | int (*xRollbackTo)(sqlite3_vtab *pVTab, int); |
| 5317 | }; |
| 5318 | |
| 5319 | /* |
| 5320 | ** CAPI3REF: Virtual Table Indexing Information |
| 5321 | ** KEYWORDS: sqlite3_index_info |
| @@ -5965,11 +6126,11 @@ | |
| 6126 | ** |
| 6127 | ** ^This interface is used to retrieve runtime status information |
| 6128 | ** about the performance of SQLite, and optionally to reset various |
| 6129 | ** highwater marks. ^The first argument is an integer code for |
| 6130 | ** the specific parameter to measure. ^(Recognized integer codes |
| 6131 | ** are of the form [status parameters | SQLITE_STATUS_...].)^ |
| 6132 | ** ^The current value of the parameter is returned into *pCurrent. |
| 6133 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 6134 | ** resetFlag is true, then the highest record value is reset after |
| 6135 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 6136 | ** value. For those parameters |
| @@ -5992,82 +6153,84 @@ | |
| 6153 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 6154 | |
| 6155 | |
| 6156 | /* |
| 6157 | ** CAPI3REF: Status Parameters |
| 6158 | ** KEYWORDS: {status parameters} |
| 6159 | ** |
| 6160 | ** These integer constants designate various run-time status parameters |
| 6161 | ** that can be returned by [sqlite3_status()]. |
| 6162 | ** |
| 6163 | ** <dl> |
| 6164 | ** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> |
| 6165 | ** <dd>This parameter is the current amount of memory checked out |
| 6166 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 6167 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 6168 | ** and internal memory usage by the SQLite library. Scratch memory |
| 6169 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 6170 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 6171 | ** this parameter. The amount returned is the sum of the allocation |
| 6172 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 6173 | ** |
| 6174 | ** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> |
| 6175 | ** <dd>This parameter records the largest memory allocation request |
| 6176 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 6177 | ** internal equivalents). Only the value returned in the |
| 6178 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6179 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6180 | ** |
| 6181 | ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> |
| 6182 | ** <dd>This parameter records the number of separate memory allocations |
| 6183 | ** currently checked out.</dd>)^ |
| 6184 | ** |
| 6185 | ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> |
| 6186 | ** <dd>This parameter returns the number of pages used out of the |
| 6187 | ** [pagecache memory allocator] that was configured using |
| 6188 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 6189 | ** value returned is in pages, not in bytes.</dd>)^ |
| 6190 | ** |
| 6191 | ** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] |
| 6192 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 6193 | ** <dd>This parameter returns the number of bytes of page cache |
| 6194 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 6195 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 6196 | ** returned value includes allocations that overflowed because they |
| 6197 | ** where too large (they were larger than the "sz" parameter to |
| 6198 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 6199 | ** no space was left in the page cache.</dd>)^ |
| 6200 | ** |
| 6201 | ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> |
| 6202 | ** <dd>This parameter records the largest memory allocation request |
| 6203 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 6204 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6205 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6206 | ** |
| 6207 | ** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> |
| 6208 | ** <dd>This parameter returns the number of allocations used out of the |
| 6209 | ** [scratch memory allocator] configured using |
| 6210 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 6211 | ** in bytes. Since a single thread may only have one scratch allocation |
| 6212 | ** outstanding at time, this parameter also reports the number of threads |
| 6213 | ** using scratch memory at the same time.</dd>)^ |
| 6214 | ** |
| 6215 | ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> |
| 6216 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 6217 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 6218 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 6219 | ** returned include overflows because the requested allocation was too |
| 6220 | ** larger (that is, because the requested allocation was larger than the |
| 6221 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 6222 | ** slots were available. |
| 6223 | ** </dd>)^ |
| 6224 | ** |
| 6225 | ** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> |
| 6226 | ** <dd>This parameter records the largest memory allocation request |
| 6227 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 6228 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 6229 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 6230 | ** |
| 6231 | ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> |
| 6232 | ** <dd>This parameter records the deepest parser stack. It is only |
| 6233 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 6234 | ** </dl> |
| 6235 | ** |
| 6236 | ** New status parameters may be added from time to time. |
| @@ -6088,13 +6251,13 @@ | |
| 6251 | ** |
| 6252 | ** ^This interface is used to retrieve runtime status information |
| 6253 | ** about a single [database connection]. ^The first argument is the |
| 6254 | ** database connection object to be interrogated. ^The second argument |
| 6255 | ** is an integer constant, taken from the set of |
| 6256 | ** [SQLITE_DBSTATUS options], that |
| 6257 | ** determines the parameter to interrogate. The set of |
| 6258 | ** [SQLITE_DBSTATUS options] is likely |
| 6259 | ** to grow in future releases of SQLite. |
| 6260 | ** |
| 6261 | ** ^The current value of the requested parameter is written into *pCur |
| 6262 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 6263 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -6107,10 +6270,11 @@ | |
| 6270 | */ |
| 6271 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 6272 | |
| 6273 | /* |
| 6274 | ** CAPI3REF: Status Parameters for database connections |
| 6275 | ** KEYWORDS: {SQLITE_DBSTATUS options} |
| 6276 | ** |
| 6277 | ** These constants are the available integer "verbs" that can be passed as |
| 6278 | ** the second argument to the [sqlite3_db_status()] interface. |
| 6279 | ** |
| 6280 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -6118,48 +6282,50 @@ | |
| 6282 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 6283 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 6284 | ** if a discontinued or unsupported verb is invoked. |
| 6285 | ** |
| 6286 | ** <dl> |
| 6287 | ** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> |
| 6288 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 6289 | ** checked out.</dd>)^ |
| 6290 | ** |
| 6291 | ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> |
| 6292 | ** <dd>This parameter returns the number malloc attempts that were |
| 6293 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 6294 | ** the current value is always zero.)^ |
| 6295 | ** |
| 6296 | ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] |
| 6297 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 6298 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6299 | ** been satisfied using lookaside memory but failed due to the amount of |
| 6300 | ** memory requested being larger than the lookaside slot size. |
| 6301 | ** Only the high-water value is meaningful; |
| 6302 | ** the current value is always zero.)^ |
| 6303 | ** |
| 6304 | ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] |
| 6305 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 6306 | ** <dd>This parameter returns the number malloc attempts that might have |
| 6307 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 6308 | ** memory already being in use. |
| 6309 | ** Only the high-water value is meaningful; |
| 6310 | ** the current value is always zero.)^ |
| 6311 | ** |
| 6312 | ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> |
| 6313 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6314 | ** memory used by all pager caches associated with the database connection.)^ |
| 6315 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 6316 | ** |
| 6317 | ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> |
| 6318 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6319 | ** memory used to store the schema for all databases associated |
| 6320 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 6321 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 6322 | ** schema memory is shared with other database connections due to |
| 6323 | ** [shared cache mode] being enabled. |
| 6324 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 6325 | ** |
| 6326 | ** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> |
| 6327 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 6328 | ** and lookaside memory used by all prepared statements associated with |
| 6329 | ** the database connection.)^ |
| 6330 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 6331 | ** </dd> |
| @@ -6177,11 +6343,11 @@ | |
| 6343 | |
| 6344 | /* |
| 6345 | ** CAPI3REF: Prepared Statement Status |
| 6346 | ** |
| 6347 | ** ^(Each prepared statement maintains various |
| 6348 | ** [SQLITE_STMTSTATUS counters] that measure the number |
| 6349 | ** of times it has performed specific operations.)^ These counters can |
| 6350 | ** be used to monitor the performance characteristics of the prepared |
| 6351 | ** statements. For example, if the number of table steps greatly exceeds |
| 6352 | ** the number of table searches or result rows, that would tend to indicate |
| 6353 | ** that the prepared statement is using a full table scan rather than |
| @@ -6188,11 +6354,11 @@ | |
| 6354 | ** an index. |
| 6355 | ** |
| 6356 | ** ^(This interface is used to retrieve and reset counter values from |
| 6357 | ** a [prepared statement]. The first argument is the prepared statement |
| 6358 | ** object to be interrogated. The second argument |
| 6359 | ** is an integer code for a specific [SQLITE_STMTSTATUS counter] |
| 6360 | ** to be interrogated.)^ |
| 6361 | ** ^The current value of the requested counter is returned. |
| 6362 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 6363 | ** interface call returns. |
| 6364 | ** |
| @@ -6200,28 +6366,29 @@ | |
| 6366 | */ |
| 6367 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 6368 | |
| 6369 | /* |
| 6370 | ** CAPI3REF: Status Parameters for prepared statements |
| 6371 | ** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} |
| 6372 | ** |
| 6373 | ** These preprocessor macros define integer codes that name counter |
| 6374 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 6375 | ** The meanings of the various counters are as follows: |
| 6376 | ** |
| 6377 | ** <dl> |
| 6378 | ** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> |
| 6379 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 6380 | ** a table as part of a full table scan. Large numbers for this counter |
| 6381 | ** may indicate opportunities for performance improvement through |
| 6382 | ** careful use of indices.</dd> |
| 6383 | ** |
| 6384 | ** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt> |
| 6385 | ** <dd>^This is the number of sort operations that have occurred. |
| 6386 | ** A non-zero value in this counter may indicate an opportunity to |
| 6387 | ** improvement performance through careful use of indices.</dd> |
| 6388 | ** |
| 6389 | ** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> |
| 6390 | ** <dd>^This is the number of rows inserted into transient indices that |
| 6391 | ** were created automatically in order to help joins run faster. |
| 6392 | ** A non-zero value in this counter may indicate an opportunity to |
| 6393 | ** improvement performance by adding permanent indices that do not |
| 6394 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -6268,10 +6435,11 @@ | |
| 6435 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 6436 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 6437 | ** the application may discard the parameter after the call to |
| 6438 | ** [sqlite3_config()] returns.)^ |
| 6439 | ** |
| 6440 | ** [[the xInit() page cache method]] |
| 6441 | ** ^(The xInit() method is called once for each effective |
| 6442 | ** call to [sqlite3_initialize()])^ |
| 6443 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 6444 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 6445 | ** The intent of the xInit() method is to set up global data structures |
| @@ -6278,10 +6446,11 @@ | |
| 6446 | ** required by the custom page cache implementation. |
| 6447 | ** ^(If the xInit() method is NULL, then the |
| 6448 | ** built-in default page cache is used instead of the application defined |
| 6449 | ** page cache.)^ |
| 6450 | ** |
| 6451 | ** [[the xShutdown() page cache method]] |
| 6452 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 6453 | ** It can be used to clean up |
| 6454 | ** any outstanding resources before process shutdown, if required. |
| 6455 | ** ^The xShutdown() method may be NULL. |
| 6456 | ** |
| @@ -6292,10 +6461,11 @@ | |
| 6461 | ** in multithreaded applications. |
| 6462 | ** |
| 6463 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 6464 | ** call to xShutdown(). |
| 6465 | ** |
| 6466 | ** [[the xCreate() page cache methods]] |
| 6467 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 6468 | ** SQLite will typically create one cache instance for each open database file, |
| 6469 | ** though this is not guaranteed. ^The |
| 6470 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 6471 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -6316,20 +6486,23 @@ | |
| 6486 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 6487 | ** false will always have the "discard" flag set to true. |
| 6488 | ** ^Hence, a cache created with bPurgeable false will |
| 6489 | ** never contain any unpinned pages. |
| 6490 | ** |
| 6491 | ** [[the xCachesize() page cache method]] |
| 6492 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 6493 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 6494 | ** instance passed as the first argument. This is the value configured using |
| 6495 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 6496 | ** parameter, the implementation is not required to do anything with this |
| 6497 | ** value; it is advisory only. |
| 6498 | ** |
| 6499 | ** [[the xPagecount() page cache methods]] |
| 6500 | ** The xPagecount() method must return the number of pages currently |
| 6501 | ** stored in the cache, both pinned and unpinned. |
| 6502 | ** |
| 6503 | ** [[the xFetch() page cache methods]] |
| 6504 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 6505 | ** the page, or a NULL pointer. |
| 6506 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 6507 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 6508 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -6354,10 +6527,11 @@ | |
| 6527 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 6528 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 6529 | ** attempt to unpin one or more cache pages by spilling the content of |
| 6530 | ** pinned pages to disk and synching the operating system disk cache. |
| 6531 | ** |
| 6532 | ** [[the xUnpin() page cache method]] |
| 6533 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 6534 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 6535 | ** then the page must be evicted from the cache. |
| 6536 | ** ^If the discard parameter is |
| 6537 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -6366,10 +6540,11 @@ | |
| 6540 | ** |
| 6541 | ** The cache must not perform any reference counting. A single |
| 6542 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 6543 | ** to xFetch(). |
| 6544 | ** |
| 6545 | ** [[the xRekey() page cache methods]] |
| 6546 | ** The xRekey() method is used to change the key value associated with the |
| 6547 | ** page passed as the second argument. If the cache |
| 6548 | ** previously contains an entry associated with newKey, it must be |
| 6549 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 6550 | ** to be pinned. |
| @@ -6378,10 +6553,11 @@ | |
| 6553 | ** existing cache entries with page numbers (keys) greater than or equal |
| 6554 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 6555 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 6556 | ** they can be safely discarded. |
| 6557 | ** |
| 6558 | ** [[the xDestroy() page cache method]] |
| 6559 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 6560 | ** All resources associated with the specified cache should be freed. ^After |
| 6561 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 6562 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 6563 | ** functions. |
| @@ -6440,11 +6616,11 @@ | |
| 6616 | ** associated with the backup operation. |
| 6617 | ** </ol>)^ |
| 6618 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 6619 | ** successful call to sqlite3_backup_init(). |
| 6620 | ** |
| 6621 | ** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b> |
| 6622 | ** |
| 6623 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 6624 | ** [database connection] associated with the destination database |
| 6625 | ** and the database name, respectively. |
| 6626 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -6467,11 +6643,11 @@ | |
| 6643 | ** [sqlite3_backup] object. |
| 6644 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 6645 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 6646 | ** operation. |
| 6647 | ** |
| 6648 | ** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b> |
| 6649 | ** |
| 6650 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 6651 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 6652 | ** ^If N is negative, all remaining source pages are copied. |
| 6653 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -6524,11 +6700,11 @@ | |
| 6700 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 6701 | ** database is modified by the using the same database connection as is used |
| 6702 | ** by the backup operation, then the backup database is automatically |
| 6703 | ** updated at the same time. |
| 6704 | ** |
| 6705 | ** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b> |
| 6706 | ** |
| 6707 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 6708 | ** application wishes to abandon the backup operation, the application |
| 6709 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 6710 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6547,11 +6723,12 @@ | |
| 6723 | ** |
| 6724 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6725 | ** is not a permanent error and does not affect the return value of |
| 6726 | ** sqlite3_backup_finish(). |
| 6727 | ** |
| 6728 | ** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] |
| 6729 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 6730 | ** |
| 6731 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6732 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6733 | ** up and the total number of pages in the source database file. |
| 6734 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6932,10 +7109,97 @@ | |
| 7109 | ** each of these values. |
| 7110 | */ |
| 7111 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 7112 | #define SQLITE_CHECKPOINT_FULL 1 |
| 7113 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 7114 | |
| 7115 | /* |
| 7116 | ** CAPI3REF: Virtual Table Interface Configuration |
| 7117 | ** |
| 7118 | ** This function may be called by either the [xConnect] or [xCreate] method |
| 7119 | ** of a [virtual table] implementation to configure |
| 7120 | ** various facets of the virtual table interface. |
| 7121 | ** |
| 7122 | ** If this interface is invoked outside the context of an xConnect or |
| 7123 | ** xCreate virtual table method then the behavior is undefined. |
| 7124 | ** |
| 7125 | ** At present, there is only one option that may be configured using |
| 7126 | ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options |
| 7127 | ** may be added in the future. |
| 7128 | */ |
| 7129 | SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); |
| 7130 | |
| 7131 | /* |
| 7132 | ** CAPI3REF: Virtual Table Configuration Options |
| 7133 | ** |
| 7134 | ** These macros define the various options to the |
| 7135 | ** [sqlite3_vtab_config()] interface that [virtual table] implementations |
| 7136 | ** can use to customize and optimize their behavior. |
| 7137 | ** |
| 7138 | ** <dl> |
| 7139 | ** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT |
| 7140 | ** <dd>Calls of the form |
| 7141 | ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, |
| 7142 | ** where X is an integer. If X is zero, then the [virtual table] whose |
| 7143 | ** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not |
| 7144 | ** support constraints. In this configuration (which is the default) if |
| 7145 | ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire |
| 7146 | ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been |
| 7147 | ** specified as part of the users SQL statement, regardless of the actual |
| 7148 | ** ON CONFLICT mode specified. |
| 7149 | ** |
| 7150 | ** If X is non-zero, then the virtual table implementation guarantees |
| 7151 | ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before |
| 7152 | ** any modifications to internal or persistent data structures have been made. |
| 7153 | ** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite |
| 7154 | ** is able to roll back a statement or database transaction, and abandon |
| 7155 | ** or continue processing the current SQL statement as appropriate. |
| 7156 | ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns |
| 7157 | ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode |
| 7158 | ** had been ABORT. |
| 7159 | ** |
| 7160 | ** Virtual table implementations that are required to handle OR REPLACE |
| 7161 | ** must do so within the [xUpdate] method. If a call to the |
| 7162 | ** [sqlite3_vtab_on_conflict()] function indicates that the current ON |
| 7163 | ** CONFLICT policy is REPLACE, the virtual table implementation should |
| 7164 | ** silently replace the appropriate rows within the xUpdate callback and |
| 7165 | ** return SQLITE_OK. Or, if this is not possible, it may return |
| 7166 | ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT |
| 7167 | ** constraint handling. |
| 7168 | ** </dl> |
| 7169 | */ |
| 7170 | #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 |
| 7171 | |
| 7172 | /* |
| 7173 | ** CAPI3REF: Determine The Virtual Table Conflict Policy |
| 7174 | ** |
| 7175 | ** This function may only be called from within a call to the [xUpdate] method |
| 7176 | ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The |
| 7177 | ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], |
| 7178 | ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode |
| 7179 | ** of the SQL statement that triggered the call to the [xUpdate] method of the |
| 7180 | ** [virtual table]. |
| 7181 | */ |
| 7182 | SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); |
| 7183 | |
| 7184 | /* |
| 7185 | ** CAPI3REF: Conflict resolution modes |
| 7186 | ** |
| 7187 | ** These constants are returned by [sqlite3_vtab_on_conflict()] to |
| 7188 | ** inform a [virtual table] implementation what the [ON CONFLICT] mode |
| 7189 | ** is for the SQL statement being evaluated. |
| 7190 | ** |
| 7191 | ** Note that the [SQLITE_IGNORE] constant is also used as a potential |
| 7192 | ** return value from the [sqlite3_set_authorizer()] callback and that |
| 7193 | ** [SQLITE_ABORT] is also a [result code]. |
| 7194 | */ |
| 7195 | #define SQLITE_ROLLBACK 1 |
| 7196 | /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ |
| 7197 | #define SQLITE_FAIL 3 |
| 7198 | /* #define SQLITE_ABORT 4 // Also an error code */ |
| 7199 | #define SQLITE_REPLACE 5 |
| 7200 | |
| 7201 | |
| 7202 | |
| 7203 | /* |
| 7204 | ** Undo the hack that converts floating point types to integer for |
| 7205 | ** builds on processors without floating point support. |
| @@ -7599,10 +7863,11 @@ | |
| 7863 | typedef struct Trigger Trigger; |
| 7864 | typedef struct TriggerPrg TriggerPrg; |
| 7865 | typedef struct TriggerStep TriggerStep; |
| 7866 | typedef struct UnpackedRecord UnpackedRecord; |
| 7867 | typedef struct VTable VTable; |
| 7868 | typedef struct VtabCtx VtabCtx; |
| 7869 | typedef struct Walker Walker; |
| 7870 | typedef struct WherePlan WherePlan; |
| 7871 | typedef struct WhereInfo WhereInfo; |
| 7872 | typedef struct WhereLevel WhereLevel; |
| 7873 | |
| @@ -7655,10 +7920,11 @@ | |
| 7920 | typedef struct BtCursor BtCursor; |
| 7921 | typedef struct BtShared BtShared; |
| 7922 | |
| 7923 | |
| 7924 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 7925 | sqlite3_vfs *pVfs, /* VFS to use with this b-tree */ |
| 7926 | const char *zFilename, /* Name of database file to open */ |
| 7927 | sqlite3 *db, /* Associated database connection */ |
| 7928 | Btree **ppBtree, /* Return open Btree* here */ |
| 7929 | int flags, /* Flags */ |
| 7930 | int vfsFlags /* Flags passed through to VFS open */ |
| @@ -9134,19 +9400,20 @@ | |
| 9400 | struct sqlite3 { |
| 9401 | sqlite3_vfs *pVfs; /* OS Interface */ |
| 9402 | int nDb; /* Number of backends currently in use */ |
| 9403 | Db *aDb; /* All backends */ |
| 9404 | int flags; /* Miscellaneous flags. See below */ |
| 9405 | unsigned int openFlags; /* Flags passed to sqlite3_vfs.xOpen() */ |
| 9406 | int errCode; /* Most recent error code (SQLITE_*) */ |
| 9407 | int errMask; /* & result codes with this before returning */ |
| 9408 | u8 autoCommit; /* The auto-commit flag. */ |
| 9409 | u8 temp_store; /* 1: file 2: memory 0: default */ |
| 9410 | u8 mallocFailed; /* True if we have seen a malloc failure */ |
| 9411 | u8 dfltLockMode; /* Default locking-mode for attached dbs */ |
| 9412 | signed char nextAutovac; /* Autovac setting after VACUUM if >=0 */ |
| 9413 | u8 suppressErr; /* Do not issue error messages if true */ |
| 9414 | u8 vtabOnConflict; /* Value to return for s3_vtab_on_conflict() */ |
| 9415 | int nextPagesize; /* Pagesize after VACUUM if >0 */ |
| 9416 | int nTable; /* Number of tables in the database */ |
| 9417 | CollSeq *pDfltColl; /* The default collating sequence (BINARY) */ |
| 9418 | i64 lastRowid; /* ROWID of most recent insert (see above) */ |
| 9419 | u32 magic; /* Magic number for detect library misuse */ |
| @@ -9201,11 +9468,11 @@ | |
| 9468 | void *pProgressArg; /* Argument to the progress callback */ |
| 9469 | int nProgressOps; /* Number of opcodes for progress callback */ |
| 9470 | #endif |
| 9471 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 9472 | Hash aModule; /* populated by sqlite3_create_module() */ |
| 9473 | VtabCtx *pVtabCtx; /* Context for active vtab connect/create */ |
| 9474 | VTable **aVTrans; /* Virtual tables with open transactions */ |
| 9475 | int nVTrans; /* Allocated size of aVTrans */ |
| 9476 | VTable *pDisconnect; /* Disconnect these in next sqlite3_prepare() */ |
| 9477 | #endif |
| 9478 | FuncDefHash aFunc; /* Hash table of connection functions */ |
| @@ -9564,10 +9831,11 @@ | |
| 9831 | struct VTable { |
| 9832 | sqlite3 *db; /* Database connection associated with this table */ |
| 9833 | Module *pMod; /* Pointer to module implementation */ |
| 9834 | sqlite3_vtab *pVtab; /* Pointer to vtab instance */ |
| 9835 | int nRef; /* Number of pointers to this structure */ |
| 9836 | u8 bConstraint; /* True if constraints are supported */ |
| 9837 | VTable *pNext; /* Next in linked list (see above) */ |
| 9838 | }; |
| 9839 | |
| 9840 | /* |
| 9841 | ** Each SQL table is represented in memory by an instance of the |
| @@ -10752,10 +11020,11 @@ | |
| 11020 | */ |
| 11021 | struct Sqlite3Config { |
| 11022 | int bMemstat; /* True to enable memory status */ |
| 11023 | int bCoreMutex; /* True to enable core mutexing */ |
| 11024 | int bFullMutex; /* True to enable full mutexing */ |
| 11025 | int bOpenUri; /* True to interpret filenames as URIs */ |
| 11026 | int mxStrlen; /* Maximum string length */ |
| 11027 | int szLookaside; /* Default lookaside buffer size */ |
| 11028 | int nLookaside; /* Default lookaside buffer count */ |
| 11029 | sqlite3_mem_methods m; /* Low-level memory allocation interface */ |
| 11030 | sqlite3_mutex_methods mutex; /* Low-level mutex interface */ |
| @@ -11001,10 +11270,12 @@ | |
| 11270 | SQLITE_PRIVATE void sqlite3AddCheckConstraint(Parse*, Expr*); |
| 11271 | SQLITE_PRIVATE void sqlite3AddColumnType(Parse*,Token*); |
| 11272 | SQLITE_PRIVATE void sqlite3AddDefaultValue(Parse*,ExprSpan*); |
| 11273 | SQLITE_PRIVATE void sqlite3AddCollateType(Parse*, Token*); |
| 11274 | SQLITE_PRIVATE void sqlite3EndTable(Parse*,Token*,Token*,Select*); |
| 11275 | SQLITE_PRIVATE int sqlite3ParseUri(const char*,const char*,unsigned int*, |
| 11276 | sqlite3_vfs**,char**,char **); |
| 11277 | |
| 11278 | SQLITE_PRIVATE Bitvec *sqlite3BitvecCreate(u32); |
| 11279 | SQLITE_PRIVATE int sqlite3BitvecTest(Bitvec*, u32); |
| 11280 | SQLITE_PRIVATE int sqlite3BitvecSet(Bitvec*, u32); |
| 11281 | SQLITE_PRIVATE void sqlite3BitvecClear(Bitvec*, u32, void*); |
| @@ -11251,10 +11522,11 @@ | |
| 11522 | SQLITE_PRIVATE int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); |
| 11523 | SQLITE_PRIVATE char sqlite3ExprAffinity(Expr *pExpr); |
| 11524 | SQLITE_PRIVATE int sqlite3Atoi64(const char*, i64*, int, u8); |
| 11525 | SQLITE_PRIVATE void sqlite3Error(sqlite3*, int, const char*,...); |
| 11526 | SQLITE_PRIVATE void *sqlite3HexToBlob(sqlite3*, const char *z, int n); |
| 11527 | SQLITE_PRIVATE u8 sqlite3HexToInt(int h); |
| 11528 | SQLITE_PRIVATE int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); |
| 11529 | SQLITE_PRIVATE const char *sqlite3ErrStr(int); |
| 11530 | SQLITE_PRIVATE int sqlite3ReadSchema(Parse *pParse); |
| 11531 | SQLITE_PRIVATE CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char*,int); |
| 11532 | SQLITE_PRIVATE CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char*zName); |
| @@ -11266,10 +11538,16 @@ | |
| 11538 | SQLITE_PRIVATE void sqlite3VdbeSetChanges(sqlite3 *, int); |
| 11539 | SQLITE_PRIVATE int sqlite3AddInt64(i64*,i64); |
| 11540 | SQLITE_PRIVATE int sqlite3SubInt64(i64*,i64); |
| 11541 | SQLITE_PRIVATE int sqlite3MulInt64(i64*,i64); |
| 11542 | SQLITE_PRIVATE int sqlite3AbsInt32(int); |
| 11543 | #ifdef SQLITE_ENABLE_8_3_NAMES |
| 11544 | SQLITE_PRIVATE void sqlite3FileSuffix3(const char*, char*); |
| 11545 | #else |
| 11546 | # define sqlite3FileSuffix3(X,Y) |
| 11547 | #endif |
| 11548 | SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z); |
| 11549 | |
| 11550 | SQLITE_PRIVATE const void *sqlite3ValueText(sqlite3_value*, u8); |
| 11551 | SQLITE_PRIVATE int sqlite3ValueBytes(sqlite3_value*, u8); |
| 11552 | SQLITE_PRIVATE void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, |
| 11553 | void(*)(void*)); |
| @@ -11375,18 +11653,20 @@ | |
| 11653 | # define sqlite3VtabCommit(X) |
| 11654 | # define sqlite3VtabInSync(db) 0 |
| 11655 | # define sqlite3VtabLock(X) |
| 11656 | # define sqlite3VtabUnlock(X) |
| 11657 | # define sqlite3VtabUnlockList(X) |
| 11658 | # define sqlite3VtabSavepoint(X, Y, Z) SQLITE_OK |
| 11659 | #else |
| 11660 | SQLITE_PRIVATE void sqlite3VtabClear(sqlite3 *db, Table*); |
| 11661 | SQLITE_PRIVATE int sqlite3VtabSync(sqlite3 *db, char **); |
| 11662 | SQLITE_PRIVATE int sqlite3VtabRollback(sqlite3 *db); |
| 11663 | SQLITE_PRIVATE int sqlite3VtabCommit(sqlite3 *db); |
| 11664 | SQLITE_PRIVATE void sqlite3VtabLock(VTable *); |
| 11665 | SQLITE_PRIVATE void sqlite3VtabUnlock(VTable *); |
| 11666 | SQLITE_PRIVATE void sqlite3VtabUnlockList(sqlite3*); |
| 11667 | SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *, int, int); |
| 11668 | # define sqlite3VtabInSync(db) ((db)->nVTrans>0 && (db)->aVTrans==0) |
| 11669 | #endif |
| 11670 | SQLITE_PRIVATE void sqlite3VtabMakeWritable(Parse*,Table*); |
| 11671 | SQLITE_PRIVATE void sqlite3VtabBeginParse(Parse*, Token*, Token*, Token*); |
| 11672 | SQLITE_PRIVATE void sqlite3VtabFinishParse(Parse*, Token*); |
| @@ -11689,20 +11969,23 @@ | |
| 11969 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, /* f0..f7 ........ */ |
| 11970 | 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40 /* f8..ff ........ */ |
| 11971 | }; |
| 11972 | #endif |
| 11973 | |
| 11974 | #ifndef SQLITE_USE_URI |
| 11975 | # define SQLITE_USE_URI 0 |
| 11976 | #endif |
| 11977 | |
| 11978 | /* |
| 11979 | ** The following singleton contains the global configuration for |
| 11980 | ** the SQLite library. |
| 11981 | */ |
| 11982 | SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = { |
| 11983 | SQLITE_DEFAULT_MEMSTATUS, /* bMemstat */ |
| 11984 | 1, /* bCoreMutex */ |
| 11985 | SQLITE_THREADSAFE==1, /* bFullMutex */ |
| 11986 | SQLITE_USE_URI, /* bOpenUri */ |
| 11987 | 0x7ffffffe, /* mxStrlen */ |
| 11988 | 100, /* szLookaside */ |
| 11989 | 500, /* nLookaside */ |
| 11990 | {0,0,0,0,0,0,0,0}, /* m */ |
| 11991 | {0,0,0,0,0,0,0,0,0}, /* mutex */ |
| @@ -17948,11 +18231,11 @@ | |
| 18231 | assert( sqlite3_mutex_held(mem0.mutex) ); |
| 18232 | nFull = sqlite3GlobalConfig.m.xRoundup(n); |
| 18233 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, n); |
| 18234 | if( mem0.alarmCallback!=0 ){ |
| 18235 | int nUsed = sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED); |
| 18236 | if( nUsed >= mem0.alarmThreshold - nFull ){ |
| 18237 | mem0.nearlyFull = 1; |
| 18238 | sqlite3MallocAlarm(nFull); |
| 18239 | }else{ |
| 18240 | mem0.nearlyFull = 0; |
| 18241 | } |
| @@ -18189,11 +18472,11 @@ | |
| 18472 | |
| 18473 | /* |
| 18474 | ** Change the size of an existing memory allocation |
| 18475 | */ |
| 18476 | SQLITE_PRIVATE void *sqlite3Realloc(void *pOld, int nBytes){ |
| 18477 | int nOld, nNew, nDiff; |
| 18478 | void *pNew; |
| 18479 | if( pOld==0 ){ |
| 18480 | return sqlite3Malloc(nBytes); /* IMP: R-28354-25769 */ |
| 18481 | } |
| 18482 | if( nBytes<=0 ){ |
| @@ -18212,13 +18495,14 @@ | |
| 18495 | if( nOld==nNew ){ |
| 18496 | pNew = pOld; |
| 18497 | }else if( sqlite3GlobalConfig.bMemstat ){ |
| 18498 | sqlite3_mutex_enter(mem0.mutex); |
| 18499 | sqlite3StatusSet(SQLITE_STATUS_MALLOC_SIZE, nBytes); |
| 18500 | nDiff = nNew - nOld; |
| 18501 | if( sqlite3StatusValue(SQLITE_STATUS_MEMORY_USED) >= |
| 18502 | mem0.alarmThreshold-nDiff ){ |
| 18503 | sqlite3MallocAlarm(nDiff); |
| 18504 | } |
| 18505 | assert( sqlite3MemdebugHasType(pOld, MEMTYPE_HEAP) ); |
| 18506 | assert( sqlite3MemdebugNoType(pOld, ~MEMTYPE_HEAP) ); |
| 18507 | pNew = sqlite3GlobalConfig.m.xRealloc(pOld, nNew); |
| 18508 | if( pNew==0 && mem0.alarmCallback ){ |
| @@ -21180,27 +21464,25 @@ | |
| 21464 | p[3] = (u8)v; |
| 21465 | } |
| 21466 | |
| 21467 | |
| 21468 | |
| 21469 | /* |
| 21470 | ** Translate a single byte of Hex into an integer. |
| 21471 | ** This routine only works if h really is a valid hexadecimal |
| 21472 | ** character: 0..9a..fA..F |
| 21473 | */ |
| 21474 | SQLITE_PRIVATE u8 sqlite3HexToInt(int h){ |
| 21475 | assert( (h>='0' && h<='9') || (h>='a' && h<='f') || (h>='A' && h<='F') ); |
| 21476 | #ifdef SQLITE_ASCII |
| 21477 | h += 9*(1&(h>>6)); |
| 21478 | #endif |
| 21479 | #ifdef SQLITE_EBCDIC |
| 21480 | h += 9*(1&~(h>>4)); |
| 21481 | #endif |
| 21482 | return (u8)(h & 0xf); |
| 21483 | } |
| 21484 | |
| 21485 | #if !defined(SQLITE_OMIT_BLOB_LITERAL) || defined(SQLITE_HAS_CODEC) |
| 21486 | /* |
| 21487 | ** Convert a BLOB literal of the form "x'hhhhhh'" into its binary |
| 21488 | ** value. Return a pointer to its binary value. Space to hold the |
| @@ -21213,11 +21495,11 @@ | |
| 21495 | |
| 21496 | zBlob = (char *)sqlite3DbMallocRaw(db, n/2 + 1); |
| 21497 | n--; |
| 21498 | if( zBlob ){ |
| 21499 | for(i=0; i<n; i+=2){ |
| 21500 | zBlob[i/2] = (sqlite3HexToInt(z[i])<<4) | sqlite3HexToInt(z[i+1]); |
| 21501 | } |
| 21502 | zBlob[i/2] = 0; |
| 21503 | } |
| 21504 | return zBlob; |
| 21505 | } |
| @@ -21345,10 +21627,36 @@ | |
| 21627 | SQLITE_PRIVATE int sqlite3AbsInt32(int x){ |
| 21628 | if( x>=0 ) return x; |
| 21629 | if( x==(int)0x80000000 ) return 0x7fffffff; |
| 21630 | return -x; |
| 21631 | } |
| 21632 | |
| 21633 | #ifdef SQLITE_ENABLE_8_3_NAMES |
| 21634 | /* |
| 21635 | ** If SQLITE_ENABLE_8_3_NAME is set at compile-time and if the database |
| 21636 | ** filename in zBaseFilename is a URI with the "8_3_names=1" parameter and |
| 21637 | ** if filename in z[] has a suffix (a.k.a. "extension") that is longer than |
| 21638 | ** three characters, then shorten the suffix on z[] to be the last three |
| 21639 | ** characters of the original suffix. |
| 21640 | ** |
| 21641 | ** Examples: |
| 21642 | ** |
| 21643 | ** test.db-journal => test.nal |
| 21644 | ** test.db-wal => test.wal |
| 21645 | ** test.db-shm => test.shm |
| 21646 | */ |
| 21647 | SQLITE_PRIVATE void sqlite3FileSuffix3(const char *zBaseFilename, char *z){ |
| 21648 | const char *zOk; |
| 21649 | zOk = sqlite3_uri_parameter(zBaseFilename, "8_3_names"); |
| 21650 | if( zOk && sqlite3GetBoolean(zOk) ){ |
| 21651 | int i, sz; |
| 21652 | sz = sqlite3Strlen30(z); |
| 21653 | for(i=sz-1; i>0 && z[i]!='/' && z[i]!='.'; i--){} |
| 21654 | if( z[i]=='.' && ALWAYS(sz>i+4) ) memcpy(&z[i+1], &z[sz-3], 4); |
| 21655 | } |
| 21656 | } |
| 21657 | #endif |
| 21658 | |
| 21659 | /************** End of util.c ************************************************/ |
| 21660 | /************** Begin file hash.c ********************************************/ |
| 21661 | /* |
| 21662 | ** 2001 September 22 |
| @@ -24398,10 +24706,22 @@ | |
| 24706 | #if SQLITE_THREADSAFE |
| 24707 | #define threadid pthread_self() |
| 24708 | #else |
| 24709 | #define threadid 0 |
| 24710 | #endif |
| 24711 | |
| 24712 | /* |
| 24713 | ** Different Unix systems declare open() in different ways. Same use |
| 24714 | ** open(const char*,int,mode_t). Others use open(const char*,int,...). |
| 24715 | ** The difference is important when using a pointer to the function. |
| 24716 | ** |
| 24717 | ** The safest way to deal with the problem is to always use this wrapper |
| 24718 | ** which always has the same well-defined interface. |
| 24719 | */ |
| 24720 | static int posixOpen(const char *zFile, int flags, int mode){ |
| 24721 | return open(zFile, flags, mode); |
| 24722 | } |
| 24723 | |
| 24724 | /* |
| 24725 | ** Many system calls are accessed through pointer-to-functions so that |
| 24726 | ** they may be overridden at runtime to facilitate fault injection during |
| 24727 | ** testing and sandboxing. The following array holds the names and pointers |
| @@ -24410,11 +24730,11 @@ | |
| 24730 | static struct unix_syscall { |
| 24731 | const char *zName; /* Name of the sytem call */ |
| 24732 | sqlite3_syscall_ptr pCurrent; /* Current value of the system call */ |
| 24733 | sqlite3_syscall_ptr pDefault; /* Default value */ |
| 24734 | } aSyscall[] = { |
| 24735 | { "open", (sqlite3_syscall_ptr)posixOpen, 0 }, |
| 24736 | #define osOpen ((int(*)(const char*,int,int))aSyscall[0].pCurrent) |
| 24737 | |
| 24738 | { "close", (sqlite3_syscall_ptr)close, 0 }, |
| 24739 | #define osClose ((int(*)(int))aSyscall[1].pCurrent) |
| 24740 | |
| @@ -24448,11 +24768,11 @@ | |
| 24768 | #define osFcntl ((int(*)(int,int,...))aSyscall[7].pCurrent) |
| 24769 | |
| 24770 | { "read", (sqlite3_syscall_ptr)read, 0 }, |
| 24771 | #define osRead ((ssize_t(*)(int,void*,size_t))aSyscall[8].pCurrent) |
| 24772 | |
| 24773 | #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE |
| 24774 | { "pread", (sqlite3_syscall_ptr)pread, 0 }, |
| 24775 | #else |
| 24776 | { "pread", (sqlite3_syscall_ptr)0, 0 }, |
| 24777 | #endif |
| 24778 | #define osPread ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[9].pCurrent) |
| @@ -24465,11 +24785,11 @@ | |
| 24785 | #define osPread64 ((ssize_t(*)(int,void*,size_t,off_t))aSyscall[10].pCurrent) |
| 24786 | |
| 24787 | { "write", (sqlite3_syscall_ptr)write, 0 }, |
| 24788 | #define osWrite ((ssize_t(*)(int,const void*,size_t))aSyscall[11].pCurrent) |
| 24789 | |
| 24790 | #if defined(USE_PREAD) || SQLITE_ENABLE_LOCKING_STYLE |
| 24791 | { "pwrite", (sqlite3_syscall_ptr)pwrite, 0 }, |
| 24792 | #else |
| 24793 | { "pwrite", (sqlite3_syscall_ptr)0, 0 }, |
| 24794 | #endif |
| 24795 | #define osPwrite ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| @@ -24483,12 +24803,14 @@ | |
| 24803 | #define osPwrite64 ((ssize_t(*)(int,const void*,size_t,off_t))\ |
| 24804 | aSyscall[13].pCurrent) |
| 24805 | |
| 24806 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 24807 | { "fchmod", (sqlite3_syscall_ptr)fchmod, 0 }, |
| 24808 | #else |
| 24809 | { "fchmod", (sqlite3_syscall_ptr)0, 0 }, |
| 24810 | #endif |
| 24811 | #define osFchmod ((int(*)(int,mode_t))aSyscall[14].pCurrent) |
| 24812 | |
| 24813 | #if defined(HAVE_POSIX_FALLOCATE) && HAVE_POSIX_FALLOCATE |
| 24814 | { "fallocate", (sqlite3_syscall_ptr)posix_fallocate, 0 }, |
| 24815 | #else |
| 24816 | { "fallocate", (sqlite3_syscall_ptr)0, 0 }, |
| @@ -25049,11 +25371,11 @@ | |
| 25371 | unixShmNode *pShmNode; /* Shared memory associated with this inode */ |
| 25372 | int nLock; /* Number of outstanding file locks */ |
| 25373 | UnixUnusedFd *pUnused; /* Unused file descriptors to close */ |
| 25374 | unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ |
| 25375 | unixInodeInfo *pPrev; /* .... doubly linked */ |
| 25376 | #if SQLITE_ENABLE_LOCKING_STYLE |
| 25377 | unsigned long long sharedByte; /* for AFP simulated shared lock */ |
| 25378 | #endif |
| 25379 | #if OS_VXWORKS |
| 25380 | sem_t *pSem; /* Named POSIX semaphore */ |
| 25381 | char aSemName[MAX_PATHNAME+2]; /* Name of that semaphore */ |
| @@ -27206,11 +27528,11 @@ | |
| 27528 | } |
| 27529 | SimulateIOError(( wrote=(-1), amt=1 )); |
| 27530 | SimulateDiskfullError(( wrote=0, amt=1 )); |
| 27531 | |
| 27532 | if( amt>0 ){ |
| 27533 | if( wrote<0 && pFile->lastErrno!=ENOSPC ){ |
| 27534 | /* lastErrno set by seekAndWrite */ |
| 27535 | return SQLITE_IOERR_WRITE; |
| 27536 | }else{ |
| 27537 | pFile->lastErrno = 0; /* not a system error */ |
| 27538 | return SQLITE_FULL; |
| @@ -27873,10 +28195,11 @@ | |
| 28195 | sqlite3_snprintf(nShmFilename, zShmFilename, |
| 28196 | SQLITE_SHM_DIRECTORY "/sqlite-shm-%x-%x", |
| 28197 | (u32)sStat.st_ino, (u32)sStat.st_dev); |
| 28198 | #else |
| 28199 | sqlite3_snprintf(nShmFilename, zShmFilename, "%s-shm", pDbFd->zPath); |
| 28200 | sqlite3FileSuffix3(pDbFd->zPath, zShmFilename); |
| 28201 | #endif |
| 28202 | pShmNode->h = -1; |
| 28203 | pDbFd->pInode->pShmNode = pShmNode; |
| 28204 | pShmNode->pInode = pDbFd->pInode; |
| 28205 | pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); |
| @@ -28031,11 +28354,11 @@ | |
| 28354 | if( pShmNode->h>=0 ){ |
| 28355 | pMem = mmap(0, szRegion, PROT_READ|PROT_WRITE, |
| 28356 | MAP_SHARED, pShmNode->h, pShmNode->nRegion*szRegion |
| 28357 | ); |
| 28358 | if( pMem==MAP_FAILED ){ |
| 28359 | rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); |
| 28360 | goto shmpage_out; |
| 28361 | } |
| 28362 | }else{ |
| 28363 | pMem = sqlite3_malloc(szRegion); |
| 28364 | if( pMem==0 ){ |
| @@ -28906,17 +29229,23 @@ | |
| 29229 | ** Finally, if the file being opened is a WAL or regular journal file, then |
| 29230 | ** this function queries the file-system for the permissions on the |
| 29231 | ** corresponding database file and sets *pMode to this value. Whenever |
| 29232 | ** possible, WAL and journal files are created using the same permissions |
| 29233 | ** as the associated database file. |
| 29234 | ** |
| 29235 | ** If the SQLITE_ENABLE_8_3_NAMES option is enabled, then the |
| 29236 | ** original filename is unavailable. But 8_3_NAMES is only used for |
| 29237 | ** FAT filesystems and permissions do not matter there, so just use |
| 29238 | ** the default permissions. |
| 29239 | */ |
| 29240 | static int findCreateFileMode( |
| 29241 | const char *zPath, /* Path of file (possibly) being created */ |
| 29242 | int flags, /* Flags passed as 4th argument to xOpen() */ |
| 29243 | mode_t *pMode /* OUT: Permissions to open file with */ |
| 29244 | ){ |
| 29245 | int rc = SQLITE_OK; /* Return Code */ |
| 29246 | *pMode = SQLITE_DEFAULT_FILE_PERMISSIONS; |
| 29247 | if( flags & (SQLITE_OPEN_WAL|SQLITE_OPEN_MAIN_JOURNAL) ){ |
| 29248 | char zDb[MAX_PATHNAME+1]; /* Database file path */ |
| 29249 | int nDb; /* Number of valid bytes in zDb */ |
| 29250 | struct stat sStat; /* Output of stat() on database file */ |
| 29251 | |
| @@ -28924,19 +29253,19 @@ | |
| 29253 | ** the path to the associated database file from zPath. This block handles |
| 29254 | ** the following naming conventions: |
| 29255 | ** |
| 29256 | ** "<path to db>-journal" |
| 29257 | ** "<path to db>-wal" |
| 29258 | ** "<path to db>-journalNN" |
| 29259 | ** "<path to db>-walNN" |
| 29260 | ** |
| 29261 | ** where NN is a 4 digit decimal number. The NN naming schemes are |
| 29262 | ** used by the test_multiplex.c module. |
| 29263 | */ |
| 29264 | nDb = sqlite3Strlen30(zPath) - 1; |
| 29265 | while( nDb>0 && zPath[nDb]!='-' ) nDb--; |
| 29266 | if( nDb==0 ) return SQLITE_OK; |
| 29267 | memcpy(zDb, zPath, nDb); |
| 29268 | zDb[nDb] = '\0'; |
| 29269 | |
| 29270 | if( 0==stat(zDb, &sStat) ){ |
| 29271 | *pMode = sStat.st_mode & 0777; |
| @@ -28943,12 +29272,10 @@ | |
| 29272 | }else{ |
| 29273 | rc = SQLITE_IOERR_FSTAT; |
| 29274 | } |
| 29275 | }else if( flags & SQLITE_OPEN_DELETEONCLOSE ){ |
| 29276 | *pMode = 0600; |
| 29277 | } |
| 29278 | return rc; |
| 29279 | } |
| 29280 | |
| 29281 | /* |
| @@ -30801,10 +31128,14 @@ | |
| 31128 | UNIXVFS("unix-nfs", nfsIoFinder ), |
| 31129 | UNIXVFS("unix-proxy", proxyIoFinder ), |
| 31130 | #endif |
| 31131 | }; |
| 31132 | unsigned int i; /* Loop counter */ |
| 31133 | |
| 31134 | /* Double-check that the aSyscall[] array has been constructed |
| 31135 | ** correctly. See ticket [bb3a86e890c8e96ab] */ |
| 31136 | assert( ArraySize(aSyscall)==16 ); |
| 31137 | |
| 31138 | /* Register all VFSes defined in the aVfs[] array */ |
| 31139 | for(i=0; i<(sizeof(aVfs)/sizeof(sqlite3_vfs)); i++){ |
| 31140 | sqlite3_vfs_register(&aVfs[i], i==0); |
| 31141 | } |
| @@ -31147,10 +31478,11 @@ | |
| 31478 | HANDLE hShared; /* Shared memory segment used for locking */ |
| 31479 | winceLock local; /* Locks obtained by this instance of winFile */ |
| 31480 | winceLock *shared; /* Global shared lock memory for the file */ |
| 31481 | #endif |
| 31482 | }; |
| 31483 | |
| 31484 | |
| 31485 | /* |
| 31486 | ** Forward prototypes. |
| 31487 | */ |
| 31488 | static int getSectorSize( |
| @@ -31315,11 +31647,11 @@ | |
| 31647 | |
| 31648 | /* |
| 31649 | ** Convert UTF-8 to multibyte character string. Space to hold the |
| 31650 | ** returned string is obtained from malloc(). |
| 31651 | */ |
| 31652 | SQLITE_API char *sqlite3_win32_utf8_to_mbcs(const char *zFilename){ |
| 31653 | char *zFilenameMbcs; |
| 31654 | WCHAR *zTmpWide; |
| 31655 | |
| 31656 | zTmpWide = utf8ToUnicode(zFilename); |
| 31657 | if( zTmpWide==0 ){ |
| @@ -31328,10 +31660,113 @@ | |
| 31660 | zFilenameMbcs = unicodeToMbcs(zTmpWide); |
| 31661 | free(zTmpWide); |
| 31662 | return zFilenameMbcs; |
| 31663 | } |
| 31664 | |
| 31665 | |
| 31666 | /* |
| 31667 | ** The return value of getLastErrorMsg |
| 31668 | ** is zero if the error message fits in the buffer, or non-zero |
| 31669 | ** otherwise (if the message was truncated). |
| 31670 | */ |
| 31671 | static int getLastErrorMsg(int nBuf, char *zBuf){ |
| 31672 | /* FormatMessage returns 0 on failure. Otherwise it |
| 31673 | ** returns the number of TCHARs written to the output |
| 31674 | ** buffer, excluding the terminating null char. |
| 31675 | */ |
| 31676 | DWORD error = GetLastError(); |
| 31677 | DWORD dwLen = 0; |
| 31678 | char *zOut = 0; |
| 31679 | |
| 31680 | if( isNT() ){ |
| 31681 | WCHAR *zTempWide = NULL; |
| 31682 | dwLen = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
| 31683 | NULL, |
| 31684 | error, |
| 31685 | 0, |
| 31686 | (LPWSTR) &zTempWide, |
| 31687 | 0, |
| 31688 | 0); |
| 31689 | if( dwLen > 0 ){ |
| 31690 | /* allocate a buffer and convert to UTF8 */ |
| 31691 | zOut = unicodeToUtf8(zTempWide); |
| 31692 | /* free the system buffer allocated by FormatMessage */ |
| 31693 | LocalFree(zTempWide); |
| 31694 | } |
| 31695 | /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. |
| 31696 | ** Since the ASCII version of these Windows API do not exist for WINCE, |
| 31697 | ** it's important to not reference them for WINCE builds. |
| 31698 | */ |
| 31699 | #if SQLITE_OS_WINCE==0 |
| 31700 | }else{ |
| 31701 | char *zTemp = NULL; |
| 31702 | dwLen = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, |
| 31703 | NULL, |
| 31704 | error, |
| 31705 | 0, |
| 31706 | (LPSTR) &zTemp, |
| 31707 | 0, |
| 31708 | 0); |
| 31709 | if( dwLen > 0 ){ |
| 31710 | /* allocate a buffer and convert to UTF8 */ |
| 31711 | zOut = sqlite3_win32_mbcs_to_utf8(zTemp); |
| 31712 | /* free the system buffer allocated by FormatMessage */ |
| 31713 | LocalFree(zTemp); |
| 31714 | } |
| 31715 | #endif |
| 31716 | } |
| 31717 | if( 0 == dwLen ){ |
| 31718 | sqlite3_snprintf(nBuf, zBuf, "OsError 0x%x (%u)", error, error); |
| 31719 | }else{ |
| 31720 | /* copy a maximum of nBuf chars to output buffer */ |
| 31721 | sqlite3_snprintf(nBuf, zBuf, "%s", zOut); |
| 31722 | /* free the UTF8 buffer */ |
| 31723 | free(zOut); |
| 31724 | } |
| 31725 | return 0; |
| 31726 | } |
| 31727 | |
| 31728 | /* |
| 31729 | ** |
| 31730 | ** This function - winLogErrorAtLine() - is only ever called via the macro |
| 31731 | ** winLogError(). |
| 31732 | ** |
| 31733 | ** This routine is invoked after an error occurs in an OS function. |
| 31734 | ** It logs a message using sqlite3_log() containing the current value of |
| 31735 | ** error code and, if possible, the human-readable equivalent from |
| 31736 | ** FormatMessage. |
| 31737 | ** |
| 31738 | ** The first argument passed to the macro should be the error code that |
| 31739 | ** will be returned to SQLite (e.g. SQLITE_IOERR_DELETE, SQLITE_CANTOPEN). |
| 31740 | ** The two subsequent arguments should be the name of the OS function that |
| 31741 | ** failed and the the associated file-system path, if any. |
| 31742 | */ |
| 31743 | #define winLogError(a,b,c) winLogErrorAtLine(a,b,c,__LINE__) |
| 31744 | static int winLogErrorAtLine( |
| 31745 | int errcode, /* SQLite error code */ |
| 31746 | const char *zFunc, /* Name of OS function that failed */ |
| 31747 | const char *zPath, /* File path associated with error */ |
| 31748 | int iLine /* Source line number where error occurred */ |
| 31749 | ){ |
| 31750 | char zMsg[500]; /* Human readable error text */ |
| 31751 | int i; /* Loop counter */ |
| 31752 | DWORD iErrno = GetLastError(); /* Error code */ |
| 31753 | |
| 31754 | zMsg[0] = 0; |
| 31755 | getLastErrorMsg(sizeof(zMsg), zMsg); |
| 31756 | assert( errcode!=SQLITE_OK ); |
| 31757 | if( zPath==0 ) zPath = ""; |
| 31758 | for(i=0; zMsg[i] && zMsg[i]!='\r' && zMsg[i]!='\n'; i++){} |
| 31759 | zMsg[i] = 0; |
| 31760 | sqlite3_log(errcode, |
| 31761 | "os_win.c:%d: (%d) %s(%s) - %s", |
| 31762 | iLine, iErrno, zFunc, zPath, zMsg |
| 31763 | ); |
| 31764 | |
| 31765 | return errcode; |
| 31766 | } |
| 31767 | |
| 31768 | #if SQLITE_OS_WINCE |
| 31769 | /************************************************************************* |
| 31770 | ** This section contains code for WinCE only. |
| 31771 | */ |
| 31772 | /* |
| @@ -31404,10 +31839,11 @@ | |
| 31839 | |
| 31840 | /* Create/open the named mutex */ |
| 31841 | pFile->hMutex = CreateMutexW(NULL, FALSE, zName); |
| 31842 | if (!pFile->hMutex){ |
| 31843 | pFile->lastErrno = GetLastError(); |
| 31844 | winLogError(SQLITE_ERROR, "winceCreateLock1", zFilename); |
| 31845 | free(zName); |
| 31846 | return FALSE; |
| 31847 | } |
| 31848 | |
| 31849 | /* Acquire the mutex before continuing */ |
| @@ -31435,10 +31871,11 @@ | |
| 31871 | pFile->shared = (winceLock*)MapViewOfFile(pFile->hShared, |
| 31872 | FILE_MAP_READ|FILE_MAP_WRITE, 0, 0, sizeof(winceLock)); |
| 31873 | /* If mapping failed, close the shared memory handle and erase it */ |
| 31874 | if (!pFile->shared){ |
| 31875 | pFile->lastErrno = GetLastError(); |
| 31876 | winLogError(SQLITE_ERROR, "winceCreateLock2", zFilename); |
| 31877 | CloseHandle(pFile->hShared); |
| 31878 | pFile->hShared = NULL; |
| 31879 | } |
| 31880 | } |
| 31881 | |
| @@ -31680,10 +32117,11 @@ | |
| 32117 | ** GetLastError(). |
| 32118 | */ |
| 32119 | dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); |
| 32120 | if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ |
| 32121 | pFile->lastErrno = GetLastError(); |
| 32122 | winLogError(SQLITE_IOERR_SEEK, "seekWinFile", pFile->zPath); |
| 32123 | return 1; |
| 32124 | } |
| 32125 | |
| 32126 | return 0; |
| 32127 | } |
| @@ -31725,11 +32163,12 @@ | |
| 32163 | free(pFile->zDeleteOnClose); |
| 32164 | } |
| 32165 | #endif |
| 32166 | OSTRACE(("CLOSE %d %s\n", pFile->h, rc ? "ok" : "failed")); |
| 32167 | OpenCounter(-1); |
| 32168 | return rc ? SQLITE_OK |
| 32169 | : winLogError(SQLITE_IOERR_CLOSE, "winClose", pFile->zPath); |
| 32170 | } |
| 32171 | |
| 32172 | /* |
| 32173 | ** Read data from a file into a buffer. Return SQLITE_OK if all |
| 32174 | ** bytes were read successfully and SQLITE_IOERR if anything goes |
| @@ -31751,11 +32190,11 @@ | |
| 32190 | if( seekWinFile(pFile, offset) ){ |
| 32191 | return SQLITE_FULL; |
| 32192 | } |
| 32193 | if( !ReadFile(pFile->h, pBuf, amt, &nRead, 0) ){ |
| 32194 | pFile->lastErrno = GetLastError(); |
| 32195 | return winLogError(SQLITE_IOERR_READ, "winRead", pFile->zPath); |
| 32196 | } |
| 32197 | if( nRead<(DWORD)amt ){ |
| 32198 | /* Unread parts of the buffer must be zero-filled */ |
| 32199 | memset(&((char*)pBuf)[nRead], 0, amt-nRead); |
| 32200 | return SQLITE_IOERR_SHORT_READ; |
| @@ -31802,11 +32241,11 @@ | |
| 32241 | |
| 32242 | if( rc ){ |
| 32243 | if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){ |
| 32244 | return SQLITE_FULL; |
| 32245 | } |
| 32246 | return winLogError(SQLITE_IOERR_WRITE, "winWrite", pFile->zPath); |
| 32247 | } |
| 32248 | return SQLITE_OK; |
| 32249 | } |
| 32250 | |
| 32251 | /* |
| @@ -31830,14 +32269,14 @@ | |
| 32269 | nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; |
| 32270 | } |
| 32271 | |
| 32272 | /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ |
| 32273 | if( seekWinFile(pFile, nByte) ){ |
| 32274 | rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate1", pFile->zPath); |
| 32275 | }else if( 0==SetEndOfFile(pFile->h) ){ |
| 32276 | pFile->lastErrno = GetLastError(); |
| 32277 | rc = winLogError(SQLITE_IOERR_TRUNCATE, "winTruncate2", pFile->zPath); |
| 32278 | } |
| 32279 | |
| 32280 | OSTRACE(("TRUNCATE %d %lld %s\n", pFile->h, nByte, rc ? "failed" : "ok")); |
| 32281 | return rc; |
| 32282 | } |
| @@ -31855,10 +32294,11 @@ | |
| 32294 | ** Make sure all writes to a particular file are committed to disk. |
| 32295 | */ |
| 32296 | static int winSync(sqlite3_file *id, int flags){ |
| 32297 | #if !defined(NDEBUG) || !defined(SQLITE_NO_SYNC) || defined(SQLITE_DEBUG) |
| 32298 | winFile *pFile = (winFile*)id; |
| 32299 | BOOL rc; |
| 32300 | #else |
| 32301 | UNUSED_PARAMETER(id); |
| 32302 | #endif |
| 32303 | |
| 32304 | assert( pFile ); |
| @@ -31867,36 +32307,37 @@ | |
| 32307 | || (flags&0x0F)==SQLITE_SYNC_FULL |
| 32308 | ); |
| 32309 | |
| 32310 | OSTRACE(("SYNC %d lock=%d\n", pFile->h, pFile->locktype)); |
| 32311 | |
| 32312 | /* Unix cannot, but some systems may return SQLITE_FULL from here. This |
| 32313 | ** line is to test that doing so does not cause any problems. |
| 32314 | */ |
| 32315 | SimulateDiskfullError( return SQLITE_FULL ); |
| 32316 | |
| 32317 | #ifndef SQLITE_TEST |
| 32318 | UNUSED_PARAMETER(flags); |
| 32319 | #else |
| 32320 | if( (flags&0x0F)==SQLITE_SYNC_FULL ){ |
| 32321 | sqlite3_fullsync_count++; |
| 32322 | } |
| 32323 | sqlite3_sync_count++; |
| 32324 | #endif |
| 32325 | |
| 32326 | /* If we compiled with the SQLITE_NO_SYNC flag, then syncing is a |
| 32327 | ** no-op |
| 32328 | */ |
| 32329 | #ifdef SQLITE_NO_SYNC |
| 32330 | return SQLITE_OK; |
| 32331 | #else |
| 32332 | rc = FlushFileBuffers(pFile->h); |
| 32333 | SimulateIOError( rc=FALSE ); |
| 32334 | if( rc ){ |
| 32335 | return SQLITE_OK; |
| 32336 | }else{ |
| 32337 | pFile->lastErrno = GetLastError(); |
| 32338 | return winLogError(SQLITE_IOERR_FSYNC, "winSync", pFile->zPath); |
| 32339 | } |
| 32340 | #endif |
| 32341 | } |
| 32342 | |
| 32343 | /* |
| @@ -31913,11 +32354,11 @@ | |
| 32354 | lowerBits = GetFileSize(pFile->h, &upperBits); |
| 32355 | if( (lowerBits == INVALID_FILE_SIZE) |
| 32356 | && ((error = GetLastError()) != NO_ERROR) ) |
| 32357 | { |
| 32358 | pFile->lastErrno = error; |
| 32359 | return winLogError(SQLITE_IOERR_FSTAT, "winFileSize", pFile->zPath); |
| 32360 | } |
| 32361 | *pSize = (((sqlite3_int64)upperBits)<<32) + lowerBits; |
| 32362 | return SQLITE_OK; |
| 32363 | } |
| 32364 | |
| @@ -31952,10 +32393,11 @@ | |
| 32393 | res = LockFile(pFile->h, SHARED_FIRST+pFile->sharedLockByte, 0, 1, 0); |
| 32394 | #endif |
| 32395 | } |
| 32396 | if( res == 0 ){ |
| 32397 | pFile->lastErrno = GetLastError(); |
| 32398 | /* No need to log a failure to lock */ |
| 32399 | } |
| 32400 | return res; |
| 32401 | } |
| 32402 | |
| 32403 | /* |
| @@ -31970,12 +32412,13 @@ | |
| 32412 | #if SQLITE_OS_WINCE==0 |
| 32413 | }else{ |
| 32414 | res = UnlockFile(pFile->h, SHARED_FIRST + pFile->sharedLockByte, 0, 1, 0); |
| 32415 | #endif |
| 32416 | } |
| 32417 | if( res==0 && GetLastError()!=ERROR_NOT_LOCKED ){ |
| 32418 | pFile->lastErrno = GetLastError(); |
| 32419 | winLogError(SQLITE_IOERR_UNLOCK, "unlockReadLock", pFile->zPath); |
| 32420 | } |
| 32421 | return res; |
| 32422 | } |
| 32423 | |
| 32424 | /* |
| @@ -32172,11 +32615,11 @@ | |
| 32615 | if( type>=EXCLUSIVE_LOCK ){ |
| 32616 | UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); |
| 32617 | if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ |
| 32618 | /* This should never happen. We should always be able to |
| 32619 | ** reacquire the read lock */ |
| 32620 | rc = winLogError(SQLITE_IOERR_UNLOCK, "winUnlock", pFile->zPath); |
| 32621 | } |
| 32622 | } |
| 32623 | if( type>=RESERVED_LOCK ){ |
| 32624 | UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); |
| 32625 | } |
| @@ -32487,10 +32930,11 @@ | |
| 32930 | return SQLITE_NOMEM; |
| 32931 | } |
| 32932 | memset(pNew, 0, sizeof(*pNew)); |
| 32933 | pNew->zFilename = (char*)&pNew[1]; |
| 32934 | sqlite3_snprintf(nName+15, pNew->zFilename, "%s-shm", pDbFd->zPath); |
| 32935 | sqlite3FileSuffix3(pDbFd->zPath, pNew->zFilename); |
| 32936 | |
| 32937 | /* Look to see if there is an existing winShmNode that can be used. |
| 32938 | ** If no matching winShmNode currently exists, create a new one. |
| 32939 | */ |
| 32940 | winShmEnterMutex(); |
| @@ -32529,11 +32973,11 @@ | |
| 32973 | ** If not, truncate the file to zero length. |
| 32974 | */ |
| 32975 | if( winShmSystemLock(pShmNode, _SHM_WRLCK, WIN_SHM_DMS, 1)==SQLITE_OK ){ |
| 32976 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, 0); |
| 32977 | if( rc!=SQLITE_OK ){ |
| 32978 | rc = winLogError(SQLITE_IOERR_SHMOPEN, "winOpenShm", pDbFd->zPath); |
| 32979 | } |
| 32980 | } |
| 32981 | if( rc==SQLITE_OK ){ |
| 32982 | winShmSystemLock(pShmNode, _SHM_UNLCK, WIN_SHM_DMS, 1); |
| 32983 | rc = winShmSystemLock(pShmNode, _SHM_RDLCK, WIN_SHM_DMS, 1); |
| @@ -32788,11 +33232,11 @@ | |
| 33232 | ** Check to see if it has been allocated (i.e. if the wal-index file is |
| 33233 | ** large enough to contain the requested region). |
| 33234 | */ |
| 33235 | rc = winFileSize((sqlite3_file *)&pShmNode->hFile, &sz); |
| 33236 | if( rc!=SQLITE_OK ){ |
| 33237 | rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap1", pDbFd->zPath); |
| 33238 | goto shmpage_out; |
| 33239 | } |
| 33240 | |
| 33241 | if( sz<nByte ){ |
| 33242 | /* The requested memory region does not exist. If isWrite is set to |
| @@ -32802,11 +33246,11 @@ | |
| 33246 | ** the requested memory region. |
| 33247 | */ |
| 33248 | if( !isWrite ) goto shmpage_out; |
| 33249 | rc = winTruncate((sqlite3_file *)&pShmNode->hFile, nByte); |
| 33250 | if( rc!=SQLITE_OK ){ |
| 33251 | rc = winLogError(SQLITE_IOERR_SHMSIZE, "winShmMap2", pDbFd->zPath); |
| 33252 | goto shmpage_out; |
| 33253 | } |
| 33254 | } |
| 33255 | |
| 33256 | /* Map the requested memory region into this processes address space. */ |
| @@ -32839,11 +33283,11 @@ | |
| 33283 | (int)GetCurrentProcessId(), pShmNode->nRegion, iOffset, szRegion, |
| 33284 | pMap ? "ok" : "failed")); |
| 33285 | } |
| 33286 | if( !pMap ){ |
| 33287 | pShmNode->lastErrno = GetLastError(); |
| 33288 | rc = winLogError(SQLITE_IOERR_SHMMAP, "winShmMap3", pDbFd->zPath); |
| 33289 | if( hMap ) CloseHandle(hMap); |
| 33290 | goto shmpage_out; |
| 33291 | } |
| 33292 | |
| 33293 | pShmNode->aRegion[pShmNode->nRegion].pMap = pMap; |
| @@ -32921,11 +33365,11 @@ | |
| 33365 | zConverted = utf8ToUnicode(zFilename); |
| 33366 | /* isNT() is 1 if SQLITE_OS_WINCE==1, so this else is never executed. |
| 33367 | */ |
| 33368 | #if SQLITE_OS_WINCE==0 |
| 33369 | }else{ |
| 33370 | zConverted = sqlite3_win32_utf8_to_mbcs(zFilename); |
| 33371 | #endif |
| 33372 | } |
| 33373 | /* caller will handle out of memory */ |
| 33374 | return zConverted; |
| 33375 | } |
| @@ -33001,72 +33445,10 @@ | |
| 33445 | |
| 33446 | OSTRACE(("TEMP FILENAME: %s\n", zBuf)); |
| 33447 | return SQLITE_OK; |
| 33448 | } |
| 33449 | |
| 33450 | /* |
| 33451 | ** Open a file. |
| 33452 | */ |
| 33453 | static int winOpen( |
| 33454 | sqlite3_vfs *pVfs, /* Not used */ |
| @@ -33234,10 +33616,11 @@ | |
| 33616 | h, zName, dwDesiredAccess, |
| 33617 | h==INVALID_HANDLE_VALUE ? "failed" : "ok")); |
| 33618 | |
| 33619 | if( h==INVALID_HANDLE_VALUE ){ |
| 33620 | pFile->lastErrno = GetLastError(); |
| 33621 | winLogError(SQLITE_CANTOPEN, "winOpen", zUtf8Name); |
| 33622 | free(zConverted); |
| 33623 | if( isReadWrite ){ |
| 33624 | return winOpen(pVfs, zName, id, |
| 33625 | ((flags|SQLITE_OPEN_READONLY)&~(SQLITE_OPEN_CREATE|SQLITE_OPEN_READWRITE)), pOutFlags); |
| 33626 | }else{ |
| @@ -33337,11 +33720,12 @@ | |
| 33720 | OSTRACE(("DELETE \"%s\" %s\n", zFilename, |
| 33721 | ( (rc==INVALID_FILE_ATTRIBUTES) && (error==ERROR_FILE_NOT_FOUND)) ? |
| 33722 | "ok" : "failed" )); |
| 33723 | |
| 33724 | return ( (rc == INVALID_FILE_ATTRIBUTES) |
| 33725 | && (error == ERROR_FILE_NOT_FOUND)) ? SQLITE_OK : |
| 33726 | winLogError(SQLITE_IOERR_DELETE, "winDelete", zFilename); |
| 33727 | } |
| 33728 | |
| 33729 | /* |
| 33730 | ** Check the existance and status of a file. |
| 33731 | */ |
| @@ -33377,10 +33761,11 @@ | |
| 33761 | }else{ |
| 33762 | attr = sAttrData.dwFileAttributes; |
| 33763 | } |
| 33764 | }else{ |
| 33765 | if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ |
| 33766 | winLogError(SQLITE_IOERR_ACCESS, "winAccess", zFilename); |
| 33767 | free(zConverted); |
| 33768 | return SQLITE_IOERR_ACCESS; |
| 33769 | }else{ |
| 33770 | attr = INVALID_FILE_ATTRIBUTES; |
| 33771 | } |
| @@ -33440,10 +33825,17 @@ | |
| 33825 | |
| 33826 | #if !SQLITE_OS_WINCE && !defined(__CYGWIN__) |
| 33827 | int nByte; |
| 33828 | void *zConverted; |
| 33829 | char *zOut; |
| 33830 | |
| 33831 | /* If this path name begins with "/X:", where "X" is any alphabetic |
| 33832 | ** character, discard the initial "/" from the pathname. |
| 33833 | */ |
| 33834 | if( zRelative[0]=='/' && sqlite3Isalpha(zRelative[1]) && zRelative[2]==':' ){ |
| 33835 | zRelative++; |
| 33836 | } |
| 33837 | |
| 33838 | /* It's odd to simulate an io-error here, but really this is just |
| 33839 | ** using the io-error infrastructure to test that SQLite handles this |
| 33840 | ** function failing. This function could fail if, for example, the |
| 33841 | ** current working directory has been unlinked. |
| @@ -36252,10 +36644,11 @@ | |
| 36644 | #define _WAL_H_ |
| 36645 | |
| 36646 | |
| 36647 | #ifdef SQLITE_OMIT_WAL |
| 36648 | # define sqlite3WalOpen(x,y,z) 0 |
| 36649 | # define sqlite3WalLimit(x,y) |
| 36650 | # define sqlite3WalClose(w,x,y,z) 0 |
| 36651 | # define sqlite3WalBeginReadTransaction(y,z) 0 |
| 36652 | # define sqlite3WalEndReadTransaction(z) |
| 36653 | # define sqlite3WalRead(v,w,x,y,z) 0 |
| 36654 | # define sqlite3WalDbsize(y) 0 |
| @@ -36277,13 +36670,16 @@ | |
| 36670 | ** There is one object of this type for each pager. |
| 36671 | */ |
| 36672 | typedef struct Wal Wal; |
| 36673 | |
| 36674 | /* Open and close a connection to a write-ahead log. */ |
| 36675 | SQLITE_PRIVATE int sqlite3WalOpen(sqlite3_vfs*, sqlite3_file*, const char *, int, i64, Wal**); |
| 36676 | SQLITE_PRIVATE int sqlite3WalClose(Wal *pWal, int sync_flags, int, u8 *); |
| 36677 | |
| 36678 | /* Set the limiting size of a WAL file. */ |
| 36679 | SQLITE_PRIVATE void sqlite3WalLimit(Wal*, i64); |
| 36680 | |
| 36681 | /* Used by readers to open (lock) and close (unlock) a snapshot. A |
| 36682 | ** snapshot is like a read-transaction. It is the state of the database |
| 36683 | ** at an instant in time. sqlite3WalOpenSnapshot gets a read lock and |
| 36684 | ** preserves the current state even if the other threads or processes |
| 36685 | ** write to or checkpoint the WAL. sqlite3WalCloseSnapshot() closes the |
| @@ -40628,10 +41024,12 @@ | |
| 41024 | int nPathname = 0; /* Number of bytes in zPathname */ |
| 41025 | int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; /* False to omit journal */ |
| 41026 | int noReadlock = (flags & PAGER_NO_READLOCK)!=0; /* True to omit read-lock */ |
| 41027 | int pcacheSize = sqlite3PcacheSize(); /* Bytes to allocate for PCache */ |
| 41028 | u32 szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; /* Default page size */ |
| 41029 | const char *zUri = 0; /* URI args to copy */ |
| 41030 | int nUri = 0; /* Number of bytes of URI args at *zUri */ |
| 41031 | |
| 41032 | /* Figure out how much space is required for each journal file-handle |
| 41033 | ** (there are two of them, the main journal and the sub-journal). This |
| 41034 | ** is the maximum space required for an in-memory journal file handle |
| 41035 | ** and a regular journal file-handle. Note that a "regular journal-handle" |
| @@ -40658,18 +41056,25 @@ | |
| 41056 | /* Compute and store the full pathname in an allocated buffer pointed |
| 41057 | ** to by zPathname, length nPathname. Or, if this is a temporary file, |
| 41058 | ** leave both nPathname and zPathname set to 0. |
| 41059 | */ |
| 41060 | if( zFilename && zFilename[0] ){ |
| 41061 | const char *z; |
| 41062 | nPathname = pVfs->mxPathname+1; |
| 41063 | zPathname = sqlite3Malloc(nPathname*2); |
| 41064 | if( zPathname==0 ){ |
| 41065 | return SQLITE_NOMEM; |
| 41066 | } |
| 41067 | zPathname[0] = 0; /* Make sure initialized even if FullPathname() fails */ |
| 41068 | rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); |
| 41069 | nPathname = sqlite3Strlen30(zPathname); |
| 41070 | z = zUri = &zFilename[sqlite3Strlen30(zFilename)+1]; |
| 41071 | while( *z ){ |
| 41072 | z += sqlite3Strlen30(z)+1; |
| 41073 | z += sqlite3Strlen30(z)+1; |
| 41074 | } |
| 41075 | nUri = &z[1] - zUri; |
| 41076 | if( rc==SQLITE_OK && nPathname+8>pVfs->mxPathname ){ |
| 41077 | /* This branch is taken when the journal path required by |
| 41078 | ** the database being opened will be more than pVfs->mxPathname |
| 41079 | ** bytes in length. This means the database cannot be opened, |
| 41080 | ** as it will not be possible to open the journal file or even |
| @@ -40698,11 +41103,11 @@ | |
| 41103 | pPtr = (u8 *)sqlite3MallocZero( |
| 41104 | ROUND8(sizeof(*pPager)) + /* Pager structure */ |
| 41105 | ROUND8(pcacheSize) + /* PCache object */ |
| 41106 | ROUND8(pVfs->szOsFile) + /* The main db file */ |
| 41107 | journalFileSize * 2 + /* The two journal files */ |
| 41108 | nPathname + 1 + nUri + /* zFilename */ |
| 41109 | nPathname + 8 + 1 /* zJournal */ |
| 41110 | #ifndef SQLITE_OMIT_WAL |
| 41111 | + nPathname + 4 + 1 /* zWal */ |
| 41112 | #endif |
| 41113 | ); |
| @@ -40720,18 +41125,21 @@ | |
| 41125 | assert( EIGHT_BYTE_ALIGNMENT(pPager->jfd) ); |
| 41126 | |
| 41127 | /* Fill in the Pager.zFilename and Pager.zJournal buffers, if required. */ |
| 41128 | if( zPathname ){ |
| 41129 | assert( nPathname>0 ); |
| 41130 | pPager->zJournal = (char*)(pPtr += nPathname + 1 + nUri); |
| 41131 | memcpy(pPager->zFilename, zPathname, nPathname); |
| 41132 | memcpy(&pPager->zFilename[nPathname+1], zUri, nUri); |
| 41133 | memcpy(pPager->zJournal, zPathname, nPathname); |
| 41134 | memcpy(&pPager->zJournal[nPathname], "-journal", 8); |
| 41135 | sqlite3FileSuffix3(pPager->zFilename, pPager->zJournal); |
| 41136 | #ifndef SQLITE_OMIT_WAL |
| 41137 | pPager->zWal = &pPager->zJournal[nPathname+8+1]; |
| 41138 | memcpy(pPager->zWal, zPathname, nPathname); |
| 41139 | memcpy(&pPager->zWal[nPathname], "-wal", 4); |
| 41140 | sqlite3FileSuffix3(pPager->zFilename, pPager->zWal); |
| 41141 | #endif |
| 41142 | sqlite3_free(zPathname); |
| 41143 | } |
| 41144 | pPager->pVfs = pVfs; |
| 41145 | pPager->vfsFlags = vfsFlags; |
| @@ -42064,15 +42472,25 @@ | |
| 42472 | */ |
| 42473 | sqlite3BackupRestart(pPager->pBackup); |
| 42474 | }else{ |
| 42475 | if( pagerUseWal(pPager) ){ |
| 42476 | PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); |
| 42477 | PgHdr *pPageOne = 0; |
| 42478 | if( pList==0 ){ |
| 42479 | /* Must have at least one page for the WAL commit flag. |
| 42480 | ** Ticket [2d1a5c67dfc2363e44f29d9bbd57f] 2011-05-18 */ |
| 42481 | rc = sqlite3PagerGet(pPager, 1, &pPageOne); |
| 42482 | pList = pPageOne; |
| 42483 | pList->pDirty = 0; |
| 42484 | } |
| 42485 | assert( rc==SQLITE_OK ); |
| 42486 | if( ALWAYS(pList) ){ |
| 42487 | rc = pagerWalFrames(pPager, pList, pPager->dbSize, 1, |
| 42488 | (pPager->fullSync ? pPager->syncFlags : 0) |
| 42489 | ); |
| 42490 | } |
| 42491 | sqlite3PagerUnref(pPageOne); |
| 42492 | if( rc==SQLITE_OK ){ |
| 42493 | sqlite3PcacheCleanAll(pPager->pPCache); |
| 42494 | } |
| 42495 | }else{ |
| 42496 | /* The following block updates the change-counter. Exactly how it |
| @@ -42926,10 +43344,11 @@ | |
| 43344 | ** An attempt to set a limit smaller than -1 is a no-op. |
| 43345 | */ |
| 43346 | SQLITE_PRIVATE i64 sqlite3PagerJournalSizeLimit(Pager *pPager, i64 iLimit){ |
| 43347 | if( iLimit>=-1 ){ |
| 43348 | pPager->journalSizeLimit = iLimit; |
| 43349 | sqlite3WalLimit(pPager->pWal, iLimit); |
| 43350 | } |
| 43351 | return pPager->journalSizeLimit; |
| 43352 | } |
| 43353 | |
| 43354 | /* |
| @@ -43017,11 +43436,12 @@ | |
| 43436 | /* Open the connection to the log file. If this operation fails, |
| 43437 | ** (e.g. due to malloc() failure), return an error code. |
| 43438 | */ |
| 43439 | if( rc==SQLITE_OK ){ |
| 43440 | rc = sqlite3WalOpen(pPager->pVfs, |
| 43441 | pPager->fd, pPager->zWal, pPager->exclusiveMode, |
| 43442 | pPager->journalSizeLimit, &pPager->pWal |
| 43443 | ); |
| 43444 | } |
| 43445 | |
| 43446 | return rc; |
| 43447 | } |
| @@ -43549,10 +43969,11 @@ | |
| 43969 | struct Wal { |
| 43970 | sqlite3_vfs *pVfs; /* The VFS used to create pDbFd */ |
| 43971 | sqlite3_file *pDbFd; /* File handle for the database file */ |
| 43972 | sqlite3_file *pWalFd; /* File handle for WAL file */ |
| 43973 | u32 iCallback; /* Value to pass to log callback (or 0) */ |
| 43974 | i64 mxWalSize; /* Truncate WAL to this size upon reset */ |
| 43975 | int nWiData; /* Size of array apWiData */ |
| 43976 | volatile u32 **apWiData; /* Pointer to wal-index content in memory */ |
| 43977 | u32 szPage; /* Database page size */ |
| 43978 | i16 readLock; /* Which read lock is being held. -1 for none */ |
| 43979 | u8 exclusiveMode; /* Non-zero if connection is in exclusive mode */ |
| @@ -44371,10 +44792,11 @@ | |
| 44792 | SQLITE_PRIVATE int sqlite3WalOpen( |
| 44793 | sqlite3_vfs *pVfs, /* vfs module to open wal and wal-index */ |
| 44794 | sqlite3_file *pDbFd, /* The open database file */ |
| 44795 | const char *zWalName, /* Name of the WAL file */ |
| 44796 | int bNoShm, /* True to run in heap-memory mode */ |
| 44797 | i64 mxWalSize, /* Truncate WAL to this size on reset */ |
| 44798 | Wal **ppWal /* OUT: Allocated Wal handle */ |
| 44799 | ){ |
| 44800 | int rc; /* Return Code */ |
| 44801 | Wal *pRet; /* Object to allocate and return */ |
| 44802 | int flags; /* Flags passed to OsOpen() */ |
| @@ -44403,10 +44825,11 @@ | |
| 44825 | |
| 44826 | pRet->pVfs = pVfs; |
| 44827 | pRet->pWalFd = (sqlite3_file *)&pRet[1]; |
| 44828 | pRet->pDbFd = pDbFd; |
| 44829 | pRet->readLock = -1; |
| 44830 | pRet->mxWalSize = mxWalSize; |
| 44831 | pRet->zWalName = zWalName; |
| 44832 | pRet->exclusiveMode = (bNoShm ? WAL_HEAPMEMORY_MODE: WAL_NORMAL_MODE); |
| 44833 | |
| 44834 | /* Open file handle on the write-ahead log file. */ |
| 44835 | flags = (SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE|SQLITE_OPEN_WAL); |
| @@ -44423,10 +44846,17 @@ | |
| 44846 | *ppWal = pRet; |
| 44847 | WALTRACE(("WAL%d: opened\n", pRet)); |
| 44848 | } |
| 44849 | return rc; |
| 44850 | } |
| 44851 | |
| 44852 | /* |
| 44853 | ** Change the size to which the WAL file is trucated on each reset. |
| 44854 | */ |
| 44855 | SQLITE_PRIVATE void sqlite3WalLimit(Wal *pWal, i64 iLimit){ |
| 44856 | if( pWal ) pWal->mxWalSize = iLimit; |
| 44857 | } |
| 44858 | |
| 44859 | /* |
| 44860 | ** Find the smallest page number out of all pages held in the WAL that |
| 44861 | ** has not been returned by any prior invocation of this method on the |
| 44862 | ** same WalIterator object. Write into *piFrame the frame index where |
| @@ -45659,10 +46089,26 @@ | |
| 46089 | ** safe and means there is no special case for sqlite3WalUndo() |
| 46090 | ** to handle if this transaction is rolled back. |
| 46091 | */ |
| 46092 | int i; /* Loop counter */ |
| 46093 | u32 *aSalt = pWal->hdr.aSalt; /* Big-endian salt values */ |
| 46094 | |
| 46095 | /* Limit the size of WAL file if the journal_size_limit PRAGMA is |
| 46096 | ** set to a non-negative value. Log errors encountered |
| 46097 | ** during the truncation attempt. */ |
| 46098 | if( pWal->mxWalSize>=0 ){ |
| 46099 | i64 sz; |
| 46100 | int rx; |
| 46101 | rx = sqlite3OsFileSize(pWal->pWalFd, &sz); |
| 46102 | if( rx==SQLITE_OK && (sz > pWal->mxWalSize) ){ |
| 46103 | rx = sqlite3OsTruncate(pWal->pWalFd, pWal->mxWalSize); |
| 46104 | } |
| 46105 | if( rx ){ |
| 46106 | sqlite3_log(rx, "cannot limit WAL size: %s", pWal->zWalName); |
| 46107 | } |
| 46108 | } |
| 46109 | |
| 46110 | pWal->nCkpt++; |
| 46111 | pWal->hdr.mxFrame = 0; |
| 46112 | sqlite3Put4byte((u8*)&aSalt[0], 1 + sqlite3Get4byte((u8*)&aSalt[0])); |
| 46113 | aSalt[1] = salt1; |
| 46114 | walIndexWriteHdr(pWal); |
| @@ -47764,10 +48210,11 @@ | |
| 48210 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 48211 | if( offset<0 ){ |
| 48212 | *pRC = SQLITE_CORRUPT_BKPT; |
| 48213 | goto ptrmap_exit; |
| 48214 | } |
| 48215 | assert( offset <= (int)pBt->usableSize-5 ); |
| 48216 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 48217 | |
| 48218 | if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){ |
| 48219 | TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent)); |
| 48220 | *pRC= rc = sqlite3PagerWrite(pDbPage); |
| @@ -47803,10 +48250,15 @@ | |
| 48250 | return rc; |
| 48251 | } |
| 48252 | pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage); |
| 48253 | |
| 48254 | offset = PTRMAP_PTROFFSET(iPtrmap, key); |
| 48255 | if( offset<0 ){ |
| 48256 | sqlite3PagerUnref(pDbPage); |
| 48257 | return SQLITE_CORRUPT_BKPT; |
| 48258 | } |
| 48259 | assert( offset <= (int)pBt->usableSize-5 ); |
| 48260 | assert( pEType!=0 ); |
| 48261 | *pEType = pPtrmap[offset]; |
| 48262 | if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]); |
| 48263 | |
| 48264 | sqlite3PagerUnref(pDbPage); |
| @@ -48664,17 +49116,17 @@ | |
| 49116 | ** SQLITE_CONSTRAINT error. We cannot allow two or more BtShared |
| 49117 | ** objects in the same database connection since doing so will lead |
| 49118 | ** to problems with locking. |
| 49119 | */ |
| 49120 | SQLITE_PRIVATE int sqlite3BtreeOpen( |
| 49121 | sqlite3_vfs *pVfs, /* VFS to use for this b-tree */ |
| 49122 | const char *zFilename, /* Name of the file containing the BTree database */ |
| 49123 | sqlite3 *db, /* Associated database handle */ |
| 49124 | Btree **ppBtree, /* Pointer to new Btree object written here */ |
| 49125 | int flags, /* Options */ |
| 49126 | int vfsFlags /* Flags passed through to sqlite3_vfs.xOpen() */ |
| 49127 | ){ |
| 49128 | BtShared *pBt = 0; /* Shared part of btree structure */ |
| 49129 | Btree *p; /* Handle to return */ |
| 49130 | sqlite3_mutex *mutexOpen = 0; /* Prevents a race condition. Ticket #3537 */ |
| 49131 | int rc = SQLITE_OK; /* Result code from this function */ |
| 49132 | u8 nReserve; /* Byte of unused space on each page */ |
| @@ -48692,10 +49144,11 @@ | |
| 49144 | const int isMemdb = (zFilename && strcmp(zFilename, ":memory:")==0) |
| 49145 | || (isTempDb && sqlite3TempInMemory(db)); |
| 49146 | #endif |
| 49147 | |
| 49148 | assert( db!=0 ); |
| 49149 | assert( pVfs!=0 ); |
| 49150 | assert( sqlite3_mutex_held(db->mutex) ); |
| 49151 | assert( (flags&0xff)==flags ); /* flags fit in 8 bits */ |
| 49152 | |
| 49153 | /* Only a BTREE_SINGLE database can be BTREE_UNORDERED */ |
| 49154 | assert( (flags & BTREE_UNORDERED)==0 || (flags & BTREE_SINGLE)!=0 ); |
| @@ -48710,11 +49163,10 @@ | |
| 49163 | flags |= BTREE_MEMORY; |
| 49164 | } |
| 49165 | if( (vfsFlags & SQLITE_OPEN_MAIN_DB)!=0 && (isMemdb || isTempDb) ){ |
| 49166 | vfsFlags = (vfsFlags & ~SQLITE_OPEN_MAIN_DB) | SQLITE_OPEN_TEMP_DB; |
| 49167 | } |
| 49168 | p = sqlite3MallocZero(sizeof(Btree)); |
| 49169 | if( !p ){ |
| 49170 | return SQLITE_NOMEM; |
| 49171 | } |
| 49172 | p->inTrans = TRANS_NONE; |
| @@ -58781,10 +59233,11 @@ | |
| 59233 | sqlite3_randomness(sizeof(iRandom), &iRandom); |
| 59234 | zMaster = sqlite3MPrintf(db, "%s-mj%08X", zMainFile, iRandom&0x7fffffff); |
| 59235 | if( !zMaster ){ |
| 59236 | return SQLITE_NOMEM; |
| 59237 | } |
| 59238 | sqlite3FileSuffix3(zMainFile, zMaster); |
| 59239 | rc = sqlite3OsAccess(pVfs, zMaster, SQLITE_ACCESS_EXISTS, &res); |
| 59240 | }while( rc==SQLITE_OK && res ); |
| 59241 | if( rc==SQLITE_OK ){ |
| 59242 | /* Open the master journal. */ |
| 59243 | rc = sqlite3OsOpenMalloc(pVfs, zMaster, &pMaster, |
| @@ -58994,10 +59447,19 @@ | |
| 59447 | } |
| 59448 | } |
| 59449 | } |
| 59450 | db->nStatement--; |
| 59451 | p->iStatement = 0; |
| 59452 | |
| 59453 | if( rc==SQLITE_OK ){ |
| 59454 | if( eOp==SAVEPOINT_ROLLBACK ){ |
| 59455 | rc = sqlite3VtabSavepoint(db, SAVEPOINT_ROLLBACK, iSavepoint); |
| 59456 | } |
| 59457 | if( rc==SQLITE_OK ){ |
| 59458 | rc = sqlite3VtabSavepoint(db, SAVEPOINT_RELEASE, iSavepoint); |
| 59459 | } |
| 59460 | } |
| 59461 | |
| 59462 | /* If the statement transaction is being rolled back, also restore the |
| 59463 | ** database handles deferred constraint counter to the value it had when |
| 59464 | ** the statement transaction was opened. */ |
| 59465 | if( eOp==SAVEPOINT_ROLLBACK ){ |
| @@ -59911,11 +60373,11 @@ | |
| 60373 | /* mem1.flags = 0; // Will be initialized by sqlite3VdbeSerialGet() */ |
| 60374 | VVA_ONLY( mem1.zMalloc = 0; ) /* Only needed by assert() statements */ |
| 60375 | |
| 60376 | /* Compilers may complain that mem1.u.i is potentially uninitialized. |
| 60377 | ** We could initialize it, as shown here, to silence those complaints. |
| 60378 | ** But in fact, mem1.u.i will never actually be used uninitialized, and doing |
| 60379 | ** the unnecessary initialization has a measurable negative performance |
| 60380 | ** impact, since this routine is a very high runner. And so, we choose |
| 60381 | ** to ignore the compiler warnings and leave this variable uninitialized. |
| 60382 | */ |
| 60383 | /* mem1.u.i = 0; // not needed, here to silence compiler warning */ |
| @@ -62326,10 +62788,11 @@ | |
| 62788 | Mem *pIn2 = 0; /* 2nd input operand */ |
| 62789 | Mem *pIn3 = 0; /* 3rd input operand */ |
| 62790 | Mem *pOut = 0; /* Output operand */ |
| 62791 | int iCompare = 0; /* Result of last OP_Compare operation */ |
| 62792 | int *aPermute = 0; /* Permutation of columns for OP_Compare */ |
| 62793 | i64 lastRowid = db->lastRowid; /* Saved value of the last insert ROWID */ |
| 62794 | #ifdef VDBE_PROFILE |
| 62795 | u64 start; /* CPU clock count at start of opcode */ |
| 62796 | int origPc; /* Program counter at start of opcode */ |
| 62797 | #endif |
| 62798 | /******************************************************************** |
| @@ -63004,10 +63467,11 @@ | |
| 63467 | VdbeFrame *pFrame = p->pFrame; |
| 63468 | p->pFrame = pFrame->pParent; |
| 63469 | p->nFrame--; |
| 63470 | sqlite3VdbeSetChanges(db, p->nChange); |
| 63471 | pc = sqlite3VdbeFrameRestore(pFrame); |
| 63472 | lastRowid = db->lastRowid; |
| 63473 | if( pOp->p2==OE_Ignore ){ |
| 63474 | /* Instruction pc is the OP_Program that invoked the sub-program |
| 63475 | ** currently being halted. If the p2 instruction of this OP_Halt |
| 63476 | ** instruction is set to OE_Ignore, then the sub-program is throwing |
| 63477 | ** an IGNORE exception. In this case jump to the address specified |
| @@ -63576,11 +64040,13 @@ | |
| 64040 | assert( pOp>aOp ); |
| 64041 | assert( pOp[-1].p4type==P4_COLLSEQ ); |
| 64042 | assert( pOp[-1].opcode==OP_CollSeq ); |
| 64043 | u.ag.ctx.pColl = pOp[-1].p4.pColl; |
| 64044 | } |
| 64045 | db->lastRowid = lastRowid; |
| 64046 | (*u.ag.ctx.pFunc->xFunc)(&u.ag.ctx, u.ag.n, u.ag.apVal); /* IMP: R-24505-23230 */ |
| 64047 | lastRowid = db->lastRowid; |
| 64048 | if( db->mallocFailed ){ |
| 64049 | /* Even though a malloc() has failed, the implementation of the |
| 64050 | ** user function may have called an sqlite3_result_XXX() function |
| 64051 | ** to return a value. The following call releases any resources |
| 64052 | ** associated with such a value. |
| @@ -64783,10 +65249,18 @@ | |
| 65249 | "SQL statements in progress"); |
| 65250 | rc = SQLITE_BUSY; |
| 65251 | }else{ |
| 65252 | u.aq.nName = sqlite3Strlen30(u.aq.zName); |
| 65253 | |
| 65254 | /* This call is Ok even if this savepoint is actually a transaction |
| 65255 | ** savepoint (and therefore should not prompt xSavepoint()) callbacks. |
| 65256 | ** If this is a transaction savepoint being opened, it is guaranteed |
| 65257 | ** that the db->aVTrans[] array is empty. */ |
| 65258 | assert( db->autoCommit==0 || db->nVTrans==0 ); |
| 65259 | rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); |
| 65260 | if( rc!=SQLITE_OK ) goto abort_due_to_error; |
| 65261 | |
| 65262 | /* Create a new savepoint structure. */ |
| 65263 | u.aq.pNew = sqlite3DbMallocRaw(db, sizeof(Savepoint)+u.aq.nName+1); |
| 65264 | if( u.aq.pNew ){ |
| 65265 | u.aq.pNew->zName = (char *)&u.aq.pNew[1]; |
| 65266 | memcpy(u.aq.pNew->zName, u.aq.zName, u.aq.nName+1); |
| @@ -64889,10 +65363,15 @@ | |
| 65363 | db->nSavepoint--; |
| 65364 | } |
| 65365 | }else{ |
| 65366 | db->nDeferredCons = u.aq.pSavepoint->nDeferredCons; |
| 65367 | } |
| 65368 | |
| 65369 | if( !isTransaction ){ |
| 65370 | rc = sqlite3VtabSavepoint(db, u.aq.p1, u.aq.iSavepoint); |
| 65371 | if( rc!=SQLITE_OK ) goto abort_due_to_error; |
| 65372 | } |
| 65373 | } |
| 65374 | } |
| 65375 | |
| 65376 | break; |
| 65377 | } |
| @@ -65028,11 +65507,15 @@ | |
| 65507 | if( p->iStatement==0 ){ |
| 65508 | assert( db->nStatement>=0 && db->nSavepoint>=0 ); |
| 65509 | db->nStatement++; |
| 65510 | p->iStatement = db->nSavepoint + db->nStatement; |
| 65511 | } |
| 65512 | |
| 65513 | rc = sqlite3VtabSavepoint(db, SAVEPOINT_BEGIN, p->iStatement); |
| 65514 | if( rc==SQLITE_OK ){ |
| 65515 | rc = sqlite3BtreeBeginStmt(u.as.pBt, p->iStatement); |
| 65516 | } |
| 65517 | |
| 65518 | /* Store the current value of the database handles deferred constraint |
| 65519 | ** counter. If the statement transaction needs to be rolled back, |
| 65520 | ** the value of this counter needs to be restored too. */ |
| 65521 | p->nStmtDefCons = db->nDeferredCons; |
| @@ -65349,11 +65832,11 @@ | |
| 65832 | |
| 65833 | assert( pOp->p1>=0 ); |
| 65834 | u.ax.pCx = allocateCursor(p, pOp->p1, pOp->p2, -1, 1); |
| 65835 | if( u.ax.pCx==0 ) goto no_mem; |
| 65836 | u.ax.pCx->nullRow = 1; |
| 65837 | rc = sqlite3BtreeOpen(db->pVfs, 0, db, &u.ax.pCx->pBt, |
| 65838 | BTREE_OMIT_JOURNAL | BTREE_SINGLE | pOp->p5, vfsFlags); |
| 65839 | if( rc==SQLITE_OK ){ |
| 65840 | rc = sqlite3BtreeBeginTrans(u.ax.pCx->pBt, 1); |
| 65841 | } |
| 65842 | if( rc==SQLITE_OK ){ |
| @@ -66023,11 +66506,11 @@ | |
| 66506 | ** engine starts picking positive candidate ROWIDs at random until |
| 66507 | ** it finds one that is not previously used. */ |
| 66508 | assert( pOp->p3==0 ); /* We cannot be in random rowid mode if this is |
| 66509 | ** an AUTOINCREMENT table. */ |
| 66510 | /* on the first attempt, simply do one more than previous */ |
| 66511 | u.be.v = lastRowid; |
| 66512 | u.be.v &= (MAX_ROWID>>1); /* ensure doesn't go negative */ |
| 66513 | u.be.v++; /* ensure non-zero */ |
| 66514 | u.be.cnt = 0; |
| 66515 | while( ((rc = sqlite3BtreeMovetoUnpacked(u.be.pC->pCursor, 0, (u64)u.be.v, |
| 66516 | 0, &u.be.res))==SQLITE_OK) |
| @@ -66135,11 +66618,11 @@ | |
| 66618 | assert( pOp->opcode==OP_InsertInt ); |
| 66619 | u.bf.iKey = pOp->p3; |
| 66620 | } |
| 66621 | |
| 66622 | if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
| 66623 | if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = lastRowid = u.bf.iKey; |
| 66624 | if( u.bf.pData->flags & MEM_Null ){ |
| 66625 | u.bf.pData->z = 0; |
| 66626 | u.bf.pData->n = 0; |
| 66627 | }else{ |
| 66628 | assert( u.bf.pData->flags & (MEM_Blob|MEM_Str) ); |
| @@ -67261,11 +67744,11 @@ | |
| 67744 | assert( pc==u.by.pFrame->pc ); |
| 67745 | } |
| 67746 | |
| 67747 | p->nFrame++; |
| 67748 | u.by.pFrame->pParent = p->pFrame; |
| 67749 | u.by.pFrame->lastRowid = lastRowid; |
| 67750 | u.by.pFrame->nChange = p->nChange; |
| 67751 | p->nChange = 0; |
| 67752 | p->pFrame = u.by.pFrame; |
| 67753 | p->aMem = aMem = &VdbeFrameMem(u.by.pFrame)[-1]; |
| 67754 | p->nMem = u.by.pFrame->nChildMem; |
| @@ -68072,31 +68555,45 @@ | |
| 68555 | sqlite_int64 rowid; |
| 68556 | Mem **apArg; |
| 68557 | Mem *pX; |
| 68558 | #endif /* local variables moved into u.cm */ |
| 68559 | |
| 68560 | assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback |
| 68561 | || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace |
| 68562 | ); |
| 68563 | u.cm.pVtab = pOp->p4.pVtab->pVtab; |
| 68564 | u.cm.pModule = (sqlite3_module *)u.cm.pVtab->pModule; |
| 68565 | u.cm.nArg = pOp->p2; |
| 68566 | assert( pOp->p4type==P4_VTAB ); |
| 68567 | if( ALWAYS(u.cm.pModule->xUpdate) ){ |
| 68568 | u8 vtabOnConflict = db->vtabOnConflict; |
| 68569 | u.cm.apArg = p->apArg; |
| 68570 | u.cm.pX = &aMem[pOp->p3]; |
| 68571 | for(u.cm.i=0; u.cm.i<u.cm.nArg; u.cm.i++){ |
| 68572 | assert( memIsValid(u.cm.pX) ); |
| 68573 | memAboutToChange(p, u.cm.pX); |
| 68574 | sqlite3VdbeMemStoreType(u.cm.pX); |
| 68575 | u.cm.apArg[u.cm.i] = u.cm.pX; |
| 68576 | u.cm.pX++; |
| 68577 | } |
| 68578 | db->vtabOnConflict = pOp->p5; |
| 68579 | rc = u.cm.pModule->xUpdate(u.cm.pVtab, u.cm.nArg, u.cm.apArg, &u.cm.rowid); |
| 68580 | db->vtabOnConflict = vtabOnConflict; |
| 68581 | importVtabErrMsg(p, u.cm.pVtab); |
| 68582 | if( rc==SQLITE_OK && pOp->p1 ){ |
| 68583 | assert( u.cm.nArg>1 && u.cm.apArg[0] && (u.cm.apArg[0]->flags&MEM_Null) ); |
| 68584 | db->lastRowid = lastRowid = u.cm.rowid; |
| 68585 | } |
| 68586 | if( rc==SQLITE_CONSTRAINT && pOp->p4.pVtab->bConstraint ){ |
| 68587 | if( pOp->p5==OE_Ignore ){ |
| 68588 | rc = SQLITE_OK; |
| 68589 | }else{ |
| 68590 | p->errorAction = ((pOp->p5==OE_Replace) ? OE_Abort : pOp->p5); |
| 68591 | } |
| 68592 | }else{ |
| 68593 | p->nChange++; |
| 68594 | } |
| 68595 | } |
| 68596 | break; |
| 68597 | } |
| 68598 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 68599 | |
| @@ -68242,10 +68739,11 @@ | |
| 68739 | |
| 68740 | /* This is the only way out of this procedure. We have to |
| 68741 | ** release the mutexes on btrees that were acquired at the |
| 68742 | ** top. */ |
| 68743 | vdbe_return: |
| 68744 | db->lastRowid = lastRowid; |
| 68745 | sqlite3VdbeLeave(p); |
| 68746 | return rc; |
| 68747 | |
| 68748 | /* Jump to here if a string or blob larger than SQLITE_MAX_LENGTH |
| 68749 | ** is encountered. |
| @@ -75970,12 +76468,16 @@ | |
| 76468 | int i; |
| 76469 | int rc = 0; |
| 76470 | sqlite3 *db = sqlite3_context_db_handle(context); |
| 76471 | const char *zName; |
| 76472 | const char *zFile; |
| 76473 | char *zPath = 0; |
| 76474 | char *zErr = 0; |
| 76475 | unsigned int flags; |
| 76476 | Db *aNew; |
| 76477 | char *zErrDyn = 0; |
| 76478 | sqlite3_vfs *pVfs; |
| 76479 | |
| 76480 | UNUSED_PARAMETER(NotUsed); |
| 76481 | |
| 76482 | zFile = (const char *)sqlite3_value_text(argv[0]); |
| 76483 | zName = (const char *)sqlite3_value_text(argv[1]); |
| @@ -76024,12 +76526,22 @@ | |
| 76526 | |
| 76527 | /* Open the database file. If the btree is successfully opened, use |
| 76528 | ** it to obtain the database schema. At this point the schema may |
| 76529 | ** or may not be initialised. |
| 76530 | */ |
| 76531 | flags = db->openFlags; |
| 76532 | rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); |
| 76533 | if( rc!=SQLITE_OK ){ |
| 76534 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 76535 | sqlite3_result_error(context, zErr, -1); |
| 76536 | sqlite3_free(zErr); |
| 76537 | return; |
| 76538 | } |
| 76539 | assert( pVfs ); |
| 76540 | flags |= SQLITE_OPEN_MAIN_DB; |
| 76541 | rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); |
| 76542 | sqlite3_free( zPath ); |
| 76543 | db->nDb++; |
| 76544 | if( rc==SQLITE_CONSTRAINT ){ |
| 76545 | rc = SQLITE_ERROR; |
| 76546 | zErrDyn = sqlite3MPrintf(db, "database is already attached"); |
| 76547 | }else if( rc==SQLITE_OK ){ |
| @@ -80139,11 +80651,11 @@ | |
| 80651 | SQLITE_OPEN_CREATE | |
| 80652 | SQLITE_OPEN_EXCLUSIVE | |
| 80653 | SQLITE_OPEN_DELETEONCLOSE | |
| 80654 | SQLITE_OPEN_TEMP_DB; |
| 80655 | |
| 80656 | rc = sqlite3BtreeOpen(db->pVfs, 0, db, &pBt, 0, flags); |
| 80657 | if( rc!=SQLITE_OK ){ |
| 80658 | sqlite3ErrorMsg(pParse, "unable to open a temporary database " |
| 80659 | "file for storing temporary tables"); |
| 80660 | pParse->rc = rc; |
| 80661 | return 1; |
| @@ -82329,10 +82841,25 @@ | |
| 82841 | UNUSED_PARAMETER2(NotUsed, NotUsed2); |
| 82842 | /* IMP: R-24470-31136 This function is an SQL wrapper around the |
| 82843 | ** sqlite3_sourceid() C interface. */ |
| 82844 | sqlite3_result_text(context, sqlite3_sourceid(), -1, SQLITE_STATIC); |
| 82845 | } |
| 82846 | |
| 82847 | /* |
| 82848 | ** Implementation of the sqlite_log() function. This is a wrapper around |
| 82849 | ** sqlite3_log(). The return value is NULL. The function exists purely for |
| 82850 | ** its side-effects. |
| 82851 | */ |
| 82852 | static void errlogFunc( |
| 82853 | sqlite3_context *context, |
| 82854 | int argc, |
| 82855 | sqlite3_value **argv |
| 82856 | ){ |
| 82857 | UNUSED_PARAMETER(argc); |
| 82858 | UNUSED_PARAMETER(context); |
| 82859 | sqlite3_log(sqlite3_value_int(argv[0]), "%s", sqlite3_value_text(argv[1])); |
| 82860 | } |
| 82861 | |
| 82862 | /* |
| 82863 | ** Implementation of the sqlite_compileoption_used() function. |
| 82864 | ** The result is an integer that identifies if the compiler option |
| 82865 | ** was used to build SQLite. |
| @@ -83097,10 +83624,11 @@ | |
| 83624 | FUNCTION(random, 0, 0, 0, randomFunc ), |
| 83625 | FUNCTION(randomblob, 1, 0, 0, randomBlob ), |
| 83626 | FUNCTION(nullif, 2, 0, 1, nullifFunc ), |
| 83627 | FUNCTION(sqlite_version, 0, 0, 0, versionFunc ), |
| 83628 | FUNCTION(sqlite_source_id, 0, 0, 0, sourceidFunc ), |
| 83629 | FUNCTION(sqlite_log, 2, 0, 0, errlogFunc ), |
| 83630 | #ifndef SQLITE_OMIT_COMPILEOPTION_DIAGS |
| 83631 | FUNCTION(sqlite_compileoption_used,1, 0, 0, compileoptionusedFunc ), |
| 83632 | FUNCTION(sqlite_compileoption_get, 1, 0, 0, compileoptiongetFunc ), |
| 83633 | #endif /* SQLITE_OMIT_COMPILEOPTION_DIAGS */ |
| 83634 | FUNCTION(quote, 1, 0, 0, quoteFunc ), |
| @@ -85309,10 +85837,11 @@ | |
| 85837 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 85838 | if( IsVirtual(pTab) ){ |
| 85839 | const char *pVTab = (const char *)sqlite3GetVTable(db, pTab); |
| 85840 | sqlite3VtabMakeWritable(pParse, pTab); |
| 85841 | sqlite3VdbeAddOp4(v, OP_VUpdate, 1, pTab->nCol+2, regIns, pVTab, P4_VTAB); |
| 85842 | sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); |
| 85843 | sqlite3MayAbort(pParse); |
| 85844 | }else |
| 85845 | #endif |
| 85846 | { |
| 85847 | int isReplace; /* Set to true if constraints may cause a replace */ |
| @@ -86073,10 +86602,22 @@ | |
| 86602 | } |
| 86603 | #ifndef SQLITE_OMIT_CHECK |
| 86604 | if( pDest->pCheck && sqlite3ExprCompare(pSrc->pCheck, pDest->pCheck) ){ |
| 86605 | return 0; /* Tables have different CHECK constraints. Ticket #2252 */ |
| 86606 | } |
| 86607 | #endif |
| 86608 | #ifndef SQLITE_OMIT_FOREIGN_KEY |
| 86609 | /* Disallow the transfer optimization if the destination table constains |
| 86610 | ** any foreign key constraints. This is more restrictive than necessary. |
| 86611 | ** But the main beneficiary of the transfer optimization is the VACUUM |
| 86612 | ** command, and the VACUUM command disables foreign key constraints. So |
| 86613 | ** the extra complication to make this rule less restrictive is probably |
| 86614 | ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] |
| 86615 | */ |
| 86616 | if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ |
| 86617 | return 0; |
| 86618 | } |
| 86619 | #endif |
| 86620 | |
| 86621 | /* If we get this far, it means either: |
| 86622 | ** |
| 86623 | ** * We can always do the transfer if the table contains an |
| @@ -87442,11 +87983,11 @@ | |
| 87983 | } |
| 87984 | |
| 87985 | /* |
| 87986 | ** Interpret the given string as a boolean value. |
| 87987 | */ |
| 87988 | SQLITE_PRIVATE u8 sqlite3GetBoolean(const char *z){ |
| 87989 | return getSafetyLevel(z)&1; |
| 87990 | } |
| 87991 | |
| 87992 | /* |
| 87993 | ** Interpret the given string as a locking mode value. |
| @@ -87612,11 +88153,11 @@ | |
| 88153 | /* Foreign key support may not be enabled or disabled while not |
| 88154 | ** in auto-commit mode. */ |
| 88155 | mask &= ~(SQLITE_ForeignKeys); |
| 88156 | } |
| 88157 | |
| 88158 | if( sqlite3GetBoolean(zRight) ){ |
| 88159 | db->flags |= mask; |
| 88160 | }else{ |
| 88161 | db->flags &= ~mask; |
| 88162 | } |
| 88163 | |
| @@ -87826,11 +88367,11 @@ | |
| 88367 | if( sqlite3StrICmp(zLeft,"secure_delete")==0 ){ |
| 88368 | Btree *pBt = pDb->pBt; |
| 88369 | int b = -1; |
| 88370 | assert( pBt!=0 ); |
| 88371 | if( zRight ){ |
| 88372 | b = sqlite3GetBoolean(zRight); |
| 88373 | } |
| 88374 | if( pId2->n==0 && b>=0 ){ |
| 88375 | int ii; |
| 88376 | for(ii=0; ii<db->nDb; ii++){ |
| 88377 | sqlite3BtreeSecureDelete(db->aDb[ii].pBt, b); |
| @@ -88426,11 +88967,11 @@ | |
| 88967 | #endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */ |
| 88968 | |
| 88969 | #ifndef NDEBUG |
| 88970 | if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ |
| 88971 | if( zRight ){ |
| 88972 | if( sqlite3GetBoolean(zRight) ){ |
| 88973 | sqlite3ParserTrace(stderr, "parser: "); |
| 88974 | }else{ |
| 88975 | sqlite3ParserTrace(0, 0); |
| 88976 | } |
| 88977 | } |
| @@ -88440,11 +88981,11 @@ | |
| 88981 | /* Reinstall the LIKE and GLOB functions. The variant of LIKE |
| 88982 | ** used will be case sensitive or not depending on the RHS. |
| 88983 | */ |
| 88984 | if( sqlite3StrICmp(zLeft, "case_sensitive_like")==0 ){ |
| 88985 | if( zRight ){ |
| 88986 | sqlite3RegisterLikeFunctions(db, sqlite3GetBoolean(zRight)); |
| 88987 | } |
| 88988 | }else |
| 88989 | |
| 88990 | #ifndef SQLITE_INTEGRITY_CHECK_ERROR_MAX |
| 88991 | # define SQLITE_INTEGRITY_CHECK_ERROR_MAX 100 |
| @@ -94017,16 +94558,18 @@ | |
| 94558 | ** does, then we can assume that it consumes less space on disk and |
| 94559 | ** will therefore be cheaper to scan to determine the query result. |
| 94560 | ** In this case set iRoot to the root page number of the index b-tree |
| 94561 | ** and pKeyInfo to the KeyInfo structure required to navigate the |
| 94562 | ** index. |
| 94563 | ** |
| 94564 | ** (2011-04-15) Do not do a full scan of an unordered index. |
| 94565 | ** |
| 94566 | ** In practice the KeyInfo structure will not be used. It is only |
| 94567 | ** passed to keep OP_OpenRead happy. |
| 94568 | */ |
| 94569 | for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ |
| 94570 | if( pIdx->bUnordered==0 && (!pBest || pIdx->nColumn<pBest->nColumn) ){ |
| 94571 | pBest = pIdx; |
| 94572 | } |
| 94573 | } |
| 94574 | if( pBest && pBest->nColumn<pTab->nCol ){ |
| 94575 | iRoot = pBest->tnum; |
| @@ -95579,11 +96122,12 @@ | |
| 96122 | SrcList *pSrc, /* The virtual table to be modified */ |
| 96123 | Table *pTab, /* The virtual table */ |
| 96124 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 96125 | Expr *pRowidExpr, /* Expression used to recompute the rowid */ |
| 96126 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 96127 | Expr *pWhere, /* WHERE clause of the UPDATE statement */ |
| 96128 | int onError /* ON CONFLICT strategy */ |
| 96129 | ); |
| 96130 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 96131 | |
| 96132 | /* |
| 96133 | ** The most recently coded instruction was an OP_Column to retrieve the |
| @@ -95823,11 +96367,11 @@ | |
| 96367 | |
| 96368 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 96369 | /* Virtual tables must be handled separately */ |
| 96370 | if( IsVirtual(pTab) ){ |
| 96371 | updateVirtualTable(pParse, pTabList, pTab, pChanges, pRowidExpr, aXRef, |
| 96372 | pWhere, onError); |
| 96373 | pWhere = 0; |
| 96374 | pTabList = 0; |
| 96375 | goto update_cleanup; |
| 96376 | } |
| 96377 | #endif |
| @@ -96153,11 +96697,12 @@ | |
| 96697 | SrcList *pSrc, /* The virtual table to be modified */ |
| 96698 | Table *pTab, /* The virtual table */ |
| 96699 | ExprList *pChanges, /* The columns to change in the UPDATE statement */ |
| 96700 | Expr *pRowid, /* Expression used to recompute the rowid */ |
| 96701 | int *aXRef, /* Mapping from columns of pTab to entries in pChanges */ |
| 96702 | Expr *pWhere, /* WHERE clause of the UPDATE statement */ |
| 96703 | int onError /* ON CONFLICT strategy */ |
| 96704 | ){ |
| 96705 | Vdbe *v = pParse->pVdbe; /* Virtual machine under construction */ |
| 96706 | ExprList *pEList = 0; /* The result set of the SELECT statement */ |
| 96707 | Select *pSelect = 0; /* The SELECT statement */ |
| 96708 | Expr *pExpr; /* Temporary expression */ |
| @@ -96210,10 +96755,11 @@ | |
| 96755 | for(i=0; i<pTab->nCol; i++){ |
| 96756 | sqlite3VdbeAddOp3(v, OP_Column, ephemTab, i+1+(pRowid!=0), iReg+2+i); |
| 96757 | } |
| 96758 | sqlite3VtabMakeWritable(pParse, pTab); |
| 96759 | sqlite3VdbeAddOp4(v, OP_VUpdate, 0, pTab->nCol+2, iReg, pVTab, P4_VTAB); |
| 96760 | sqlite3VdbeChangeP5(v, onError==OE_Default ? OE_Abort : onError); |
| 96761 | sqlite3MayAbort(pParse); |
| 96762 | sqlite3VdbeAddOp2(v, OP_Next, ephemTab, addr+1); |
| 96763 | sqlite3VdbeJumpHere(v, addr); |
| 96764 | sqlite3VdbeAddOp2(v, OP_Close, ephemTab, 0); |
| 96765 | |
| @@ -96583,10 +97129,22 @@ | |
| 97129 | ************************************************************************* |
| 97130 | ** This file contains code used to help implement virtual tables. |
| 97131 | */ |
| 97132 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 97133 | |
| 97134 | /* |
| 97135 | ** Before a virtual table xCreate() or xConnect() method is invoked, the |
| 97136 | ** sqlite3.pVtabCtx member variable is set to point to an instance of |
| 97137 | ** this struct allocated on the stack. It is used by the implementation of |
| 97138 | ** the sqlite3_declare_vtab() and sqlite3_vtab_config() APIs, both of which |
| 97139 | ** are invoked only from within xCreate and xConnect methods. |
| 97140 | */ |
| 97141 | struct VtabCtx { |
| 97142 | Table *pTab; |
| 97143 | VTable *pVTable; |
| 97144 | }; |
| 97145 | |
| 97146 | /* |
| 97147 | ** The actual function that does the work of creating a new module. |
| 97148 | ** This function implements the sqlite3_create_module() and |
| 97149 | ** sqlite3_create_module_v2() interfaces. |
| 97150 | */ |
| @@ -96611,17 +97169,17 @@ | |
| 97169 | pMod->pModule = pModule; |
| 97170 | pMod->pAux = pAux; |
| 97171 | pMod->xDestroy = xDestroy; |
| 97172 | pDel = (Module *)sqlite3HashInsert(&db->aModule, zCopy, nName, (void*)pMod); |
| 97173 | if( pDel && pDel->xDestroy ){ |
| 97174 | sqlite3ResetInternalSchema(db, -1); |
| 97175 | pDel->xDestroy(pDel->pAux); |
| 97176 | } |
| 97177 | sqlite3DbFree(db, pDel); |
| 97178 | if( pDel==pMod ){ |
| 97179 | db->mallocFailed = 1; |
| 97180 | } |
| 97181 | }else if( xDestroy ){ |
| 97182 | xDestroy(pAux); |
| 97183 | } |
| 97184 | rc = sqlite3ApiExit(db, SQLITE_OK); |
| 97185 | sqlite3_mutex_leave(db->mutex); |
| @@ -97003,10 +97561,11 @@ | |
| 97561 | Table *pTab, |
| 97562 | Module *pMod, |
| 97563 | int (*xConstruct)(sqlite3*,void*,int,const char*const*,sqlite3_vtab**,char**), |
| 97564 | char **pzErr |
| 97565 | ){ |
| 97566 | VtabCtx sCtx; |
| 97567 | VTable *pVTable; |
| 97568 | int rc; |
| 97569 | const char *const*azArg = (const char *const*)pTab->azModuleArg; |
| 97570 | int nArg = pTab->nModuleArg; |
| 97571 | char *zErr = 0; |
| @@ -97022,16 +97581,18 @@ | |
| 97581 | return SQLITE_NOMEM; |
| 97582 | } |
| 97583 | pVTable->db = db; |
| 97584 | pVTable->pMod = pMod; |
| 97585 | |
| 97586 | /* Invoke the virtual table constructor */ |
| 97587 | assert( &db->pVtabCtx ); |
| 97588 | assert( xConstruct ); |
| 97589 | sCtx.pTab = pTab; |
| 97590 | sCtx.pVTable = pVTable; |
| 97591 | db->pVtabCtx = &sCtx; |
| 97592 | rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr); |
| 97593 | db->pVtabCtx = 0; |
| 97594 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 97595 | |
| 97596 | if( SQLITE_OK!=rc ){ |
| 97597 | if( zErr==0 ){ |
| 97598 | *pzErr = sqlite3MPrintf(db, "vtable constructor failed: %s", zModuleName); |
| @@ -97043,11 +97604,11 @@ | |
| 97604 | }else if( ALWAYS(pVTable->pVtab) ){ |
| 97605 | /* Justification of ALWAYS(): A correct vtab constructor must allocate |
| 97606 | ** the sqlite3_vtab object if successful. */ |
| 97607 | pVTable->pVtab->pModule = pMod->pModule; |
| 97608 | pVTable->nRef = 1; |
| 97609 | if( sCtx.pTab ){ |
| 97610 | const char *zFormat = "vtable constructor did not declare schema: %s"; |
| 97611 | *pzErr = sqlite3MPrintf(db, zFormat, pTab->zName); |
| 97612 | sqlite3VtabUnlock(pVTable); |
| 97613 | rc = SQLITE_ERROR; |
| 97614 | }else{ |
| @@ -97091,11 +97652,10 @@ | |
| 97652 | } |
| 97653 | } |
| 97654 | } |
| 97655 | |
| 97656 | sqlite3DbFree(db, zModuleName); |
| 97657 | return rc; |
| 97658 | } |
| 97659 | |
| 97660 | /* |
| 97661 | ** This function is invoked by the parser to call the xConnect() method |
| @@ -97211,12 +97771,11 @@ | |
| 97771 | int rc = SQLITE_OK; |
| 97772 | Table *pTab; |
| 97773 | char *zErr = 0; |
| 97774 | |
| 97775 | sqlite3_mutex_enter(db->mutex); |
| 97776 | if( !db->pVtabCtx || !(pTab = db->pVtabCtx->pTab) ){ |
| 97777 | sqlite3Error(db, SQLITE_MISUSE, 0); |
| 97778 | sqlite3_mutex_leave(db->mutex); |
| 97779 | return SQLITE_MISUSE_BKPT; |
| 97780 | } |
| 97781 | assert( (pTab->tabFlags & TF_Virtual)!=0 ); |
| @@ -97239,11 +97798,11 @@ | |
| 97798 | pTab->aCol = pParse->pNewTable->aCol; |
| 97799 | pTab->nCol = pParse->pNewTable->nCol; |
| 97800 | pParse->pNewTable->nCol = 0; |
| 97801 | pParse->pNewTable->aCol = 0; |
| 97802 | } |
| 97803 | db->pVtabCtx->pTab = 0; |
| 97804 | }else{ |
| 97805 | sqlite3Error(db, SQLITE_ERROR, (zErr ? "%s" : 0), zErr); |
| 97806 | sqlite3DbFree(db, zErr); |
| 97807 | rc = SQLITE_ERROR; |
| 97808 | } |
| @@ -97391,11 +97950,10 @@ | |
| 97950 | pModule = pVTab->pVtab->pModule; |
| 97951 | |
| 97952 | if( pModule->xBegin ){ |
| 97953 | int i; |
| 97954 | |
| 97955 | /* If pVtab is already in the aVTrans array, return early */ |
| 97956 | for(i=0; i<db->nVTrans; i++){ |
| 97957 | if( db->aVTrans[i]==pVTab ){ |
| 97958 | return SQLITE_OK; |
| 97959 | } |
| @@ -97404,10 +97962,53 @@ | |
| 97962 | /* Invoke the xBegin method */ |
| 97963 | rc = pModule->xBegin(pVTab->pVtab); |
| 97964 | if( rc==SQLITE_OK ){ |
| 97965 | rc = addToVTrans(db, pVTab); |
| 97966 | } |
| 97967 | } |
| 97968 | return rc; |
| 97969 | } |
| 97970 | |
| 97971 | /* |
| 97972 | ** Invoke either the xSavepoint, xRollbackTo or xRelease method of all |
| 97973 | ** virtual tables that currently have an open transaction. Pass iSavepoint |
| 97974 | ** as the second argument to the virtual table method invoked. |
| 97975 | ** |
| 97976 | ** If op is SAVEPOINT_BEGIN, the xSavepoint method is invoked. If it is |
| 97977 | ** SAVEPOINT_ROLLBACK, the xRollbackTo method. Otherwise, if op is |
| 97978 | ** SAVEPOINT_RELEASE, then the xRelease method of each virtual table with |
| 97979 | ** an open transaction is invoked. |
| 97980 | ** |
| 97981 | ** If any virtual table method returns an error code other than SQLITE_OK, |
| 97982 | ** processing is abandoned and the error returned to the caller of this |
| 97983 | ** function immediately. If all calls to virtual table methods are successful, |
| 97984 | ** SQLITE_OK is returned. |
| 97985 | */ |
| 97986 | SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){ |
| 97987 | int rc = SQLITE_OK; |
| 97988 | |
| 97989 | assert( op==SAVEPOINT_RELEASE||op==SAVEPOINT_ROLLBACK||op==SAVEPOINT_BEGIN ); |
| 97990 | if( db->aVTrans ){ |
| 97991 | int i; |
| 97992 | for(i=0; rc==SQLITE_OK && i<db->nVTrans; i++){ |
| 97993 | const sqlite3_module *pMod = db->aVTrans[i]->pMod->pModule; |
| 97994 | if( pMod->iVersion>=2 ){ |
| 97995 | int (*xMethod)(sqlite3_vtab *, int); |
| 97996 | switch( op ){ |
| 97997 | case SAVEPOINT_BEGIN: |
| 97998 | xMethod = pMod->xSavepoint; |
| 97999 | break; |
| 98000 | case SAVEPOINT_ROLLBACK: |
| 98001 | xMethod = pMod->xRollbackTo; |
| 98002 | break; |
| 98003 | default: |
| 98004 | xMethod = pMod->xRelease; |
| 98005 | break; |
| 98006 | } |
| 98007 | if( xMethod ) rc = xMethod(db->aVTrans[i]->pVtab, iSavepoint); |
| 98008 | } |
| 98009 | } |
| 98010 | } |
| 98011 | return rc; |
| 98012 | } |
| 98013 | |
| 98014 | /* |
| @@ -97505,10 +98106,61 @@ | |
| 98106 | pToplevel->apVtabLock[pToplevel->nVtabLock++] = pTab; |
| 98107 | }else{ |
| 98108 | pToplevel->db->mallocFailed = 1; |
| 98109 | } |
| 98110 | } |
| 98111 | |
| 98112 | /* |
| 98113 | ** Return the ON CONFLICT resolution mode in effect for the virtual |
| 98114 | ** table update operation currently in progress. |
| 98115 | ** |
| 98116 | ** The results of this routine are undefined unless it is called from |
| 98117 | ** within an xUpdate method. |
| 98118 | */ |
| 98119 | SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *db){ |
| 98120 | static const unsigned char aMap[] = { |
| 98121 | SQLITE_ROLLBACK, SQLITE_ABORT, SQLITE_FAIL, SQLITE_IGNORE, SQLITE_REPLACE |
| 98122 | }; |
| 98123 | assert( OE_Rollback==1 && OE_Abort==2 && OE_Fail==3 ); |
| 98124 | assert( OE_Ignore==4 && OE_Replace==5 ); |
| 98125 | assert( db->vtabOnConflict>=1 && db->vtabOnConflict<=5 ); |
| 98126 | return (int)aMap[db->vtabOnConflict-1]; |
| 98127 | } |
| 98128 | |
| 98129 | /* |
| 98130 | ** Call from within the xCreate() or xConnect() methods to provide |
| 98131 | ** the SQLite core with additional information about the behavior |
| 98132 | ** of the virtual table being implemented. |
| 98133 | */ |
| 98134 | SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){ |
| 98135 | va_list ap; |
| 98136 | int rc = SQLITE_OK; |
| 98137 | |
| 98138 | sqlite3_mutex_enter(db->mutex); |
| 98139 | |
| 98140 | va_start(ap, op); |
| 98141 | switch( op ){ |
| 98142 | case SQLITE_VTAB_CONSTRAINT_SUPPORT: { |
| 98143 | VtabCtx *p = db->pVtabCtx; |
| 98144 | if( !p ){ |
| 98145 | rc = SQLITE_MISUSE_BKPT; |
| 98146 | }else{ |
| 98147 | assert( p->pTab==0 || (p->pTab->tabFlags & TF_Virtual)!=0 ); |
| 98148 | p->pVTable->bConstraint = (u8)va_arg(ap, int); |
| 98149 | } |
| 98150 | break; |
| 98151 | } |
| 98152 | default: |
| 98153 | rc = SQLITE_MISUSE_BKPT; |
| 98154 | break; |
| 98155 | } |
| 98156 | va_end(ap); |
| 98157 | |
| 98158 | if( rc!=SQLITE_OK ) sqlite3Error(db, rc, 0); |
| 98159 | sqlite3_mutex_leave(db->mutex); |
| 98160 | return rc; |
| 98161 | } |
| 98162 | |
| 98163 | #endif /* SQLITE_OMIT_VIRTUALTABLE */ |
| 98164 | |
| 98165 | /************** End of vtab.c ************************************************/ |
| 98166 | /************** Begin file where.c *******************************************/ |
| @@ -107527,10 +108179,15 @@ | |
| 108179 | typedef void(*LOGFUNC_t)(void*,int,const char*); |
| 108180 | sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t); |
| 108181 | sqlite3GlobalConfig.pLogArg = va_arg(ap, void*); |
| 108182 | break; |
| 108183 | } |
| 108184 | |
| 108185 | case SQLITE_CONFIG_URI: { |
| 108186 | sqlite3GlobalConfig.bOpenUri = va_arg(ap, int); |
| 108187 | break; |
| 108188 | } |
| 108189 | |
| 108190 | default: { |
| 108191 | rc = SQLITE_ERROR; |
| 108192 | break; |
| 108193 | } |
| @@ -108886,25 +109543,257 @@ | |
| 109543 | } |
| 109544 | db->aLimit[limitId] = newLimit; |
| 109545 | } |
| 109546 | return oldLimit; /* IMP: R-53341-35419 */ |
| 109547 | } |
| 109548 | |
| 109549 | /* |
| 109550 | ** This function is used to parse both URIs and non-URI filenames passed by the |
| 109551 | ** user to API functions sqlite3_open() or sqlite3_open_v2(), and for database |
| 109552 | ** URIs specified as part of ATTACH statements. |
| 109553 | ** |
| 109554 | ** The first argument to this function is the name of the VFS to use (or |
| 109555 | ** a NULL to signify the default VFS) if the URI does not contain a "vfs=xxx" |
| 109556 | ** query parameter. The second argument contains the URI (or non-URI filename) |
| 109557 | ** itself. When this function is called the *pFlags variable should contain |
| 109558 | ** the default flags to open the database handle with. The value stored in |
| 109559 | ** *pFlags may be updated before returning if the URI filename contains |
| 109560 | ** "cache=xxx" or "mode=xxx" query parameters. |
| 109561 | ** |
| 109562 | ** If successful, SQLITE_OK is returned. In this case *ppVfs is set to point to |
| 109563 | ** the VFS that should be used to open the database file. *pzFile is set to |
| 109564 | ** point to a buffer containing the name of the file to open. It is the |
| 109565 | ** responsibility of the caller to eventually call sqlite3_free() to release |
| 109566 | ** this buffer. |
| 109567 | ** |
| 109568 | ** If an error occurs, then an SQLite error code is returned and *pzErrMsg |
| 109569 | ** may be set to point to a buffer containing an English language error |
| 109570 | ** message. It is the responsibility of the caller to eventually release |
| 109571 | ** this buffer by calling sqlite3_free(). |
| 109572 | */ |
| 109573 | SQLITE_PRIVATE int sqlite3ParseUri( |
| 109574 | const char *zDefaultVfs, /* VFS to use if no "vfs=xxx" query option */ |
| 109575 | const char *zUri, /* Nul-terminated URI to parse */ |
| 109576 | unsigned int *pFlags, /* IN/OUT: SQLITE_OPEN_XXX flags */ |
| 109577 | sqlite3_vfs **ppVfs, /* OUT: VFS to use */ |
| 109578 | char **pzFile, /* OUT: Filename component of URI */ |
| 109579 | char **pzErrMsg /* OUT: Error message (if rc!=SQLITE_OK) */ |
| 109580 | ){ |
| 109581 | int rc = SQLITE_OK; |
| 109582 | unsigned int flags = *pFlags; |
| 109583 | const char *zVfs = zDefaultVfs; |
| 109584 | char *zFile; |
| 109585 | char c; |
| 109586 | int nUri = sqlite3Strlen30(zUri); |
| 109587 | |
| 109588 | assert( *pzErrMsg==0 ); |
| 109589 | |
| 109590 | if( ((flags & SQLITE_OPEN_URI) || sqlite3GlobalConfig.bOpenUri) |
| 109591 | && nUri>=5 && memcmp(zUri, "file:", 5)==0 |
| 109592 | ){ |
| 109593 | char *zOpt; |
| 109594 | int eState; /* Parser state when parsing URI */ |
| 109595 | int iIn; /* Input character index */ |
| 109596 | int iOut = 0; /* Output character index */ |
| 109597 | int nByte = nUri+2; /* Bytes of space to allocate */ |
| 109598 | |
| 109599 | /* Make sure the SQLITE_OPEN_URI flag is set to indicate to the VFS xOpen |
| 109600 | ** method that there may be extra parameters following the file-name. */ |
| 109601 | flags |= SQLITE_OPEN_URI; |
| 109602 | |
| 109603 | for(iIn=0; iIn<nUri; iIn++) nByte += (zUri[iIn]=='&'); |
| 109604 | zFile = sqlite3_malloc(nByte); |
| 109605 | if( !zFile ) return SQLITE_NOMEM; |
| 109606 | |
| 109607 | /* Discard the scheme and authority segments of the URI. */ |
| 109608 | if( zUri[5]=='/' && zUri[6]=='/' ){ |
| 109609 | iIn = 7; |
| 109610 | while( zUri[iIn] && zUri[iIn]!='/' ) iIn++; |
| 109611 | |
| 109612 | if( iIn!=7 && (iIn!=16 || memcmp("localhost", &zUri[7], 9)) ){ |
| 109613 | *pzErrMsg = sqlite3_mprintf("invalid uri authority: %.*s", |
| 109614 | iIn-7, &zUri[7]); |
| 109615 | rc = SQLITE_ERROR; |
| 109616 | goto parse_uri_out; |
| 109617 | } |
| 109618 | }else{ |
| 109619 | iIn = 5; |
| 109620 | } |
| 109621 | |
| 109622 | /* Copy the filename and any query parameters into the zFile buffer. |
| 109623 | ** Decode %HH escape codes along the way. |
| 109624 | ** |
| 109625 | ** Within this loop, variable eState may be set to 0, 1 or 2, depending |
| 109626 | ** on the parsing context. As follows: |
| 109627 | ** |
| 109628 | ** 0: Parsing file-name. |
| 109629 | ** 1: Parsing name section of a name=value query parameter. |
| 109630 | ** 2: Parsing value section of a name=value query parameter. |
| 109631 | */ |
| 109632 | eState = 0; |
| 109633 | while( (c = zUri[iIn])!=0 && c!='#' ){ |
| 109634 | iIn++; |
| 109635 | if( c=='%' |
| 109636 | && sqlite3Isxdigit(zUri[iIn]) |
| 109637 | && sqlite3Isxdigit(zUri[iIn+1]) |
| 109638 | ){ |
| 109639 | int octet = (sqlite3HexToInt(zUri[iIn++]) << 4); |
| 109640 | octet += sqlite3HexToInt(zUri[iIn++]); |
| 109641 | |
| 109642 | assert( octet>=0 && octet<256 ); |
| 109643 | if( octet==0 ){ |
| 109644 | /* This branch is taken when "%00" appears within the URI. In this |
| 109645 | ** case we ignore all text in the remainder of the path, name or |
| 109646 | ** value currently being parsed. So ignore the current character |
| 109647 | ** and skip to the next "?", "=" or "&", as appropriate. */ |
| 109648 | while( (c = zUri[iIn])!=0 && c!='#' |
| 109649 | && (eState!=0 || c!='?') |
| 109650 | && (eState!=1 || (c!='=' && c!='&')) |
| 109651 | && (eState!=2 || c!='&') |
| 109652 | ){ |
| 109653 | iIn++; |
| 109654 | } |
| 109655 | continue; |
| 109656 | } |
| 109657 | c = octet; |
| 109658 | }else if( eState==1 && (c=='&' || c=='=') ){ |
| 109659 | if( zFile[iOut-1]==0 ){ |
| 109660 | /* An empty option name. Ignore this option altogether. */ |
| 109661 | while( zUri[iIn] && zUri[iIn]!='#' && zUri[iIn-1]!='&' ) iIn++; |
| 109662 | continue; |
| 109663 | } |
| 109664 | if( c=='&' ){ |
| 109665 | zFile[iOut++] = '\0'; |
| 109666 | }else{ |
| 109667 | eState = 2; |
| 109668 | } |
| 109669 | c = 0; |
| 109670 | }else if( (eState==0 && c=='?') || (eState==2 && c=='&') ){ |
| 109671 | c = 0; |
| 109672 | eState = 1; |
| 109673 | } |
| 109674 | zFile[iOut++] = c; |
| 109675 | } |
| 109676 | if( eState==1 ) zFile[iOut++] = '\0'; |
| 109677 | zFile[iOut++] = '\0'; |
| 109678 | zFile[iOut++] = '\0'; |
| 109679 | |
| 109680 | /* Check if there were any options specified that should be interpreted |
| 109681 | ** here. Options that are interpreted here include "vfs" and those that |
| 109682 | ** correspond to flags that may be passed to the sqlite3_open_v2() |
| 109683 | ** method. */ |
| 109684 | zOpt = &zFile[sqlite3Strlen30(zFile)+1]; |
| 109685 | while( zOpt[0] ){ |
| 109686 | int nOpt = sqlite3Strlen30(zOpt); |
| 109687 | char *zVal = &zOpt[nOpt+1]; |
| 109688 | int nVal = sqlite3Strlen30(zVal); |
| 109689 | |
| 109690 | if( nOpt==3 && memcmp("vfs", zOpt, 3)==0 ){ |
| 109691 | zVfs = zVal; |
| 109692 | }else{ |
| 109693 | struct OpenMode { |
| 109694 | const char *z; |
| 109695 | int mode; |
| 109696 | } *aMode = 0; |
| 109697 | char *zModeType; |
| 109698 | int mask; |
| 109699 | int limit; |
| 109700 | |
| 109701 | if( nOpt==5 && memcmp("cache", zOpt, 5)==0 ){ |
| 109702 | static struct OpenMode aCacheMode[] = { |
| 109703 | { "shared", SQLITE_OPEN_SHAREDCACHE }, |
| 109704 | { "private", SQLITE_OPEN_PRIVATECACHE }, |
| 109705 | { 0, 0 } |
| 109706 | }; |
| 109707 | |
| 109708 | mask = SQLITE_OPEN_SHAREDCACHE|SQLITE_OPEN_PRIVATECACHE; |
| 109709 | aMode = aCacheMode; |
| 109710 | limit = mask; |
| 109711 | zModeType = "cache"; |
| 109712 | } |
| 109713 | if( nOpt==4 && memcmp("mode", zOpt, 4)==0 ){ |
| 109714 | static struct OpenMode aOpenMode[] = { |
| 109715 | { "ro", SQLITE_OPEN_READONLY }, |
| 109716 | { "rw", SQLITE_OPEN_READWRITE }, |
| 109717 | { "rwc", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE }, |
| 109718 | { 0, 0 } |
| 109719 | }; |
| 109720 | |
| 109721 | mask = SQLITE_OPEN_READONLY|SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE; |
| 109722 | aMode = aOpenMode; |
| 109723 | limit = mask & flags; |
| 109724 | zModeType = "access"; |
| 109725 | } |
| 109726 | |
| 109727 | if( aMode ){ |
| 109728 | int i; |
| 109729 | int mode = 0; |
| 109730 | for(i=0; aMode[i].z; i++){ |
| 109731 | const char *z = aMode[i].z; |
| 109732 | if( nVal==sqlite3Strlen30(z) && 0==memcmp(zVal, z, nVal) ){ |
| 109733 | mode = aMode[i].mode; |
| 109734 | break; |
| 109735 | } |
| 109736 | } |
| 109737 | if( mode==0 ){ |
| 109738 | *pzErrMsg = sqlite3_mprintf("no such %s mode: %s", zModeType, zVal); |
| 109739 | rc = SQLITE_ERROR; |
| 109740 | goto parse_uri_out; |
| 109741 | } |
| 109742 | if( mode>limit ){ |
| 109743 | *pzErrMsg = sqlite3_mprintf("%s mode not allowed: %s", |
| 109744 | zModeType, zVal); |
| 109745 | rc = SQLITE_PERM; |
| 109746 | goto parse_uri_out; |
| 109747 | } |
| 109748 | flags = (flags & ~mask) | mode; |
| 109749 | } |
| 109750 | } |
| 109751 | |
| 109752 | zOpt = &zVal[nVal+1]; |
| 109753 | } |
| 109754 | |
| 109755 | }else{ |
| 109756 | zFile = sqlite3_malloc(nUri+2); |
| 109757 | if( !zFile ) return SQLITE_NOMEM; |
| 109758 | memcpy(zFile, zUri, nUri); |
| 109759 | zFile[nUri] = '\0'; |
| 109760 | zFile[nUri+1] = '\0'; |
| 109761 | } |
| 109762 | |
| 109763 | *ppVfs = sqlite3_vfs_find(zVfs); |
| 109764 | if( *ppVfs==0 ){ |
| 109765 | *pzErrMsg = sqlite3_mprintf("no such vfs: %s", zVfs); |
| 109766 | rc = SQLITE_ERROR; |
| 109767 | } |
| 109768 | parse_uri_out: |
| 109769 | if( rc!=SQLITE_OK ){ |
| 109770 | sqlite3_free(zFile); |
| 109771 | zFile = 0; |
| 109772 | } |
| 109773 | *pFlags = flags; |
| 109774 | *pzFile = zFile; |
| 109775 | return rc; |
| 109776 | } |
| 109777 | |
| 109778 | |
| 109779 | /* |
| 109780 | ** This routine does the work of opening a database on behalf of |
| 109781 | ** sqlite3_open() and sqlite3_open16(). The database filename "zFilename" |
| 109782 | ** is UTF-8 encoded. |
| 109783 | */ |
| 109784 | static int openDatabase( |
| 109785 | const char *zFilename, /* Database filename UTF-8 encoded */ |
| 109786 | sqlite3 **ppDb, /* OUT: Returned database handle */ |
| 109787 | unsigned int flags, /* Operational flags */ |
| 109788 | const char *zVfs /* Name of the VFS to use */ |
| 109789 | ){ |
| 109790 | sqlite3 *db; /* Store allocated handle here */ |
| 109791 | int rc; /* Return code */ |
| 109792 | int isThreadsafe; /* True for threadsafe connections */ |
| 109793 | char *zOpen = 0; /* Filename argument to pass to BtreeOpen() */ |
| 109794 | char *zErrMsg = 0; /* Error message from sqlite3ParseUri() */ |
| 109795 | |
| 109796 | *ppDb = 0; |
| 109797 | #ifndef SQLITE_OMIT_AUTOINIT |
| 109798 | rc = sqlite3_initialize(); |
| 109799 | if( rc ) return rc; |
| @@ -108924,11 +109813,11 @@ | |
| 109813 | assert( SQLITE_OPEN_READWRITE == 0x02 ); |
| 109814 | assert( SQLITE_OPEN_CREATE == 0x04 ); |
| 109815 | testcase( (1<<(flags&7))==0x02 ); /* READONLY */ |
| 109816 | testcase( (1<<(flags&7))==0x04 ); /* READWRITE */ |
| 109817 | testcase( (1<<(flags&7))==0x40 ); /* READWRITE | CREATE */ |
| 109818 | if( ((1<<(flags&7)) & 0x46)==0 ) return SQLITE_MISUSE_BKPT; |
| 109819 | |
| 109820 | if( sqlite3GlobalConfig.bCoreMutex==0 ){ |
| 109821 | isThreadsafe = 0; |
| 109822 | }else if( flags & SQLITE_OPEN_NOMUTEX ){ |
| 109823 | isThreadsafe = 0; |
| @@ -109005,17 +109894,10 @@ | |
| 109894 | sqlite3HashInit(&db->aCollSeq); |
| 109895 | #ifndef SQLITE_OMIT_VIRTUALTABLE |
| 109896 | sqlite3HashInit(&db->aModule); |
| 109897 | #endif |
| 109898 | |
| 109899 | /* Add the default collation sequence BINARY. BINARY works for both UTF-8 |
| 109900 | ** and UTF-16, so add a version for each to avoid any unnecessary |
| 109901 | ** conversions. The only error that can occur here is a malloc() failure. |
| 109902 | */ |
| 109903 | createCollation(db, "BINARY", SQLITE_UTF8, SQLITE_COLL_BINARY, 0, |
| @@ -109034,13 +109916,22 @@ | |
| 109916 | |
| 109917 | /* Also add a UTF-8 case-insensitive collation sequence. */ |
| 109918 | createCollation(db, "NOCASE", SQLITE_UTF8, SQLITE_COLL_NOCASE, 0, |
| 109919 | nocaseCollatingFunc, 0); |
| 109920 | |
| 109921 | /* Parse the filename/URI argument. */ |
| 109922 | db->openFlags = flags; |
| 109923 | rc = sqlite3ParseUri(zVfs, zFilename, &flags, &db->pVfs, &zOpen, &zErrMsg); |
| 109924 | if( rc!=SQLITE_OK ){ |
| 109925 | if( rc==SQLITE_NOMEM ) db->mallocFailed = 1; |
| 109926 | sqlite3Error(db, rc, zErrMsg ? "%s" : 0, zErrMsg); |
| 109927 | sqlite3_free(zErrMsg); |
| 109928 | goto opendb_out; |
| 109929 | } |
| 109930 | |
| 109931 | /* Open the backend database driver */ |
| 109932 | rc = sqlite3BtreeOpen(db->pVfs, zOpen, db, &db->aDb[0].pBt, 0, |
| 109933 | flags | SQLITE_OPEN_MAIN_DB); |
| 109934 | if( rc!=SQLITE_OK ){ |
| 109935 | if( rc==SQLITE_IOERR_NOMEM ){ |
| 109936 | rc = SQLITE_NOMEM; |
| 109937 | } |
| @@ -109129,10 +110020,11 @@ | |
| 110020 | sqlite3GlobalConfig.nLookaside); |
| 110021 | |
| 110022 | sqlite3_wal_autocheckpoint(db, SQLITE_DEFAULT_WAL_AUTOCHECKPOINT); |
| 110023 | |
| 110024 | opendb_out: |
| 110025 | sqlite3_free(zOpen); |
| 110026 | if( db ){ |
| 110027 | assert( db->mutex!=0 || isThreadsafe==0 || sqlite3GlobalConfig.bFullMutex==0 ); |
| 110028 | sqlite3_mutex_leave(db->mutex); |
| 110029 | } |
| 110030 | rc = sqlite3_errcode(db); |
| @@ -109160,11 +110052,11 @@ | |
| 110052 | const char *filename, /* Database filename (UTF-8) */ |
| 110053 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 110054 | int flags, /* Flags */ |
| 110055 | const char *zVfs /* Name of VFS module to use */ |
| 110056 | ){ |
| 110057 | return openDatabase(filename, ppDb, (unsigned int)flags, zVfs); |
| 110058 | } |
| 110059 | |
| 110060 | #ifndef SQLITE_OMIT_UTF16 |
| 110061 | /* |
| 110062 | ** Open a new database handle. |
| @@ -109770,10 +110662,32 @@ | |
| 110662 | } |
| 110663 | va_end(ap); |
| 110664 | #endif /* SQLITE_OMIT_BUILTIN_TEST */ |
| 110665 | return rc; |
| 110666 | } |
| 110667 | |
| 110668 | /* |
| 110669 | ** This is a utility routine, useful to VFS implementations, that checks |
| 110670 | ** to see if a database file was a URI that contained a specific query |
| 110671 | ** parameter, and if so obtains the value of the query parameter. |
| 110672 | ** |
| 110673 | ** The zFilename argument is the filename pointer passed into the xOpen() |
| 110674 | ** method of a VFS implementation. The zParam argument is the name of the |
| 110675 | ** query parameter we seek. This routine returns the value of the zParam |
| 110676 | ** parameter if it exists. If the parameter does not exist, this routine |
| 110677 | ** returns a NULL pointer. |
| 110678 | */ |
| 110679 | SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam){ |
| 110680 | zFilename += sqlite3Strlen30(zFilename) + 1; |
| 110681 | while( zFilename[0] ){ |
| 110682 | int x = strcmp(zFilename, zParam); |
| 110683 | zFilename += sqlite3Strlen30(zFilename) + 1; |
| 110684 | if( x==0 ) return zFilename; |
| 110685 | zFilename += sqlite3Strlen30(zFilename) + 1; |
| 110686 | } |
| 110687 | return 0; |
| 110688 | } |
| 110689 | |
| 110690 | /************** End of main.c ************************************************/ |
| 110691 | /************** Begin file notify.c ******************************************/ |
| 110692 | /* |
| 110693 | ** 2009 March 3 |
| @@ -110851,10 +111765,11 @@ | |
| 111765 | Fts3DeferredToken *pDeferred; /* Deferred search tokens, if any */ |
| 111766 | sqlite3_int64 iPrevId; /* Previous id read from aDoclist */ |
| 111767 | char *pNextId; /* Pointer into the body of aDoclist */ |
| 111768 | char *aDoclist; /* List of docids for full-text queries */ |
| 111769 | int nDoclist; /* Size of buffer at aDoclist */ |
| 111770 | int desc; /* True to sort in descending order */ |
| 111771 | int eEvalmode; /* An FTS3_EVAL_XX constant */ |
| 111772 | int nRowAvg; /* Average size of database rows, in pages */ |
| 111773 | |
| 111774 | int isMatchinfoNeeded; /* True when aMatchinfo[] needs filling in */ |
| 111775 | u32 *aMatchinfo; /* Information about most recent match */ |
| @@ -111033,11 +111948,11 @@ | |
| 111948 | SQLITE_PRIVATE int sqlite3Fts3GetVarint(const char *, sqlite_int64 *); |
| 111949 | SQLITE_PRIVATE int sqlite3Fts3GetVarint32(const char *, int *); |
| 111950 | SQLITE_PRIVATE int sqlite3Fts3VarintLen(sqlite3_uint64); |
| 111951 | SQLITE_PRIVATE void sqlite3Fts3Dequote(char *); |
| 111952 | |
| 111953 | SQLITE_PRIVATE char *sqlite3Fts3FindPositions(Fts3Cursor *, Fts3Expr *, sqlite3_int64, int); |
| 111954 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadDoclist(Fts3Cursor *, Fts3Expr *); |
| 111955 | SQLITE_PRIVATE int sqlite3Fts3ExprLoadFtDoclist(Fts3Cursor *, Fts3Expr *, char **, int *); |
| 111956 | SQLITE_PRIVATE int sqlite3Fts3ExprNearTrim(Fts3Expr *, Fts3Expr *, int); |
| 111957 | |
| 111958 | /* fts3_tokenizer.c */ |
| @@ -111060,10 +111975,11 @@ | |
| 111975 | char **, int, int, const char *, int, Fts3Expr ** |
| 111976 | ); |
| 111977 | SQLITE_PRIVATE void sqlite3Fts3ExprFree(Fts3Expr *); |
| 111978 | #ifdef SQLITE_TEST |
| 111979 | SQLITE_PRIVATE int sqlite3Fts3ExprInitTestInterface(sqlite3 *db); |
| 111980 | SQLITE_PRIVATE int sqlite3Fts3InitTerm(sqlite3 *db); |
| 111981 | #endif |
| 111982 | |
| 111983 | /* fts3_aux.c */ |
| 111984 | SQLITE_PRIVATE int sqlite3Fts3InitAux(sqlite3 *db); |
| 111985 | |
| @@ -111180,10 +112096,38 @@ | |
| 112096 | static void fts3GetDeltaVarint(char **pp, sqlite3_int64 *pVal){ |
| 112097 | sqlite3_int64 iVal; |
| 112098 | *pp += sqlite3Fts3GetVarint(*pp, &iVal); |
| 112099 | *pVal += iVal; |
| 112100 | } |
| 112101 | |
| 112102 | /* |
| 112103 | ** When this function is called, *pp points to the first byte following a |
| 112104 | ** varint that is part of a doclist (or position-list, or any other list |
| 112105 | ** of varints). This function moves *pp to point to the start of that varint, |
| 112106 | ** and decrements the value stored in *pVal by the varint value. |
| 112107 | ** |
| 112108 | ** Argument pStart points to the first byte of the doclist that the |
| 112109 | ** varint is part of. |
| 112110 | */ |
| 112111 | static void fts3GetReverseDeltaVarint( |
| 112112 | char **pp, |
| 112113 | char *pStart, |
| 112114 | sqlite3_int64 *pVal |
| 112115 | ){ |
| 112116 | sqlite3_int64 iVal; |
| 112117 | char *p = *pp; |
| 112118 | |
| 112119 | /* Pointer p now points at the first byte past the varint we are |
| 112120 | ** interested in. So, unless the doclist is corrupt, the 0x80 bit is |
| 112121 | ** clear on character p[-1]. */ |
| 112122 | for(p = (*pp)-2; p>=pStart && *p&0x80; p--); |
| 112123 | p++; |
| 112124 | *pp = p; |
| 112125 | |
| 112126 | sqlite3Fts3GetVarint(p, &iVal); |
| 112127 | *pVal -= iVal; |
| 112128 | } |
| 112129 | |
| 112130 | /* |
| 112131 | ** As long as *pp has not reached its end (pEnd), then do the same |
| 112132 | ** as fts3GetDeltaVarint(): read a single varint and add it to *pVal. |
| 112133 | ** But if we have reached the end of the varint, just set *pp=0 and |
| @@ -111285,10 +112229,12 @@ | |
| 112229 | if( *pRc==SQLITE_OK ){ |
| 112230 | int i; /* Iterator variable */ |
| 112231 | int rc; /* Return code */ |
| 112232 | char *zSql; /* SQL statement passed to declare_vtab() */ |
| 112233 | char *zCols; /* List of user defined columns */ |
| 112234 | |
| 112235 | sqlite3_vtab_config(p->db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); |
| 112236 | |
| 112237 | /* Create a list of user columns for the virtual table */ |
| 112238 | zCols = sqlite3_mprintf("%Q, ", p->azColumn[0]); |
| 112239 | for(i=1; zCols && i<p->nColumn; i++){ |
| 112240 | zCols = sqlite3_mprintf("%z%Q, ", zCols, p->azColumn[i]); |
| @@ -111854,10 +112800,26 @@ | |
| 112800 | |
| 112801 | if( iCons>=0 ){ |
| 112802 | pInfo->aConstraintUsage[iCons].argvIndex = 1; |
| 112803 | pInfo->aConstraintUsage[iCons].omit = 1; |
| 112804 | } |
| 112805 | |
| 112806 | /* Regardless of the strategy selected, FTS can deliver rows in rowid (or |
| 112807 | ** docid) order. Both ascending and descending are possible. |
| 112808 | */ |
| 112809 | if( pInfo->nOrderBy==1 ){ |
| 112810 | struct sqlite3_index_orderby *pOrder = &pInfo->aOrderBy[0]; |
| 112811 | if( pOrder->iColumn<0 || pOrder->iColumn==p->nColumn+1 ){ |
| 112812 | if( pOrder->desc ){ |
| 112813 | pInfo->idxStr = "DESC"; |
| 112814 | }else{ |
| 112815 | pInfo->idxStr = "ASC"; |
| 112816 | } |
| 112817 | } |
| 112818 | pInfo->orderByConsumed = 1; |
| 112819 | } |
| 112820 | |
| 112821 | return SQLITE_OK; |
| 112822 | } |
| 112823 | |
| 112824 | /* |
| 112825 | ** Implementation of xOpen method. |
| @@ -111911,11 +112873,11 @@ | |
| 112873 | if( rc==SQLITE_OK ){ |
| 112874 | /* If no row was found and no error has occured, then the %_content |
| 112875 | ** table is missing a row that is present in the full-text index. |
| 112876 | ** The data structures are corrupt. |
| 112877 | */ |
| 112878 | rc = SQLITE_CORRUPT_VTAB; |
| 112879 | } |
| 112880 | pCsr->isEof = 1; |
| 112881 | if( pContext ){ |
| 112882 | sqlite3_result_error_code(pContext, rc); |
| 112883 | } |
| @@ -111971,11 +112933,11 @@ | |
| 112933 | ** nNode bytes of content (see sqlite3Fts3ReadBlock() for details). |
| 112934 | */ |
| 112935 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 112936 | zCsr += sqlite3Fts3GetVarint(zCsr, &iChild); |
| 112937 | if( zCsr>zEnd ){ |
| 112938 | return SQLITE_CORRUPT_VTAB; |
| 112939 | } |
| 112940 | |
| 112941 | while( zCsr<zEnd && (piFirst || piLast) ){ |
| 112942 | int cmp; /* memcmp() result */ |
| 112943 | int nSuffix; /* Size of term suffix */ |
| @@ -111989,11 +112951,11 @@ | |
| 112951 | } |
| 112952 | isFirstTerm = 0; |
| 112953 | zCsr += sqlite3Fts3GetVarint32(zCsr, &nSuffix); |
| 112954 | |
| 112955 | if( nPrefix<0 || nSuffix<0 || &zCsr[nSuffix]>zEnd ){ |
| 112956 | rc = SQLITE_CORRUPT_VTAB; |
| 112957 | goto finish_scan; |
| 112958 | } |
| 112959 | if( nPrefix+nSuffix>nAlloc ){ |
| 112960 | char *zNew; |
| 112961 | nAlloc = (nPrefix+nSuffix) * 2; |
| @@ -113758,16 +114720,24 @@ | |
| 114720 | rc = sqlite3_reset(pCsr->pStmt); |
| 114721 | break; |
| 114722 | } |
| 114723 | pCsr->iPrevId = sqlite3_column_int64(pCsr->pStmt, 0); |
| 114724 | }else{ |
| 114725 | if( pCsr->desc==0 ){ |
| 114726 | if( pCsr->pNextId>=&pCsr->aDoclist[pCsr->nDoclist] ){ |
| 114727 | pCsr->isEof = 1; |
| 114728 | break; |
| 114729 | } |
| 114730 | fts3GetDeltaVarint(&pCsr->pNextId, &pCsr->iPrevId); |
| 114731 | }else{ |
| 114732 | fts3GetReverseDeltaVarint(&pCsr->pNextId,pCsr->aDoclist,&pCsr->iPrevId); |
| 114733 | if( pCsr->pNextId<=pCsr->aDoclist ){ |
| 114734 | pCsr->isEof = 1; |
| 114735 | break; |
| 114736 | } |
| 114737 | } |
| 114738 | sqlite3_reset(pCsr->pStmt); |
| 114739 | pCsr->isRequireSeek = 1; |
| 114740 | pCsr->isMatchinfoNeeded = 1; |
| 114741 | } |
| 114742 | }while( SQLITE_OK==(rc = fts3EvalDeferred(pCsr, &res)) && res==0 ); |
| 114743 | |
| @@ -113796,12 +114766,12 @@ | |
| 114766 | const char *idxStr, /* Unused */ |
| 114767 | int nVal, /* Number of elements in apVal */ |
| 114768 | sqlite3_value **apVal /* Arguments for the indexing scheme */ |
| 114769 | ){ |
| 114770 | const char *azSql[] = { |
| 114771 | "SELECT %s FROM %Q.'%q_content' AS x WHERE docid = ?", /* non-full-scan */ |
| 114772 | "SELECT %s FROM %Q.'%q_content' AS x ORDER BY docid %s", /* full-scan */ |
| 114773 | }; |
| 114774 | int rc; /* Return code */ |
| 114775 | char *zSql; /* SQL statement used to access %_content */ |
| 114776 | Fts3Table *p = (Fts3Table *)pCursor->pVtab; |
| 114777 | Fts3Cursor *pCsr = (Fts3Cursor *)pCursor; |
| @@ -113853,11 +114823,13 @@ | |
| 114823 | ** statement loops through all rows of the %_content table. For a |
| 114824 | ** full-text query or docid lookup, the statement retrieves a single |
| 114825 | ** row by docid. |
| 114826 | */ |
| 114827 | zSql = (char *)azSql[idxNum==FTS3_FULLSCAN_SEARCH]; |
| 114828 | zSql = sqlite3_mprintf( |
| 114829 | zSql, p->zReadExprlist, p->zDb, p->zName, (idxStr ? idxStr : "ASC") |
| 114830 | ); |
| 114831 | if( !zSql ){ |
| 114832 | rc = SQLITE_NOMEM; |
| 114833 | }else{ |
| 114834 | rc = sqlite3_prepare_v2(p->db, zSql, -1, &pCsr->pStmt, 0); |
| 114835 | sqlite3_free(zSql); |
| @@ -113865,11 +114837,26 @@ | |
| 114837 | if( rc==SQLITE_OK && idxNum==FTS3_DOCID_SEARCH ){ |
| 114838 | rc = sqlite3_bind_value(pCsr->pStmt, 1, apVal[0]); |
| 114839 | } |
| 114840 | pCsr->eSearch = (i16)idxNum; |
| 114841 | |
| 114842 | assert( pCsr->desc==0 ); |
| 114843 | if( rc!=SQLITE_OK ) return rc; |
| 114844 | if( rc==SQLITE_OK && pCsr->nDoclist>0 && idxStr && idxStr[0]=='D' ){ |
| 114845 | sqlite3_int64 iDocid = 0; |
| 114846 | char *csr = pCsr->aDoclist; |
| 114847 | while( csr<&pCsr->aDoclist[pCsr->nDoclist] ){ |
| 114848 | fts3GetDeltaVarint(&csr, &iDocid); |
| 114849 | } |
| 114850 | pCsr->pNextId = csr; |
| 114851 | pCsr->iPrevId = iDocid; |
| 114852 | pCsr->desc = 1; |
| 114853 | pCsr->isRequireSeek = 1; |
| 114854 | pCsr->isMatchinfoNeeded = 1; |
| 114855 | pCsr->eEvalmode = FTS3_EVAL_NEXT; |
| 114856 | return SQLITE_OK; |
| 114857 | } |
| 114858 | return fts3NextMethod(pCursor); |
| 114859 | } |
| 114860 | |
| 114861 | /* |
| 114862 | ** This is the xEof method of the virtual table. SQLite calls this |
| @@ -114017,17 +115004,37 @@ | |
| 115004 | pCsr->eEvalmode = FTS3_EVAL_MATCHINFO; |
| 115005 | rc = fts3EvalExpr(pCsr, pExpr, paDoclist, pnDoclist, 1); |
| 115006 | pCsr->eEvalmode = FTS3_EVAL_NEXT; |
| 115007 | return rc; |
| 115008 | } |
| 115009 | |
| 115010 | |
| 115011 | /* |
| 115012 | ** When called, *ppPoslist must point to the byte immediately following the |
| 115013 | ** end of a position-list. i.e. ( (*ppPoslist)[-1]==POS_END ). This function |
| 115014 | ** moves *ppPoslist so that it instead points to the first byte of the |
| 115015 | ** same position list. |
| 115016 | */ |
| 115017 | static void fts3ReversePoslist(char *pStart, char **ppPoslist){ |
| 115018 | char *p = &(*ppPoslist)[-3]; |
| 115019 | char c = p[1]; |
| 115020 | while( p>pStart && (*p & 0x80) | c ){ |
| 115021 | c = *p--; |
| 115022 | } |
| 115023 | if( p>pStart ){ p = &p[2]; } |
| 115024 | while( *p++&0x80 ); |
| 115025 | *ppPoslist = p; |
| 115026 | } |
| 115027 | |
| 115028 | |
| 115029 | /* |
| 115030 | ** After ExprLoadDoclist() (see above) has been called, this function is |
| 115031 | ** used to iterate/search through the position lists that make up the doclist |
| 115032 | ** stored in pExpr->aDoclist. |
| 115033 | */ |
| 115034 | SQLITE_PRIVATE char *sqlite3Fts3FindPositions( |
| 115035 | Fts3Cursor *pCursor, /* Associate FTS3 cursor */ |
| 115036 | Fts3Expr *pExpr, /* Access this expressions doclist */ |
| 115037 | sqlite3_int64 iDocid, /* Docid associated with requested pos-list */ |
| 115038 | int iCol /* Column of requested pos-list */ |
| 115039 | ){ |
| 115040 | assert( pExpr->isLoaded ); |
| @@ -114034,23 +115041,39 @@ | |
| 115041 | if( pExpr->aDoclist ){ |
| 115042 | char *pEnd = &pExpr->aDoclist[pExpr->nDoclist]; |
| 115043 | char *pCsr; |
| 115044 | |
| 115045 | if( pExpr->pCurrent==0 ){ |
| 115046 | if( pCursor->desc==0 ){ |
| 115047 | pExpr->pCurrent = pExpr->aDoclist; |
| 115048 | pExpr->iCurrent = 0; |
| 115049 | fts3GetDeltaVarint(&pExpr->pCurrent, &pExpr->iCurrent); |
| 115050 | }else{ |
| 115051 | pCsr = pExpr->aDoclist; |
| 115052 | while( pCsr<pEnd ){ |
| 115053 | fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent); |
| 115054 | fts3PoslistCopy(0, &pCsr); |
| 115055 | } |
| 115056 | fts3ReversePoslist(pExpr->aDoclist, &pCsr); |
| 115057 | pExpr->pCurrent = pCsr; |
| 115058 | } |
| 115059 | } |
| 115060 | pCsr = pExpr->pCurrent; |
| 115061 | assert( pCsr ); |
| 115062 | |
| 115063 | while( (pCursor->desc==0 && pCsr<pEnd) |
| 115064 | || (pCursor->desc && pCsr>pExpr->aDoclist) |
| 115065 | ){ |
| 115066 | if( pCursor->desc==0 && pExpr->iCurrent<iDocid ){ |
| 115067 | fts3PoslistCopy(0, &pCsr); |
| 115068 | if( pCsr<pEnd ){ |
| 115069 | fts3GetDeltaVarint(&pCsr, &pExpr->iCurrent); |
| 115070 | } |
| 115071 | pExpr->pCurrent = pCsr; |
| 115072 | }else if( pCursor->desc && pExpr->iCurrent>iDocid ){ |
| 115073 | fts3GetReverseDeltaVarint(&pCsr, pExpr->aDoclist, &pExpr->iCurrent); |
| 115074 | fts3ReversePoslist(pExpr->aDoclist, &pCsr); |
| 115075 | pExpr->pCurrent = pCsr; |
| 115076 | }else{ |
| 115077 | if( pExpr->iCurrent==iDocid ){ |
| 115078 | int iThis = 0; |
| 115079 | if( iCol<0 ){ |
| @@ -114303,13 +115326,24 @@ | |
| 115326 | "ALTER TABLE %Q.'%q_segdir' RENAME TO '%q_segdir';", |
| 115327 | p->zDb, p->zName, zName |
| 115328 | ); |
| 115329 | return rc; |
| 115330 | } |
| 115331 | |
| 115332 | static int fts3SavepointMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 115333 | return sqlite3Fts3PendingTermsFlush((Fts3Table *)pVtab); |
| 115334 | } |
| 115335 | static int fts3ReleaseMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 115336 | return SQLITE_OK; |
| 115337 | } |
| 115338 | static int fts3RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){ |
| 115339 | sqlite3Fts3PendingTermsClear((Fts3Table *)pVtab); |
| 115340 | return SQLITE_OK; |
| 115341 | } |
| 115342 | |
| 115343 | static const sqlite3_module fts3Module = { |
| 115344 | /* iVersion */ 2, |
| 115345 | /* xCreate */ fts3CreateMethod, |
| 115346 | /* xConnect */ fts3ConnectMethod, |
| 115347 | /* xBestIndex */ fts3BestIndexMethod, |
| 115348 | /* xDisconnect */ fts3DisconnectMethod, |
| 115349 | /* xDestroy */ fts3DestroyMethod, |
| @@ -114325,10 +115359,13 @@ | |
| 115359 | /* xSync */ fts3SyncMethod, |
| 115360 | /* xCommit */ fts3CommitMethod, |
| 115361 | /* xRollback */ fts3RollbackMethod, |
| 115362 | /* xFindFunction */ fts3FindFunctionMethod, |
| 115363 | /* xRename */ fts3RenameMethod, |
| 115364 | /* xSavepoint */ fts3SavepointMethod, |
| 115365 | /* xRelease */ fts3ReleaseMethod, |
| 115366 | /* xRollbackTo */ fts3RollbackToMethod, |
| 115367 | }; |
| 115368 | |
| 115369 | /* |
| 115370 | ** This function is registered as the module destructor (called when an |
| 115371 | ** FTS3 enabled database connection is closed). It frees the memory |
| @@ -114370,10 +115407,15 @@ | |
| 115407 | |
| 115408 | #ifdef SQLITE_ENABLE_ICU |
| 115409 | const sqlite3_tokenizer_module *pIcu = 0; |
| 115410 | sqlite3Fts3IcuTokenizerModule(&pIcu); |
| 115411 | #endif |
| 115412 | |
| 115413 | #ifdef SQLITE_TEST |
| 115414 | rc = sqlite3Fts3InitTerm(db); |
| 115415 | if( rc!=SQLITE_OK ) return rc; |
| 115416 | #endif |
| 115417 | |
| 115418 | rc = sqlite3Fts3InitAux(db); |
| 115419 | if( rc!=SQLITE_OK ) return rc; |
| 115420 | |
| 115421 | sqlite3Fts3SimpleTokenizerModule(&pSimple); |
| @@ -117891,11 +118933,11 @@ | |
| 118933 | sqlite3_bind_int64(pStmt, 1, iDocid); |
| 118934 | } |
| 118935 | rc = sqlite3_step(pStmt); |
| 118936 | if( rc!=SQLITE_ROW || sqlite3_column_type(pStmt, 0)!=SQLITE_BLOB ){ |
| 118937 | rc = sqlite3_reset(pStmt); |
| 118938 | if( rc==SQLITE_OK ) rc = SQLITE_CORRUPT_VTAB; |
| 118939 | pStmt = 0; |
| 118940 | }else{ |
| 118941 | rc = SQLITE_OK; |
| 118942 | } |
| 118943 | } |
| @@ -118141,10 +119183,18 @@ | |
| 119183 | sqlite3_tokenizer_cursor *pCsr; |
| 119184 | int (*xNext)(sqlite3_tokenizer_cursor *pCursor, |
| 119185 | const char**,int*,int*,int*,int*); |
| 119186 | |
| 119187 | assert( pTokenizer && pModule ); |
| 119188 | |
| 119189 | /* If the user has inserted a NULL value, this function may be called with |
| 119190 | ** zText==0. In this case, add zero token entries to the hash table and |
| 119191 | ** return early. */ |
| 119192 | if( zText==0 ){ |
| 119193 | *pnWord = 0; |
| 119194 | return SQLITE_OK; |
| 119195 | } |
| 119196 | |
| 119197 | rc = pModule->xOpen(pTokenizer, zText, -1, &pCsr); |
| 119198 | if( rc!=SQLITE_OK ){ |
| 119199 | return rc; |
| 119200 | } |
| @@ -118232,15 +119282,13 @@ | |
| 119282 | */ |
| 119283 | static int fts3InsertTerms(Fts3Table *p, sqlite3_value **apVal, u32 *aSz){ |
| 119284 | int i; /* Iterator variable */ |
| 119285 | for(i=2; i<p->nColumn+2; i++){ |
| 119286 | const char *zText = (const char *)sqlite3_value_text(apVal[i]); |
| 119287 | int rc = fts3PendingTermsAdd(p, zText, i-2, &aSz[i-2]); |
| 119288 | if( rc!=SQLITE_OK ){ |
| 119289 | return rc; |
| 119290 | } |
| 119291 | aSz[p->nColumn] += sqlite3_value_bytes(apVal[i]); |
| 119292 | } |
| 119293 | return SQLITE_OK; |
| 119294 | } |
| @@ -118341,18 +119389,18 @@ | |
| 119389 | ** full-text index. |
| 119390 | */ |
| 119391 | static void fts3DeleteTerms( |
| 119392 | int *pRC, /* Result code */ |
| 119393 | Fts3Table *p, /* The FTS table to delete from */ |
| 119394 | sqlite3_value *pRowid, /* The docid to be deleted */ |
| 119395 | u32 *aSz /* Sizes of deleted document written here */ |
| 119396 | ){ |
| 119397 | int rc; |
| 119398 | sqlite3_stmt *pSelect; |
| 119399 | |
| 119400 | if( *pRC ) return; |
| 119401 | rc = fts3SqlStmt(p, SQL_SELECT_CONTENT_BY_ROWID, &pSelect, &pRowid); |
| 119402 | if( rc==SQLITE_OK ){ |
| 119403 | if( SQLITE_ROW==sqlite3_step(pSelect) ){ |
| 119404 | int i; |
| 119405 | for(i=1; i<=p->nColumn; i++){ |
| 119406 | const char *zText = (const char *)sqlite3_column_text(pSelect, i); |
| @@ -118566,11 +119614,11 @@ | |
| 119614 | pNext += sqlite3Fts3GetVarint32(pNext, &nPrefix); |
| 119615 | pNext += sqlite3Fts3GetVarint32(pNext, &nSuffix); |
| 119616 | if( nPrefix<0 || nSuffix<=0 |
| 119617 | || &pNext[nSuffix]>&pReader->aNode[pReader->nNode] |
| 119618 | ){ |
| 119619 | return SQLITE_CORRUPT_VTAB; |
| 119620 | } |
| 119621 | |
| 119622 | if( nPrefix+nSuffix>pReader->nTermAlloc ){ |
| 119623 | int nNew = (nPrefix+nSuffix)*2; |
| 119624 | char *zNew = sqlite3_realloc(pReader->zTerm, nNew); |
| @@ -118592,11 +119640,11 @@ | |
| 119640 | ** of these statements is untrue, then the data structure is corrupt. |
| 119641 | */ |
| 119642 | if( &pReader->aDoclist[pReader->nDoclist]>&pReader->aNode[pReader->nNode] |
| 119643 | || pReader->aDoclist[pReader->nDoclist-1] |
| 119644 | ){ |
| 119645 | return SQLITE_CORRUPT_VTAB; |
| 119646 | } |
| 119647 | return SQLITE_OK; |
| 119648 | } |
| 119649 | |
| 119650 | /* |
| @@ -118717,11 +119765,11 @@ | |
| 119765 | while( a<pEnd ){ |
| 119766 | a += sqlite3Fts3GetVarint(a, &nByte); |
| 119767 | } |
| 119768 | if( nDoc==0 || nByte==0 ){ |
| 119769 | sqlite3_reset(pStmt); |
| 119770 | return SQLITE_CORRUPT_VTAB; |
| 119771 | } |
| 119772 | |
| 119773 | pCsr->nRowAvg = (int)(((nByte / nDoc) + pgsz) / pgsz); |
| 119774 | assert( pCsr->nRowAvg>0 ); |
| 119775 | rc = sqlite3_reset(pStmt); |
| @@ -119488,20 +120536,20 @@ | |
| 120536 | |
| 120537 | /* |
| 120538 | ** The first value in the apVal[] array is assumed to contain an integer. |
| 120539 | ** This function tests if there exist any documents with docid values that |
| 120540 | ** are different from that integer. i.e. if deleting the document with docid |
| 120541 | ** pRowid would mean the FTS3 table were empty. |
| 120542 | ** |
| 120543 | ** If successful, *pisEmpty is set to true if the table is empty except for |
| 120544 | ** document pRowid, or false otherwise, and SQLITE_OK is returned. If an |
| 120545 | ** error occurs, an SQLite error code is returned. |
| 120546 | */ |
| 120547 | static int fts3IsEmpty(Fts3Table *p, sqlite3_value *pRowid, int *pisEmpty){ |
| 120548 | sqlite3_stmt *pStmt; |
| 120549 | int rc; |
| 120550 | rc = fts3SqlStmt(p, SQL_IS_EMPTY, &pStmt, &pRowid); |
| 120551 | if( rc==SQLITE_OK ){ |
| 120552 | if( SQLITE_ROW==sqlite3_step(pStmt) ){ |
| 120553 | *pisEmpty = sqlite3_column_int(pStmt, 0); |
| 120554 | } |
| 120555 | rc = sqlite3_reset(pStmt); |
| @@ -120221,10 +121269,44 @@ | |
| 121269 | pToken->pDeferred = pDeferred; |
| 121270 | |
| 121271 | return SQLITE_OK; |
| 121272 | } |
| 121273 | |
| 121274 | /* |
| 121275 | ** SQLite value pRowid contains the rowid of a row that may or may not be |
| 121276 | ** present in the FTS3 table. If it is, delete it and adjust the contents |
| 121277 | ** of subsiduary data structures accordingly. |
| 121278 | */ |
| 121279 | static int fts3DeleteByRowid( |
| 121280 | Fts3Table *p, |
| 121281 | sqlite3_value *pRowid, |
| 121282 | int *pnDoc, |
| 121283 | u32 *aSzDel |
| 121284 | ){ |
| 121285 | int isEmpty = 0; |
| 121286 | int rc = fts3IsEmpty(p, pRowid, &isEmpty); |
| 121287 | if( rc==SQLITE_OK ){ |
| 121288 | if( isEmpty ){ |
| 121289 | /* Deleting this row means the whole table is empty. In this case |
| 121290 | ** delete the contents of all three tables and throw away any |
| 121291 | ** data in the pendingTerms hash table. */ |
| 121292 | rc = fts3DeleteAll(p); |
| 121293 | *pnDoc = *pnDoc - 1; |
| 121294 | }else{ |
| 121295 | sqlite3_int64 iRemove = sqlite3_value_int64(pRowid); |
| 121296 | rc = fts3PendingTermsDocid(p, iRemove); |
| 121297 | fts3DeleteTerms(&rc, p, pRowid, aSzDel); |
| 121298 | fts3SqlExec(&rc, p, SQL_DELETE_CONTENT, &pRowid); |
| 121299 | if( sqlite3_changes(p->db) ) *pnDoc = *pnDoc - 1; |
| 121300 | if( p->bHasDocsize ){ |
| 121301 | fts3SqlExec(&rc, p, SQL_DELETE_DOCSIZE, &pRowid); |
| 121302 | } |
| 121303 | } |
| 121304 | } |
| 121305 | |
| 121306 | return rc; |
| 121307 | } |
| 121308 | |
| 121309 | /* |
| 121310 | ** This function does the work for the xUpdate method of FTS3 virtual |
| 121311 | ** tables. |
| 121312 | */ |
| @@ -120239,50 +121321,95 @@ | |
| 121321 | int isRemove = 0; /* True for an UPDATE or DELETE */ |
| 121322 | sqlite3_int64 iRemove = 0; /* Rowid removed by UPDATE or DELETE */ |
| 121323 | u32 *aSzIns; /* Sizes of inserted documents */ |
| 121324 | u32 *aSzDel; /* Sizes of deleted documents */ |
| 121325 | int nChng = 0; /* Net change in number of documents */ |
| 121326 | int bInsertDone = 0; |
| 121327 | |
| 121328 | assert( p->pSegments==0 ); |
| 121329 | |
| 121330 | /* Check for a "special" INSERT operation. One of the form: |
| 121331 | ** |
| 121332 | ** INSERT INTO xyz(xyz) VALUES('command'); |
| 121333 | */ |
| 121334 | if( nArg>1 |
| 121335 | && sqlite3_value_type(apVal[0])==SQLITE_NULL |
| 121336 | && sqlite3_value_type(apVal[p->nColumn+2])!=SQLITE_NULL |
| 121337 | ){ |
| 121338 | return fts3SpecialInsert(p, apVal[p->nColumn+2]); |
| 121339 | } |
| 121340 | |
| 121341 | /* Allocate space to hold the change in document sizes */ |
| 121342 | aSzIns = sqlite3_malloc( sizeof(aSzIns[0])*(p->nColumn+1)*2 ); |
| 121343 | if( aSzIns==0 ) return SQLITE_NOMEM; |
| 121344 | aSzDel = &aSzIns[p->nColumn+1]; |
| 121345 | memset(aSzIns, 0, sizeof(aSzIns[0])*(p->nColumn+1)*2); |
| 121346 | |
| 121347 | /* If this is an INSERT operation, or an UPDATE that modifies the rowid |
| 121348 | ** value, then this operation requires constraint handling. |
| 121349 | ** |
| 121350 | ** If the on-conflict mode is REPLACE, this means that the existing row |
| 121351 | ** should be deleted from the database before inserting the new row. Or, |
| 121352 | ** if the on-conflict mode is other than REPLACE, then this method must |
| 121353 | ** detect the conflict and return SQLITE_CONSTRAINT before beginning to |
| 121354 | ** modify the database file. |
| 121355 | */ |
| 121356 | if( nArg>1 ){ |
| 121357 | /* Find the value object that holds the new rowid value. */ |
| 121358 | sqlite3_value *pNewRowid = apVal[3+p->nColumn]; |
| 121359 | if( sqlite3_value_type(pNewRowid)==SQLITE_NULL ){ |
| 121360 | pNewRowid = apVal[1]; |
| 121361 | } |
| 121362 | |
| 121363 | if( sqlite3_value_type(pNewRowid)!=SQLITE_NULL && ( |
| 121364 | sqlite3_value_type(apVal[0])==SQLITE_NULL |
| 121365 | || sqlite3_value_int64(apVal[0])!=sqlite3_value_int64(pNewRowid) |
| 121366 | )){ |
| 121367 | /* The new rowid is not NULL (in this case the rowid will be |
| 121368 | ** automatically assigned and there is no chance of a conflict), and |
| 121369 | ** the statement is either an INSERT or an UPDATE that modifies the |
| 121370 | ** rowid column. So if the conflict mode is REPLACE, then delete any |
| 121371 | ** existing row with rowid=pNewRowid. |
| 121372 | ** |
| 121373 | ** Or, if the conflict mode is not REPLACE, insert the new record into |
| 121374 | ** the %_content table. If we hit the duplicate rowid constraint (or any |
| 121375 | ** other error) while doing so, return immediately. |
| 121376 | ** |
| 121377 | ** This branch may also run if pNewRowid contains a value that cannot |
| 121378 | ** be losslessly converted to an integer. In this case, the eventual |
| 121379 | ** call to fts3InsertData() (either just below or further on in this |
| 121380 | ** function) will return SQLITE_MISMATCH. If fts3DeleteByRowid is |
| 121381 | ** invoked, it will delete zero rows (since no row will have |
| 121382 | ** docid=$pNewRowid if $pNewRowid is not an integer value). |
| 121383 | */ |
| 121384 | if( sqlite3_vtab_on_conflict(p->db)==SQLITE_REPLACE ){ |
| 121385 | rc = fts3DeleteByRowid(p, pNewRowid, &nChng, aSzDel); |
| 121386 | }else{ |
| 121387 | rc = fts3InsertData(p, apVal, pRowid); |
| 121388 | bInsertDone = 1; |
| 121389 | } |
| 121390 | } |
| 121391 | } |
| 121392 | if( rc!=SQLITE_OK ){ |
| 121393 | sqlite3_free(aSzIns); |
| 121394 | return rc; |
| 121395 | } |
| 121396 | |
| 121397 | /* If this is a DELETE or UPDATE operation, remove the old record. */ |
| 121398 | if( sqlite3_value_type(apVal[0])!=SQLITE_NULL ){ |
| 121399 | assert( sqlite3_value_type(apVal[0])==SQLITE_INTEGER ); |
| 121400 | rc = fts3DeleteByRowid(p, apVal[0], &nChng, aSzDel); |
| 121401 | isRemove = 1; |
| 121402 | iRemove = sqlite3_value_int64(apVal[0]); |
| 121403 | } |
| 121404 | |
| 121405 | /* If this is an INSERT or UPDATE operation, insert the new record. */ |
| 121406 | if( nArg>1 && rc==SQLITE_OK ){ |
| 121407 | if( bInsertDone==0 ){ |
| 121408 | rc = fts3InsertData(p, apVal, pRowid); |
| 121409 | if( rc==SQLITE_CONSTRAINT ) rc = SQLITE_CORRUPT_VTAB; |
| 121410 | } |
| 121411 | if( rc==SQLITE_OK && (!isRemove || *pRowid!=iRemove) ){ |
| 121412 | rc = fts3PendingTermsDocid(p, *pRowid); |
| 121413 | } |
| 121414 | if( rc==SQLITE_OK ){ |
| 121415 | rc = fts3InsertTerms(p, apVal, aSzIns); |
| @@ -120742,11 +121869,11 @@ | |
| 121869 | SnippetPhrase *pPhrase = &p->aPhrase[iPhrase]; |
| 121870 | char *pCsr; |
| 121871 | |
| 121872 | pPhrase->nToken = pExpr->pPhrase->nToken; |
| 121873 | |
| 121874 | pCsr = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->pCsr->iPrevId, p->iCol); |
| 121875 | if( pCsr ){ |
| 121876 | int iFirst = 0; |
| 121877 | pPhrase->pList = pCsr; |
| 121878 | fts3GetDeltaPosition(&pCsr, &iFirst); |
| 121879 | pPhrase->pHead = pCsr; |
| @@ -121215,11 +122342,11 @@ | |
| 122342 | for(i=0; i<p->nCol; i++) p->aMatchinfo[iStart+i*3] = 0; |
| 122343 | |
| 122344 | if( pExpr->aDoclist ){ |
| 122345 | char *pCsr; |
| 122346 | |
| 122347 | pCsr = sqlite3Fts3FindPositions(p->pCursor, pExpr, p->pCursor->iPrevId, -1); |
| 122348 | if( pCsr ){ |
| 122349 | fts3LoadColumnlistCounts(&pCsr, &p->aMatchinfo[iStart], 0); |
| 122350 | } |
| 122351 | } |
| 122352 | |
| @@ -121287,11 +122414,11 @@ | |
| 122414 | pStmt = *ppStmt; |
| 122415 | assert( sqlite3_data_count(pStmt)==1 ); |
| 122416 | |
| 122417 | a = sqlite3_column_blob(pStmt, 0); |
| 122418 | a += sqlite3Fts3GetVarint(a, &nDoc); |
| 122419 | if( nDoc==0 ) return SQLITE_CORRUPT_VTAB; |
| 122420 | *pnDoc = (u32)nDoc; |
| 122421 | |
| 122422 | if( paLen ) *paLen = a; |
| 122423 | return SQLITE_OK; |
| 122424 | } |
| @@ -121382,11 +122509,11 @@ | |
| 122509 | (void)fts3ExprIterate(pCsr->pExpr, fts3MatchinfoLcsCb, (void*)aIter); |
| 122510 | for(i=0; i<pInfo->nPhrase; i++){ |
| 122511 | LcsIterator *pIter = &aIter[i]; |
| 122512 | nToken -= pIter->pExpr->pPhrase->nToken; |
| 122513 | pIter->iPosOffset = nToken; |
| 122514 | pIter->pRead = sqlite3Fts3FindPositions(pCsr,pIter->pExpr,pCsr->iPrevId,-1); |
| 122515 | if( pIter->pRead ){ |
| 122516 | pIter->iPos = pIter->iPosOffset; |
| 122517 | fts3LcsIteratorAdvance(&aIter[i]); |
| 122518 | }else{ |
| 122519 | pIter->iCol = LCS_ITERATOR_FINISHED; |
| @@ -121735,10 +122862,11 @@ | |
| 122862 | int iPos; /* Position just read from pList */ |
| 122863 | int iOff; /* Offset of this term from read positions */ |
| 122864 | }; |
| 122865 | |
| 122866 | struct TermOffsetCtx { |
| 122867 | Fts3Cursor *pCsr; |
| 122868 | int iCol; /* Column of table to populate aTerm for */ |
| 122869 | int iTerm; |
| 122870 | sqlite3_int64 iDocid; |
| 122871 | TermOffset *aTerm; |
| 122872 | }; |
| @@ -121752,11 +122880,11 @@ | |
| 122880 | int iTerm; /* For looping through nTerm phrase terms */ |
| 122881 | char *pList; /* Pointer to position list for phrase */ |
| 122882 | int iPos = 0; /* First position in position-list */ |
| 122883 | |
| 122884 | UNUSED_PARAMETER(iPhrase); |
| 122885 | pList = sqlite3Fts3FindPositions(p->pCsr, pExpr, p->iDocid, p->iCol); |
| 122886 | nTerm = pExpr->pPhrase->nToken; |
| 122887 | if( pList ){ |
| 122888 | fts3GetDeltaPosition(&pList, &iPos); |
| 122889 | assert( iPos>=0 ); |
| 122890 | } |
| @@ -121805,10 +122933,11 @@ | |
| 122933 | if( 0==sCtx.aTerm ){ |
| 122934 | rc = SQLITE_NOMEM; |
| 122935 | goto offsets_out; |
| 122936 | } |
| 122937 | sCtx.iDocid = pCsr->iPrevId; |
| 122938 | sCtx.pCsr = pCsr; |
| 122939 | |
| 122940 | /* Loop through the table columns, appending offset information to |
| 122941 | ** string-buffer res for each column. |
| 122942 | */ |
| 122943 | for(iCol=0; iCol<pTab->nColumn; iCol++){ |
| @@ -121880,11 +123009,11 @@ | |
| 123009 | sqlite3_snprintf(sizeof(aBuffer), aBuffer, |
| 123010 | "%d %d %d %d ", iCol, pTerm-sCtx.aTerm, iStart, iEnd-iStart |
| 123011 | ); |
| 123012 | rc = fts3StringAppend(&res, aBuffer, -1); |
| 123013 | }else if( rc==SQLITE_DONE ){ |
| 123014 | rc = SQLITE_CORRUPT_VTAB; |
| 123015 | } |
| 123016 | } |
| 123017 | } |
| 123018 | if( rc==SQLITE_DONE ){ |
| 123019 | rc = SQLITE_OK; |
| @@ -122468,29 +123597,29 @@ | |
| 123597 | ** is greater than RTREE_MAX_DEPTH, the r-tree structure must be corrupt. |
| 123598 | */ |
| 123599 | if( pNode && iNode==1 ){ |
| 123600 | pRtree->iDepth = readInt16(pNode->zData); |
| 123601 | if( pRtree->iDepth>RTREE_MAX_DEPTH ){ |
| 123602 | rc = SQLITE_CORRUPT_VTAB; |
| 123603 | } |
| 123604 | } |
| 123605 | |
| 123606 | /* If no error has occurred so far, check if the "number of entries" |
| 123607 | ** field on the node is too large. If so, set the return code to |
| 123608 | ** SQLITE_CORRUPT_VTAB. |
| 123609 | */ |
| 123610 | if( pNode && rc==SQLITE_OK ){ |
| 123611 | if( NCELL(pNode)>((pRtree->iNodeSize-4)/pRtree->nBytesPerCell) ){ |
| 123612 | rc = SQLITE_CORRUPT_VTAB; |
| 123613 | } |
| 123614 | } |
| 123615 | |
| 123616 | if( rc==SQLITE_OK ){ |
| 123617 | if( pNode!=0 ){ |
| 123618 | nodeHashInsert(pRtree, pNode); |
| 123619 | }else{ |
| 123620 | rc = SQLITE_CORRUPT_VTAB; |
| 123621 | } |
| 123622 | *ppNode = pNode; |
| 123623 | }else{ |
| 123624 | sqlite3_free(pNode); |
| 123625 | *ppNode = 0; |
| @@ -123013,11 +124142,11 @@ | |
| 124142 | if( nodeGetRowid(pRtree, pNode, ii)==iRowid ){ |
| 124143 | *piIndex = ii; |
| 124144 | return SQLITE_OK; |
| 124145 | } |
| 124146 | } |
| 124147 | return SQLITE_CORRUPT_VTAB; |
| 124148 | } |
| 124149 | |
| 124150 | /* |
| 124151 | ** Return the index of the cell containing a pointer to node pNode |
| 124152 | ** in its parent. If pNode is the root node, return -1. |
| @@ -123608,11 +124737,11 @@ | |
| 124737 | RtreeNode *pParent = p->pParent; |
| 124738 | RtreeCell cell; |
| 124739 | int iCell; |
| 124740 | |
| 124741 | if( nodeParentIndex(pRtree, p, &iCell) ){ |
| 124742 | return SQLITE_CORRUPT_VTAB; |
| 124743 | } |
| 124744 | |
| 124745 | nodeGetCell(pRtree, pParent, iCell, &cell); |
| 124746 | if( !cellContains(pRtree, &cell, pCell) ){ |
| 124747 | cellUnion(pRtree, &cell, pCell); |
| @@ -124280,11 +125409,11 @@ | |
| 125409 | rc2 = nodeAcquire(pRtree, iNode, 0, &pChild->pParent); |
| 125410 | } |
| 125411 | } |
| 125412 | rc = sqlite3_reset(pRtree->pReadParent); |
| 125413 | if( rc==SQLITE_OK ) rc = rc2; |
| 125414 | if( rc==SQLITE_OK && !pChild->pParent ) rc = SQLITE_CORRUPT_VTAB; |
| 125415 | pChild = pChild->pParent; |
| 125416 | } |
| 125417 | return rc; |
| 125418 | } |
| 125419 | |
| @@ -124575,10 +125704,94 @@ | |
| 125704 | sqlite3_step(pRtree->pWriteRowid); |
| 125705 | rc = sqlite3_reset(pRtree->pWriteRowid); |
| 125706 | *piRowid = sqlite3_last_insert_rowid(pRtree->db); |
| 125707 | return rc; |
| 125708 | } |
| 125709 | |
| 125710 | /* |
| 125711 | ** Remove the entry with rowid=iDelete from the r-tree structure. |
| 125712 | */ |
| 125713 | static int rtreeDeleteRowid(Rtree *pRtree, sqlite3_int64 iDelete){ |
| 125714 | int rc; /* Return code */ |
| 125715 | RtreeNode *pLeaf; /* Leaf node containing record iDelete */ |
| 125716 | int iCell; /* Index of iDelete cell in pLeaf */ |
| 125717 | RtreeNode *pRoot; /* Root node of rtree structure */ |
| 125718 | |
| 125719 | |
| 125720 | /* Obtain a reference to the root node to initialise Rtree.iDepth */ |
| 125721 | rc = nodeAcquire(pRtree, 1, 0, &pRoot); |
| 125722 | |
| 125723 | /* Obtain a reference to the leaf node that contains the entry |
| 125724 | ** about to be deleted. |
| 125725 | */ |
| 125726 | if( rc==SQLITE_OK ){ |
| 125727 | rc = findLeafNode(pRtree, iDelete, &pLeaf); |
| 125728 | } |
| 125729 | |
| 125730 | /* Delete the cell in question from the leaf node. */ |
| 125731 | if( rc==SQLITE_OK ){ |
| 125732 | int rc2; |
| 125733 | rc = nodeRowidIndex(pRtree, pLeaf, iDelete, &iCell); |
| 125734 | if( rc==SQLITE_OK ){ |
| 125735 | rc = deleteCell(pRtree, pLeaf, iCell, 0); |
| 125736 | } |
| 125737 | rc2 = nodeRelease(pRtree, pLeaf); |
| 125738 | if( rc==SQLITE_OK ){ |
| 125739 | rc = rc2; |
| 125740 | } |
| 125741 | } |
| 125742 | |
| 125743 | /* Delete the corresponding entry in the <rtree>_rowid table. */ |
| 125744 | if( rc==SQLITE_OK ){ |
| 125745 | sqlite3_bind_int64(pRtree->pDeleteRowid, 1, iDelete); |
| 125746 | sqlite3_step(pRtree->pDeleteRowid); |
| 125747 | rc = sqlite3_reset(pRtree->pDeleteRowid); |
| 125748 | } |
| 125749 | |
| 125750 | /* Check if the root node now has exactly one child. If so, remove |
| 125751 | ** it, schedule the contents of the child for reinsertion and |
| 125752 | ** reduce the tree height by one. |
| 125753 | ** |
| 125754 | ** This is equivalent to copying the contents of the child into |
| 125755 | ** the root node (the operation that Gutman's paper says to perform |
| 125756 | ** in this scenario). |
| 125757 | */ |
| 125758 | if( rc==SQLITE_OK && pRtree->iDepth>0 && NCELL(pRoot)==1 ){ |
| 125759 | int rc2; |
| 125760 | RtreeNode *pChild; |
| 125761 | i64 iChild = nodeGetRowid(pRtree, pRoot, 0); |
| 125762 | rc = nodeAcquire(pRtree, iChild, pRoot, &pChild); |
| 125763 | if( rc==SQLITE_OK ){ |
| 125764 | rc = removeNode(pRtree, pChild, pRtree->iDepth-1); |
| 125765 | } |
| 125766 | rc2 = nodeRelease(pRtree, pChild); |
| 125767 | if( rc==SQLITE_OK ) rc = rc2; |
| 125768 | if( rc==SQLITE_OK ){ |
| 125769 | pRtree->iDepth--; |
| 125770 | writeInt16(pRoot->zData, pRtree->iDepth); |
| 125771 | pRoot->isDirty = 1; |
| 125772 | } |
| 125773 | } |
| 125774 | |
| 125775 | /* Re-insert the contents of any underfull nodes removed from the tree. */ |
| 125776 | for(pLeaf=pRtree->pDeleted; pLeaf; pLeaf=pRtree->pDeleted){ |
| 125777 | if( rc==SQLITE_OK ){ |
| 125778 | rc = reinsertNodeContent(pRtree, pLeaf); |
| 125779 | } |
| 125780 | pRtree->pDeleted = pLeaf->pNext; |
| 125781 | sqlite3_free(pLeaf); |
| 125782 | } |
| 125783 | |
| 125784 | /* Release the reference to the root node. */ |
| 125785 | if( rc==SQLITE_OK ){ |
| 125786 | rc = nodeRelease(pRtree, pRoot); |
| 125787 | }else{ |
| 125788 | nodeRelease(pRtree, pRoot); |
| 125789 | } |
| 125790 | |
| 125791 | return rc; |
| 125792 | } |
| 125793 | |
| 125794 | /* |
| 125795 | ** The xUpdate method for rtree module virtual tables. |
| 125796 | */ |
| 125797 | static int rtreeUpdate( |
| @@ -124587,107 +125800,29 @@ | |
| 125800 | sqlite3_value **azData, |
| 125801 | sqlite_int64 *pRowid |
| 125802 | ){ |
| 125803 | Rtree *pRtree = (Rtree *)pVtab; |
| 125804 | int rc = SQLITE_OK; |
| 125805 | RtreeCell cell; /* New cell to insert if nData>1 */ |
| 125806 | int bHaveRowid = 0; /* Set to 1 after new rowid is determined */ |
| 125807 | |
| 125808 | rtreeReference(pRtree); |
| 125809 | assert(nData>=1); |
| 125810 | |
| 125811 | /* Constraint handling. A write operation on an r-tree table may return |
| 125812 | ** SQLITE_CONSTRAINT for two reasons: |
| 125813 | ** |
| 125814 | ** 1. A duplicate rowid value, or |
| 125815 | ** 2. The supplied data violates the "x2>=x1" constraint. |
| 125816 | ** |
| 125817 | ** In the first case, if the conflict-handling mode is REPLACE, then |
| 125818 | ** the conflicting row can be removed before proceeding. In the second |
| 125819 | ** case, SQLITE_CONSTRAINT must be returned regardless of the |
| 125820 | ** conflict-handling mode specified by the user. |
| 125821 | */ |
| 125822 | if( nData>1 ){ |
| 125823 | int ii; |
| 125824 | |
| 125825 | /* Populate the cell.aCoord[] array. The first coordinate is azData[3]. */ |
| 125826 | assert( nData==(pRtree->nDim*2 + 3) ); |
| 125827 | if( pRtree->eCoordType==RTREE_COORD_REAL32 ){ |
| 125828 | for(ii=0; ii<(pRtree->nDim*2); ii+=2){ |
| @@ -124707,22 +125842,53 @@ | |
| 125842 | goto constraint; |
| 125843 | } |
| 125844 | } |
| 125845 | } |
| 125846 | |
| 125847 | /* If a rowid value was supplied, check if it is already present in |
| 125848 | ** the table. If so, the constraint has failed. */ |
| 125849 | if( sqlite3_value_type(azData[2])!=SQLITE_NULL ){ |
| 125850 | cell.iRowid = sqlite3_value_int64(azData[2]); |
| 125851 | if( sqlite3_value_type(azData[0])==SQLITE_NULL |
| 125852 | || sqlite3_value_int64(azData[0])!=cell.iRowid |
| 125853 | ){ |
| 125854 | int steprc; |
| 125855 | sqlite3_bind_int64(pRtree->pReadRowid, 1, cell.iRowid); |
| 125856 | steprc = sqlite3_step(pRtree->pReadRowid); |
| 125857 | rc = sqlite3_reset(pRtree->pReadRowid); |
| 125858 | if( SQLITE_ROW==steprc ){ |
| 125859 | if( sqlite3_vtab_on_conflict(pRtree->db)==SQLITE_REPLACE ){ |
| 125860 | rc = rtreeDeleteRowid(pRtree, cell.iRowid); |
| 125861 | }else{ |
| 125862 | rc = SQLITE_CONSTRAINT; |
| 125863 | goto constraint; |
| 125864 | } |
| 125865 | } |
| 125866 | } |
| 125867 | bHaveRowid = 1; |
| 125868 | } |
| 125869 | } |
| 125870 | |
| 125871 | /* If azData[0] is not an SQL NULL value, it is the rowid of a |
| 125872 | ** record to delete from the r-tree table. The following block does |
| 125873 | ** just that. |
| 125874 | */ |
| 125875 | if( sqlite3_value_type(azData[0])!=SQLITE_NULL ){ |
| 125876 | rc = rtreeDeleteRowid(pRtree, sqlite3_value_int64(azData[0])); |
| 125877 | } |
| 125878 | |
| 125879 | /* If the azData[] array contains more than one element, elements |
| 125880 | ** (azData[2]..azData[argc-1]) contain a new record to insert into |
| 125881 | ** the r-tree structure. |
| 125882 | */ |
| 125883 | if( rc==SQLITE_OK && nData>1 ){ |
| 125884 | /* Insert the new record into the r-tree */ |
| 125885 | RtreeNode *pLeaf; |
| 125886 | |
| 125887 | /* Figure out the rowid of the new row. */ |
| 125888 | if( bHaveRowid==0 ){ |
| 125889 | rc = newRowid(pRtree, &cell.iRowid); |
| 125890 | } |
| 125891 | *pRowid = cell.iRowid; |
| 125892 | |
| 125893 | if( rc==SQLITE_OK ){ |
| 125894 | rc = ChooseLeaf(pRtree, &cell, 0, &pLeaf); |
| @@ -124958,10 +126124,12 @@ | |
| 126124 | int iErr = (argc<6) ? 2 : argc>(RTREE_MAX_DIMENSIONS*2+4) ? 3 : argc%2; |
| 126125 | if( aErrMsg[iErr] ){ |
| 126126 | *pzErr = sqlite3_mprintf("%s", aErrMsg[iErr]); |
| 126127 | return SQLITE_ERROR; |
| 126128 | } |
| 126129 | |
| 126130 | sqlite3_vtab_config(db, SQLITE_VTAB_CONSTRAINT_SUPPORT, 1); |
| 126131 | |
| 126132 | /* Allocate the sqlite3_vtab structure */ |
| 126133 | nDb = strlen(argv[1]); |
| 126134 | nName = strlen(argv[2]); |
| 126135 | pRtree = (Rtree *)sqlite3_malloc(sizeof(Rtree)+nDb+nName+2); |
| 126136 |
+341
-77
| --- src/sqlite3.h | ||
| +++ src/sqlite3.h | ||
| @@ -105,13 +105,13 @@ | ||
| 105 | 105 | ** |
| 106 | 106 | ** See also: [sqlite3_libversion()], |
| 107 | 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | 109 | */ |
| 110 | -#define SQLITE_VERSION "3.7.6" | |
| 111 | -#define SQLITE_VERSION_NUMBER 3007006 | |
| 112 | -#define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" | |
| 110 | +#define SQLITE_VERSION "3.7.7" | |
| 111 | +#define SQLITE_VERSION_NUMBER 3007007 | |
| 112 | +#define SQLITE_SOURCE_ID "2011-05-20 01:50:01 2018d4e108872f2436df046636401b89cfde589d" | |
| 113 | 113 | |
| 114 | 114 | /* |
| 115 | 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | 117 | ** |
| @@ -373,11 +373,12 @@ | ||
| 373 | 373 | ** Many SQLite functions return an integer result code from the set shown |
| 374 | 374 | ** here in order to indicates success or failure. |
| 375 | 375 | ** |
| 376 | 376 | ** New error codes may be added in future versions of SQLite. |
| 377 | 377 | ** |
| 378 | -** See also: [SQLITE_IOERR_READ | extended result codes] | |
| 378 | +** See also: [SQLITE_IOERR_READ | extended result codes], | |
| 379 | +** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. | |
| 379 | 380 | */ |
| 380 | 381 | #define SQLITE_OK 0 /* Successful result */ |
| 381 | 382 | /* beginning-of-error-codes */ |
| 382 | 383 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 383 | 384 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -450,28 +451,31 @@ | ||
| 450 | 451 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 451 | 452 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 452 | 453 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 453 | 454 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 454 | 455 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 456 | +#define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) | |
| 457 | +#define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) | |
| 455 | 458 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 456 | 459 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 457 | 460 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 461 | +#define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) | |
| 458 | 462 | |
| 459 | 463 | /* |
| 460 | 464 | ** CAPI3REF: Flags For File Open Operations |
| 461 | 465 | ** |
| 462 | 466 | ** These bit values are intended for use in the |
| 463 | 467 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 464 | -** in the 4th parameter to the xOpen method of the | |
| 465 | -** [sqlite3_vfs] object. | |
| 468 | +** in the 4th parameter to the [sqlite3_vfs.xOpen] method. | |
| 466 | 469 | */ |
| 467 | 470 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 468 | 471 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 469 | 472 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 470 | 473 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 471 | 474 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 472 | 475 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 476 | +#define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ | |
| 473 | 477 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 474 | 478 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 475 | 479 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 476 | 480 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 477 | 481 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -578,21 +582,22 @@ | ||
| 578 | 582 | }; |
| 579 | 583 | |
| 580 | 584 | /* |
| 581 | 585 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 582 | 586 | ** |
| 583 | -** Every file opened by the [sqlite3_vfs] xOpen method populates an | |
| 587 | +** Every file opened by the [sqlite3_vfs.xOpen] method populates an | |
| 584 | 588 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 585 | 589 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 586 | 590 | ** This object defines the methods used to perform various operations |
| 587 | 591 | ** against the open file represented by the [sqlite3_file] object. |
| 588 | 592 | ** |
| 589 | -** If the xOpen method sets the sqlite3_file.pMethods element | |
| 593 | +** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element | |
| 590 | 594 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 591 | -** may be invoked even if the xOpen reported that it failed. The | |
| 592 | -** only way to prevent a call to xClose following a failed xOpen | |
| 593 | -** is for the xOpen to set the sqlite3_file.pMethods element to NULL. | |
| 595 | +** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The | |
| 596 | +** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] | |
| 597 | +** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element | |
| 598 | +** to NULL. | |
| 594 | 599 | ** |
| 595 | 600 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 596 | 601 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 597 | 602 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 598 | 603 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -757,10 +762,11 @@ | ||
| 757 | 762 | */ |
| 758 | 763 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 759 | 764 | |
| 760 | 765 | /* |
| 761 | 766 | ** CAPI3REF: OS Interface Object |
| 767 | +** KEYWORDS: VFS VFSes | |
| 762 | 768 | ** |
| 763 | 769 | ** An instance of the sqlite3_vfs object defines the interface between |
| 764 | 770 | ** the SQLite core and the underlying operating system. The "vfs" |
| 765 | 771 | ** in the name of the object stands for "virtual file system". |
| 766 | 772 | ** |
| @@ -789,10 +795,11 @@ | ||
| 789 | 795 | ** object once the object has been registered. |
| 790 | 796 | ** |
| 791 | 797 | ** The zName field holds the name of the VFS module. The name must |
| 792 | 798 | ** be unique across all VFS modules. |
| 793 | 799 | ** |
| 800 | +** [[sqlite3_vfs.xOpen]] | |
| 794 | 801 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 795 | 802 | ** is either a NULL pointer or string obtained |
| 796 | 803 | ** from xFullPathname() with an optional suffix added. |
| 797 | 804 | ** ^If a suffix is added to the zFilename parameter, it will |
| 798 | 805 | ** consist of a single "-" character followed by no more than |
| @@ -866,10 +873,11 @@ | ||
| 866 | 873 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 867 | 874 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 868 | 875 | ** element will be valid after xOpen returns regardless of the success |
| 869 | 876 | ** or failure of the xOpen call. |
| 870 | 877 | ** |
| 878 | +** [[sqlite3_vfs.xAccess]] | |
| 871 | 879 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 872 | 880 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 873 | 881 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 874 | 882 | ** to test whether a file is at least readable. The file can be a |
| 875 | 883 | ** directory. |
| @@ -1112,13 +1120,13 @@ | ||
| 1112 | 1120 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1113 | 1121 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1114 | 1122 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1115 | 1123 | ** |
| 1116 | 1124 | ** The first argument to sqlite3_config() is an integer |
| 1117 | -** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines | |
| 1125 | +** [configuration option] that determines | |
| 1118 | 1126 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1119 | -** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] | |
| 1127 | +** vary depending on the [configuration option] | |
| 1120 | 1128 | ** in the first argument. |
| 1121 | 1129 | ** |
| 1122 | 1130 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1123 | 1131 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1124 | 1132 | ** then this routine returns a non-zero [error code]. |
| @@ -1224,10 +1232,11 @@ | ||
| 1224 | 1232 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1225 | 1233 | }; |
| 1226 | 1234 | |
| 1227 | 1235 | /* |
| 1228 | 1236 | ** CAPI3REF: Configuration Options |
| 1237 | +** KEYWORDS: {configuration option} | |
| 1229 | 1238 | ** |
| 1230 | 1239 | ** These constants are the available integer configuration options that |
| 1231 | 1240 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1232 | 1241 | ** |
| 1233 | 1242 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1236,11 +1245,11 @@ | ||
| 1236 | 1245 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1237 | 1246 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1238 | 1247 | ** is invoked. |
| 1239 | 1248 | ** |
| 1240 | 1249 | ** <dl> |
| 1241 | -** <dt>SQLITE_CONFIG_SINGLETHREAD</dt> | |
| 1250 | +** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt> | |
| 1242 | 1251 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1243 | 1252 | ** [threading mode] to Single-thread. In other words, it disables |
| 1244 | 1253 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1245 | 1254 | ** by a single thread. ^If SQLite is compiled with |
| 1246 | 1255 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1247,11 +1256,11 @@ | ||
| 1247 | 1256 | ** it is not possible to change the [threading mode] from its default |
| 1248 | 1257 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1249 | 1258 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1250 | 1259 | ** configuration option.</dd> |
| 1251 | 1260 | ** |
| 1252 | -** <dt>SQLITE_CONFIG_MULTITHREAD</dt> | |
| 1261 | +** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt> | |
| 1253 | 1262 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1254 | 1263 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1255 | 1264 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1256 | 1265 | ** The application is responsible for serializing access to |
| 1257 | 1266 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1261,11 +1270,11 @@ | ||
| 1261 | 1270 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1262 | 1271 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1263 | 1272 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1264 | 1273 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1265 | 1274 | ** |
| 1266 | -** <dt>SQLITE_CONFIG_SERIALIZED</dt> | |
| 1275 | +** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt> | |
| 1267 | 1276 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1268 | 1277 | ** [threading mode] to Serialized. In other words, this option enables |
| 1269 | 1278 | ** all mutexes including the recursive |
| 1270 | 1279 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1271 | 1280 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1277,27 +1286,27 @@ | ||
| 1277 | 1286 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1278 | 1287 | ** it is not possible to set the Serialized [threading mode] and |
| 1279 | 1288 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1280 | 1289 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1281 | 1290 | ** |
| 1282 | -** <dt>SQLITE_CONFIG_MALLOC</dt> | |
| 1291 | +** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> | |
| 1283 | 1292 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1284 | 1293 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1285 | 1294 | ** alternative low-level memory allocation routines to be used in place of |
| 1286 | 1295 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1287 | 1296 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1288 | 1297 | ** before the [sqlite3_config()] call returns.</dd> |
| 1289 | 1298 | ** |
| 1290 | -** <dt>SQLITE_CONFIG_GETMALLOC</dt> | |
| 1299 | +** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt> | |
| 1291 | 1300 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1292 | 1301 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1293 | 1302 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1294 | 1303 | ** This option can be used to overload the default memory allocation |
| 1295 | 1304 | ** routines with a wrapper that simulations memory allocation failure or |
| 1296 | 1305 | ** tracks memory usage, for example. </dd> |
| 1297 | 1306 | ** |
| 1298 | -** <dt>SQLITE_CONFIG_MEMSTATUS</dt> | |
| 1307 | +** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> | |
| 1299 | 1308 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1300 | 1309 | ** boolean, which enables or disables the collection of memory allocation |
| 1301 | 1310 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1302 | 1311 | ** following SQLite interfaces become non-operational: |
| 1303 | 1312 | ** <ul> |
| @@ -1309,11 +1318,11 @@ | ||
| 1309 | 1318 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1310 | 1319 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1311 | 1320 | ** allocation statistics are disabled by default. |
| 1312 | 1321 | ** </dd> |
| 1313 | 1322 | ** |
| 1314 | -** <dt>SQLITE_CONFIG_SCRATCH</dt> | |
| 1323 | +** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> | |
| 1315 | 1324 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1316 | 1325 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1317 | 1326 | ** aligned memory buffer from which the scratch allocations will be |
| 1318 | 1327 | ** drawn, the size of each scratch allocation (sz), |
| 1319 | 1328 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1325,11 +1334,11 @@ | ||
| 1325 | 1334 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1326 | 1335 | ** times the database page size. ^If SQLite needs needs additional |
| 1327 | 1336 | ** scratch memory beyond what is provided by this configuration option, then |
| 1328 | 1337 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1329 | 1338 | ** |
| 1330 | -** <dt>SQLITE_CONFIG_PAGECACHE</dt> | |
| 1339 | +** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> | |
| 1331 | 1340 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1332 | 1341 | ** the database page cache with the default page cache implemenation. |
| 1333 | 1342 | ** This configuration should not be used if an application-define page |
| 1334 | 1343 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1335 | 1344 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1346,11 +1355,11 @@ | ||
| 1346 | 1355 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1347 | 1356 | ** The pointer in the first argument must |
| 1348 | 1357 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1349 | 1358 | ** will be undefined.</dd> |
| 1350 | 1359 | ** |
| 1351 | -** <dt>SQLITE_CONFIG_HEAP</dt> | |
| 1360 | +** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> | |
| 1352 | 1361 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1353 | 1362 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1354 | 1363 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1355 | 1364 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1356 | 1365 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1363,11 +1372,11 @@ | ||
| 1363 | 1372 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1364 | 1373 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1365 | 1374 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1366 | 1375 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1367 | 1376 | ** |
| 1368 | -** <dt>SQLITE_CONFIG_MUTEX</dt> | |
| 1377 | +** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> | |
| 1369 | 1378 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1370 | 1379 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1371 | 1380 | ** alternative low-level mutex routines to be used in place |
| 1372 | 1381 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1373 | 1382 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1375,11 +1384,11 @@ | ||
| 1375 | 1384 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1376 | 1385 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1377 | 1386 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1378 | 1387 | ** return [SQLITE_ERROR].</dd> |
| 1379 | 1388 | ** |
| 1380 | -** <dt>SQLITE_CONFIG_GETMUTEX</dt> | |
| 1389 | +** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt> | |
| 1381 | 1390 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1382 | 1391 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1383 | 1392 | ** [sqlite3_mutex_methods] |
| 1384 | 1393 | ** structure is filled with the currently defined mutex routines.)^ |
| 1385 | 1394 | ** This option can be used to overload the default mutex allocation |
| @@ -1388,32 +1397,32 @@ | ||
| 1388 | 1397 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1389 | 1398 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1390 | 1399 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1391 | 1400 | ** return [SQLITE_ERROR].</dd> |
| 1392 | 1401 | ** |
| 1393 | -** <dt>SQLITE_CONFIG_LOOKASIDE</dt> | |
| 1402 | +** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt> | |
| 1394 | 1403 | ** <dd> ^(This option takes two arguments that determine the default |
| 1395 | 1404 | ** memory allocation for the lookaside memory allocator on each |
| 1396 | 1405 | ** [database connection]. The first argument is the |
| 1397 | 1406 | ** size of each lookaside buffer slot and the second is the number of |
| 1398 | 1407 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1399 | 1408 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1400 | 1409 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1401 | 1410 | ** configuration on individual connections.)^ </dd> |
| 1402 | 1411 | ** |
| 1403 | -** <dt>SQLITE_CONFIG_PCACHE</dt> | |
| 1412 | +** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt> | |
| 1404 | 1413 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1405 | 1414 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1406 | 1415 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1407 | 1416 | ** object and uses it for page cache memory allocations.</dd> |
| 1408 | 1417 | ** |
| 1409 | -** <dt>SQLITE_CONFIG_GETPCACHE</dt> | |
| 1418 | +** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt> | |
| 1410 | 1419 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1411 | 1420 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1412 | 1421 | ** page cache implementation into that object.)^ </dd> |
| 1413 | 1422 | ** |
| 1414 | -** <dt>SQLITE_CONFIG_LOG</dt> | |
| 1423 | +** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> | |
| 1415 | 1424 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1416 | 1425 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1417 | 1426 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1418 | 1427 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1419 | 1428 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1427,10 +1436,22 @@ | ||
| 1427 | 1436 | ** The SQLite logging interface is not reentrant; the logger function |
| 1428 | 1437 | ** supplied by the application must not invoke any SQLite interface. |
| 1429 | 1438 | ** In a multi-threaded application, the application-defined logger |
| 1430 | 1439 | ** function must be threadsafe. </dd> |
| 1431 | 1440 | ** |
| 1441 | +** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI | |
| 1442 | +** <dd> This option takes a single argument of type int. If non-zero, then | |
| 1443 | +** URI handling is globally enabled. If the parameter is zero, then URI handling | |
| 1444 | +** is globally disabled. If URI handling is globally enabled, all filenames | |
| 1445 | +** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or | |
| 1446 | +** specified as part of [ATTACH] commands are interpreted as URIs, regardless | |
| 1447 | +** of whether or not the [SQLITE_OPEN_URI] flag is set when the database | |
| 1448 | +** connection is opened. If it is globally disabled, filenames are | |
| 1449 | +** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the | |
| 1450 | +** database connection is opened. By default, URI handling is globally | |
| 1451 | +** disabled. The default value may be changed by compiling with the | |
| 1452 | +** [SQLITE_USE_URI] symbol defined. | |
| 1432 | 1453 | ** </dl> |
| 1433 | 1454 | */ |
| 1434 | 1455 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1435 | 1456 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 1436 | 1457 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1445,10 +1466,11 @@ | ||
| 1445 | 1466 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 1446 | 1467 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 1447 | 1468 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 1448 | 1469 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 1449 | 1470 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 1471 | +#define SQLITE_CONFIG_URI 17 /* int */ | |
| 1450 | 1472 | |
| 1451 | 1473 | /* |
| 1452 | 1474 | ** CAPI3REF: Database Connection Configuration Options |
| 1453 | 1475 | ** |
| 1454 | 1476 | ** These constants are the available integer configuration options that |
| @@ -1530,17 +1552,21 @@ | ||
| 1530 | 1552 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 1531 | 1553 | ** is another alias for the rowid. |
| 1532 | 1554 | ** |
| 1533 | 1555 | ** ^This routine returns the [rowid] of the most recent |
| 1534 | 1556 | ** successful [INSERT] into the database from the [database connection] |
| 1535 | -** in the first argument. ^If no successful [INSERT]s | |
| 1557 | +** in the first argument. ^As of SQLite version 3.7.7, this routines | |
| 1558 | +** records the last insert rowid of both ordinary tables and [virtual tables]. | |
| 1559 | +** ^If no successful [INSERT]s | |
| 1536 | 1560 | ** have ever occurred on that database connection, zero is returned. |
| 1537 | 1561 | ** |
| 1538 | -** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted | |
| 1539 | -** row is returned by this routine as long as the trigger is running. | |
| 1540 | -** But once the trigger terminates, the value returned by this routine | |
| 1541 | -** reverts to the last value inserted before the trigger fired.)^ | |
| 1562 | +** ^(If an [INSERT] occurs within a trigger or within a [virtual table] | |
| 1563 | +** method, then this routine will return the [rowid] of the inserted | |
| 1564 | +** row as long as the trigger or virtual table method is running. | |
| 1565 | +** But once the trigger or virtual table method ends, the value returned | |
| 1566 | +** by this routine reverts to what it was before the trigger or virtual | |
| 1567 | +** table method began.)^ | |
| 1542 | 1568 | ** |
| 1543 | 1569 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 1544 | 1570 | ** successful [INSERT] and does not change the value returned by this |
| 1545 | 1571 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 1546 | 1572 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2199,10 +2225,13 @@ | ||
| 2199 | 2225 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2200 | 2226 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2201 | 2227 | ** to signal SQLite whether or not the action is permitted. See the |
| 2202 | 2228 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2203 | 2229 | ** information. |
| 2230 | +** | |
| 2231 | +** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] | |
| 2232 | +** from the [sqlite3_vtab_on_conflict()] interface. | |
| 2204 | 2233 | */ |
| 2205 | 2234 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2206 | 2235 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2207 | 2236 | |
| 2208 | 2237 | /* |
| @@ -2321,11 +2350,11 @@ | ||
| 2321 | 2350 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2322 | 2351 | |
| 2323 | 2352 | /* |
| 2324 | 2353 | ** CAPI3REF: Opening A New Database Connection |
| 2325 | 2354 | ** |
| 2326 | -** ^These routines open an SQLite database file whose name is given by the | |
| 2355 | +** ^These routines open an SQLite database file as specified by the | |
| 2327 | 2356 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2328 | 2357 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2329 | 2358 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2330 | 2359 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2331 | 2360 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2348,11 +2377,11 @@ | ||
| 2348 | 2377 | ** except that it accepts two additional parameters for additional control |
| 2349 | 2378 | ** over the new database connection. ^(The flags parameter to |
| 2350 | 2379 | ** sqlite3_open_v2() can take one of |
| 2351 | 2380 | ** the following three values, optionally combined with the |
| 2352 | 2381 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2353 | -** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ | |
| 2382 | +** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ | |
| 2354 | 2383 | ** |
| 2355 | 2384 | ** <dl> |
| 2356 | 2385 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2357 | 2386 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2358 | 2387 | ** already exist, an error is returned.</dd>)^ |
| @@ -2367,13 +2396,12 @@ | ||
| 2367 | 2396 | ** it does not already exist. This is the behavior that is always used for |
| 2368 | 2397 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2369 | 2398 | ** </dl> |
| 2370 | 2399 | ** |
| 2371 | 2400 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2372 | -** combinations shown above or one of the combinations shown above combined | |
| 2373 | -** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], | |
| 2374 | -** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, | |
| 2401 | +** combinations shown above optionally combined with other | |
| 2402 | +** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] | |
| 2375 | 2403 | ** then the behavior is undefined. |
| 2376 | 2404 | ** |
| 2377 | 2405 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2378 | 2406 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2379 | 2407 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2383,10 +2411,15 @@ | ||
| 2383 | 2411 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2384 | 2412 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2385 | 2413 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2386 | 2414 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2387 | 2415 | ** participate in [shared cache mode] even if it is enabled. |
| 2416 | +** | |
| 2417 | +** ^The fourth parameter to sqlite3_open_v2() is the name of the | |
| 2418 | +** [sqlite3_vfs] object that defines the operating system interface that | |
| 2419 | +** the new database connection should use. ^If the fourth parameter is | |
| 2420 | +** a NULL pointer then the default [sqlite3_vfs] object is used. | |
| 2388 | 2421 | ** |
| 2389 | 2422 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2390 | 2423 | ** is created for the connection. ^This in-memory database will vanish when |
| 2391 | 2424 | ** the database connection is closed. Future versions of SQLite might |
| 2392 | 2425 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2396,14 +2429,115 @@ | ||
| 2396 | 2429 | ** |
| 2397 | 2430 | ** ^If the filename is an empty string, then a private, temporary |
| 2398 | 2431 | ** on-disk database will be created. ^This private database will be |
| 2399 | 2432 | ** automatically deleted as soon as the database connection is closed. |
| 2400 | 2433 | ** |
| 2401 | -** ^The fourth parameter to sqlite3_open_v2() is the name of the | |
| 2402 | -** [sqlite3_vfs] object that defines the operating system interface that | |
| 2403 | -** the new database connection should use. ^If the fourth parameter is | |
| 2404 | -** a NULL pointer then the default [sqlite3_vfs] object is used. | |
| 2434 | +** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3> | |
| 2435 | +** | |
| 2436 | +** ^If [URI filename] interpretation is enabled, and the filename argument | |
| 2437 | +** begins with "file:", then the filename is interpreted as a URI. ^URI | |
| 2438 | +** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is | |
| 2439 | +** is set in the fourth argument to sqlite3_open_v2(), or if it has | |
| 2440 | +** been enabled globally using the [SQLITE_CONFIG_URI] option with the | |
| 2441 | +** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. | |
| 2442 | +** As of SQLite version 3.7.7, URI filename interpretation is turned off | |
| 2443 | +** by default, but future releases of SQLite might enable URI filename | |
| 2444 | +** intepretation by default. See "[URI filenames]" for additional | |
| 2445 | +** information. | |
| 2446 | +** | |
| 2447 | +** URI filenames are parsed according to RFC 3986. ^If the URI contains an | |
| 2448 | +** authority, then it must be either an empty string or the string | |
| 2449 | +** "localhost". ^If the authority is not an empty string or "localhost", an | |
| 2450 | +** error is returned to the caller. ^The fragment component of a URI, if | |
| 2451 | +** present, is ignored. | |
| 2452 | +** | |
| 2453 | +** ^SQLite uses the path component of the URI as the name of the disk file | |
| 2454 | +** which contains the database. ^If the path begins with a '/' character, | |
| 2455 | +** then it is interpreted as an absolute path. ^If the path does not begin | |
| 2456 | +** with a '/' (meaning that the authority section is omitted from the URI) | |
| 2457 | +** then the path is interpreted as a relative path. | |
| 2458 | +** ^On windows, the first component of an absolute path | |
| 2459 | +** is a drive specification (e.g. "C:"). | |
| 2460 | +** | |
| 2461 | +** [[core URI query parameters]] | |
| 2462 | +** The query component of a URI may contain parameters that are interpreted | |
| 2463 | +** either by SQLite itself, or by a [VFS | custom VFS implementation]. | |
| 2464 | +** SQLite interprets the following three query parameters: | |
| 2465 | +** | |
| 2466 | +** <ul> | |
| 2467 | +** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of | |
| 2468 | +** a VFS object that provides the operating system interface that should | |
| 2469 | +** be used to access the database file on disk. ^If this option is set to | |
| 2470 | +** an empty string the default VFS object is used. ^Specifying an unknown | |
| 2471 | +** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is | |
| 2472 | +** present, then the VFS specified by the option takes precedence over | |
| 2473 | +** the value passed as the fourth parameter to sqlite3_open_v2(). | |
| 2474 | +** | |
| 2475 | +** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or | |
| 2476 | +** "rwc". Attempting to set it to any other value is an error)^. | |
| 2477 | +** ^If "ro" is specified, then the database is opened for read-only | |
| 2478 | +** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the | |
| 2479 | +** third argument to sqlite3_prepare_v2(). ^If the mode option is set to | |
| 2480 | +** "rw", then the database is opened for read-write (but not create) | |
| 2481 | +** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had | |
| 2482 | +** been set. ^Value "rwc" is equivalent to setting both | |
| 2483 | +** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is | |
| 2484 | +** used, it is an error to specify a value for the mode parameter that is | |
| 2485 | +** less restrictive than that specified by the flags passed as the third | |
| 2486 | +** parameter. | |
| 2487 | +** | |
| 2488 | +** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or | |
| 2489 | +** "private". ^Setting it to "shared" is equivalent to setting the | |
| 2490 | +** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to | |
| 2491 | +** sqlite3_open_v2(). ^Setting the cache parameter to "private" is | |
| 2492 | +** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. | |
| 2493 | +** ^If sqlite3_open_v2() is used and the "cache" parameter is present in | |
| 2494 | +** a URI filename, its value overrides any behaviour requested by setting | |
| 2495 | +** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. | |
| 2496 | +** </ul> | |
| 2497 | +** | |
| 2498 | +** ^Specifying an unknown parameter in the query component of a URI is not an | |
| 2499 | +** error. Future versions of SQLite might understand additional query | |
| 2500 | +** parameters. See "[query parameters with special meaning to SQLite]" for | |
| 2501 | +** additional information. | |
| 2502 | +** | |
| 2503 | +** [[URI filename examples]] <h3>URI filename examples</h3> | |
| 2504 | +** | |
| 2505 | +** <table border="1" align=center cellpadding=5> | |
| 2506 | +** <tr><th> URI filenames <th> Results | |
| 2507 | +** <tr><td> file:data.db <td> | |
| 2508 | +** Open the file "data.db" in the current directory. | |
| 2509 | +** <tr><td> file:/home/fred/data.db<br> | |
| 2510 | +** file:///home/fred/data.db <br> | |
| 2511 | +** file://localhost/home/fred/data.db <br> <td> | |
| 2512 | +** Open the database file "/home/fred/data.db". | |
| 2513 | +** <tr><td> file://darkstar/home/fred/data.db <td> | |
| 2514 | +** An error. "darkstar" is not a recognized authority. | |
| 2515 | +** <tr><td style="white-space:nowrap"> | |
| 2516 | +** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db | |
| 2517 | +** <td> Windows only: Open the file "data.db" on fred's desktop on drive | |
| 2518 | +** C:. Note that the %20 escaping in this example is not strictly | |
| 2519 | +** necessary - space characters can be used literally | |
| 2520 | +** in URI filenames. | |
| 2521 | +** <tr><td> file:data.db?mode=ro&cache=private <td> | |
| 2522 | +** Open file "data.db" in the current directory for read-only access. | |
| 2523 | +** Regardless of whether or not shared-cache mode is enabled by | |
| 2524 | +** default, use a private cache. | |
| 2525 | +** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td> | |
| 2526 | +** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". | |
| 2527 | +** <tr><td> file:data.db?mode=readonly <td> | |
| 2528 | +** An error. "readonly" is not a valid option for the "mode" parameter. | |
| 2529 | +** </table> | |
| 2530 | +** | |
| 2531 | +** ^URI hexadecimal escape sequences (%HH) are supported within the path and | |
| 2532 | +** query components of a URI. A hexadecimal escape sequence consists of a | |
| 2533 | +** percent sign - "%" - followed by exactly two hexadecimal digits | |
| 2534 | +** specifying an octet value. ^Before the path or query components of a | |
| 2535 | +** URI filename are interpreted, they are encoded using UTF-8 and all | |
| 2536 | +** hexadecimal escape sequences replaced by a single byte containing the | |
| 2537 | +** corresponding octet. If this process generates an invalid UTF-8 encoding, | |
| 2538 | +** the results are undefined. | |
| 2405 | 2539 | ** |
| 2406 | 2540 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 2407 | 2541 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 2408 | 2542 | ** codepage is currently defined. Filenames containing international |
| 2409 | 2543 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2421,10 +2555,30 @@ | ||
| 2421 | 2555 | const char *filename, /* Database filename (UTF-8) */ |
| 2422 | 2556 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 2423 | 2557 | int flags, /* Flags */ |
| 2424 | 2558 | const char *zVfs /* Name of VFS module to use */ |
| 2425 | 2559 | ); |
| 2560 | + | |
| 2561 | +/* | |
| 2562 | +** CAPI3REF: Obtain Values For URI Parameters | |
| 2563 | +** | |
| 2564 | +** This is a utility routine, useful to VFS implementations, that checks | |
| 2565 | +** to see if a database file was a URI that contained a specific query | |
| 2566 | +** parameter, and if so obtains the value of the query parameter. | |
| 2567 | +** | |
| 2568 | +** The zFilename argument is the filename pointer passed into the xOpen() | |
| 2569 | +** method of a VFS implementation. The zParam argument is the name of the | |
| 2570 | +** query parameter we seek. This routine returns the value of the zParam | |
| 2571 | +** parameter if it exists. If the parameter does not exist, this routine | |
| 2572 | +** returns a NULL pointer. | |
| 2573 | +** | |
| 2574 | +** If the zFilename argument to this function is not a pointer that SQLite | |
| 2575 | +** passed into the xOpen VFS method, then the behavior of this routine | |
| 2576 | +** is undefined and probably undesirable. | |
| 2577 | +*/ | |
| 2578 | +SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); | |
| 2579 | + | |
| 2426 | 2580 | |
| 2427 | 2581 | /* |
| 2428 | 2582 | ** CAPI3REF: Error Codes And Messages |
| 2429 | 2583 | ** |
| 2430 | 2584 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -2537,47 +2691,49 @@ | ||
| 2537 | 2691 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 2538 | 2692 | ** The synopsis of the meanings of the various limits is shown below. |
| 2539 | 2693 | ** Additional information is available at [limits | Limits in SQLite]. |
| 2540 | 2694 | ** |
| 2541 | 2695 | ** <dl> |
| 2542 | -** ^(<dt>SQLITE_LIMIT_LENGTH</dt> | |
| 2696 | +** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> | |
| 2543 | 2697 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 2544 | 2698 | ** |
| 2545 | -** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> | |
| 2699 | +** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> | |
| 2546 | 2700 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 2547 | 2701 | ** |
| 2548 | -** ^(<dt>SQLITE_LIMIT_COLUMN</dt> | |
| 2702 | +** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt> | |
| 2549 | 2703 | ** <dd>The maximum number of columns in a table definition or in the |
| 2550 | 2704 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 2551 | 2705 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 2552 | 2706 | ** |
| 2553 | -** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> | |
| 2707 | +** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> | |
| 2554 | 2708 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 2555 | 2709 | ** |
| 2556 | -** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> | |
| 2710 | +** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> | |
| 2557 | 2711 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 2558 | 2712 | ** |
| 2559 | -** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> | |
| 2713 | +** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> | |
| 2560 | 2714 | ** <dd>The maximum number of instructions in a virtual machine program |
| 2561 | 2715 | ** used to implement an SQL statement. This limit is not currently |
| 2562 | 2716 | ** enforced, though that might be added in some future release of |
| 2563 | 2717 | ** SQLite.</dd>)^ |
| 2564 | 2718 | ** |
| 2565 | -** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> | |
| 2719 | +** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> | |
| 2566 | 2720 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 2567 | 2721 | ** |
| 2568 | -** ^(<dt>SQLITE_LIMIT_ATTACHED</dt> | |
| 2722 | +** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt> | |
| 2569 | 2723 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 2570 | 2724 | ** |
| 2725 | +** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] | |
| 2571 | 2726 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 2572 | 2727 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 2573 | 2728 | ** [GLOB] operators.</dd>)^ |
| 2574 | 2729 | ** |
| 2730 | +** [[SQLITE_LIMIT_VARIABLE_NUMBER]] | |
| 2575 | 2731 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 2576 | 2732 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 2577 | 2733 | ** |
| 2578 | -** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> | |
| 2734 | +** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> | |
| 2579 | 2735 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 2580 | 2736 | ** </dl> |
| 2581 | 2737 | */ |
| 2582 | 2738 | #define SQLITE_LIMIT_LENGTH 0 |
| 2583 | 2739 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -4608,10 +4764,15 @@ | ||
| 4608 | 4764 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 4609 | 4765 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 4610 | 4766 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 4611 | 4767 | void **ppArg); |
| 4612 | 4768 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 4769 | + /* The methods above are in version 1 of the sqlite_module object. Those | |
| 4770 | + ** below are for version 2 and greater. */ | |
| 4771 | + int (*xSavepoint)(sqlite3_vtab *pVTab, int); | |
| 4772 | + int (*xRelease)(sqlite3_vtab *pVTab, int); | |
| 4773 | + int (*xRollbackTo)(sqlite3_vtab *pVTab, int); | |
| 4613 | 4774 | }; |
| 4614 | 4775 | |
| 4615 | 4776 | /* |
| 4616 | 4777 | ** CAPI3REF: Virtual Table Indexing Information |
| 4617 | 4778 | ** KEYWORDS: sqlite3_index_info |
| @@ -5422,11 +5583,11 @@ | ||
| 5422 | 5583 | ** |
| 5423 | 5584 | ** ^This interface is used to retrieve runtime status information |
| 5424 | 5585 | ** about the performance of SQLite, and optionally to reset various |
| 5425 | 5586 | ** highwater marks. ^The first argument is an integer code for |
| 5426 | 5587 | ** the specific parameter to measure. ^(Recognized integer codes |
| 5427 | -** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ | |
| 5588 | +** are of the form [status parameters | SQLITE_STATUS_...].)^ | |
| 5428 | 5589 | ** ^The current value of the parameter is returned into *pCurrent. |
| 5429 | 5590 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 5430 | 5591 | ** resetFlag is true, then the highest record value is reset after |
| 5431 | 5592 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 5432 | 5593 | ** value. For those parameters |
| @@ -5449,82 +5610,84 @@ | ||
| 5449 | 5610 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 5450 | 5611 | |
| 5451 | 5612 | |
| 5452 | 5613 | /* |
| 5453 | 5614 | ** CAPI3REF: Status Parameters |
| 5615 | +** KEYWORDS: {status parameters} | |
| 5454 | 5616 | ** |
| 5455 | 5617 | ** These integer constants designate various run-time status parameters |
| 5456 | 5618 | ** that can be returned by [sqlite3_status()]. |
| 5457 | 5619 | ** |
| 5458 | 5620 | ** <dl> |
| 5459 | -** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> | |
| 5621 | +** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> | |
| 5460 | 5622 | ** <dd>This parameter is the current amount of memory checked out |
| 5461 | 5623 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 5462 | 5624 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 5463 | 5625 | ** and internal memory usage by the SQLite library. Scratch memory |
| 5464 | 5626 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 5465 | 5627 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 5466 | 5628 | ** this parameter. The amount returned is the sum of the allocation |
| 5467 | 5629 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 5468 | 5630 | ** |
| 5469 | -** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> | |
| 5631 | +** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> | |
| 5470 | 5632 | ** <dd>This parameter records the largest memory allocation request |
| 5471 | 5633 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 5472 | 5634 | ** internal equivalents). Only the value returned in the |
| 5473 | 5635 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5474 | 5636 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5475 | 5637 | ** |
| 5476 | -** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> | |
| 5638 | +** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> | |
| 5477 | 5639 | ** <dd>This parameter records the number of separate memory allocations |
| 5478 | 5640 | ** currently checked out.</dd>)^ |
| 5479 | 5641 | ** |
| 5480 | -** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> | |
| 5642 | +** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> | |
| 5481 | 5643 | ** <dd>This parameter returns the number of pages used out of the |
| 5482 | 5644 | ** [pagecache memory allocator] that was configured using |
| 5483 | 5645 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 5484 | 5646 | ** value returned is in pages, not in bytes.</dd>)^ |
| 5485 | 5647 | ** |
| 5648 | +** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] | |
| 5486 | 5649 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 5487 | 5650 | ** <dd>This parameter returns the number of bytes of page cache |
| 5488 | 5651 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 5489 | 5652 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 5490 | 5653 | ** returned value includes allocations that overflowed because they |
| 5491 | 5654 | ** where too large (they were larger than the "sz" parameter to |
| 5492 | 5655 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 5493 | 5656 | ** no space was left in the page cache.</dd>)^ |
| 5494 | 5657 | ** |
| 5495 | -** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> | |
| 5658 | +** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> | |
| 5496 | 5659 | ** <dd>This parameter records the largest memory allocation request |
| 5497 | 5660 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 5498 | 5661 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5499 | 5662 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5500 | 5663 | ** |
| 5501 | -** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> | |
| 5664 | +** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> | |
| 5502 | 5665 | ** <dd>This parameter returns the number of allocations used out of the |
| 5503 | 5666 | ** [scratch memory allocator] configured using |
| 5504 | 5667 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 5505 | 5668 | ** in bytes. Since a single thread may only have one scratch allocation |
| 5506 | 5669 | ** outstanding at time, this parameter also reports the number of threads |
| 5507 | 5670 | ** using scratch memory at the same time.</dd>)^ |
| 5508 | 5671 | ** |
| 5509 | -** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> | |
| 5672 | +** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> | |
| 5510 | 5673 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 5511 | 5674 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 5512 | 5675 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 5513 | 5676 | ** returned include overflows because the requested allocation was too |
| 5514 | 5677 | ** larger (that is, because the requested allocation was larger than the |
| 5515 | 5678 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 5516 | 5679 | ** slots were available. |
| 5517 | 5680 | ** </dd>)^ |
| 5518 | 5681 | ** |
| 5519 | -** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> | |
| 5682 | +** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> | |
| 5520 | 5683 | ** <dd>This parameter records the largest memory allocation request |
| 5521 | 5684 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 5522 | 5685 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5523 | 5686 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5524 | 5687 | ** |
| 5525 | -** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> | |
| 5688 | +** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> | |
| 5526 | 5689 | ** <dd>This parameter records the deepest parser stack. It is only |
| 5527 | 5690 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 5528 | 5691 | ** </dl> |
| 5529 | 5692 | ** |
| 5530 | 5693 | ** New status parameters may be added from time to time. |
| @@ -5545,13 +5708,13 @@ | ||
| 5545 | 5708 | ** |
| 5546 | 5709 | ** ^This interface is used to retrieve runtime status information |
| 5547 | 5710 | ** about a single [database connection]. ^The first argument is the |
| 5548 | 5711 | ** database connection object to be interrogated. ^The second argument |
| 5549 | 5712 | ** is an integer constant, taken from the set of |
| 5550 | -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that | |
| 5713 | +** [SQLITE_DBSTATUS options], that | |
| 5551 | 5714 | ** determines the parameter to interrogate. The set of |
| 5552 | -** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely | |
| 5715 | +** [SQLITE_DBSTATUS options] is likely | |
| 5553 | 5716 | ** to grow in future releases of SQLite. |
| 5554 | 5717 | ** |
| 5555 | 5718 | ** ^The current value of the requested parameter is written into *pCur |
| 5556 | 5719 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 5557 | 5720 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -5564,10 +5727,11 @@ | ||
| 5564 | 5727 | */ |
| 5565 | 5728 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 5566 | 5729 | |
| 5567 | 5730 | /* |
| 5568 | 5731 | ** CAPI3REF: Status Parameters for database connections |
| 5732 | +** KEYWORDS: {SQLITE_DBSTATUS options} | |
| 5569 | 5733 | ** |
| 5570 | 5734 | ** These constants are the available integer "verbs" that can be passed as |
| 5571 | 5735 | ** the second argument to the [sqlite3_db_status()] interface. |
| 5572 | 5736 | ** |
| 5573 | 5737 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -5575,48 +5739,50 @@ | ||
| 5575 | 5739 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 5576 | 5740 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 5577 | 5741 | ** if a discontinued or unsupported verb is invoked. |
| 5578 | 5742 | ** |
| 5579 | 5743 | ** <dl> |
| 5580 | -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> | |
| 5744 | +** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> | |
| 5581 | 5745 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 5582 | 5746 | ** checked out.</dd>)^ |
| 5583 | 5747 | ** |
| 5584 | -** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> | |
| 5748 | +** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> | |
| 5585 | 5749 | ** <dd>This parameter returns the number malloc attempts that were |
| 5586 | 5750 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 5587 | 5751 | ** the current value is always zero.)^ |
| 5588 | 5752 | ** |
| 5753 | +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] | |
| 5589 | 5754 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 5590 | 5755 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5591 | 5756 | ** been satisfied using lookaside memory but failed due to the amount of |
| 5592 | 5757 | ** memory requested being larger than the lookaside slot size. |
| 5593 | 5758 | ** Only the high-water value is meaningful; |
| 5594 | 5759 | ** the current value is always zero.)^ |
| 5595 | 5760 | ** |
| 5761 | +** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] | |
| 5596 | 5762 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 5597 | 5763 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5598 | 5764 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 5599 | 5765 | ** memory already being in use. |
| 5600 | 5766 | ** Only the high-water value is meaningful; |
| 5601 | 5767 | ** the current value is always zero.)^ |
| 5602 | 5768 | ** |
| 5603 | -** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> | |
| 5769 | +** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> | |
| 5604 | 5770 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5605 | 5771 | ** memory used by all pager caches associated with the database connection.)^ |
| 5606 | 5772 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 5607 | 5773 | ** |
| 5608 | -** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> | |
| 5774 | +** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> | |
| 5609 | 5775 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5610 | 5776 | ** memory used to store the schema for all databases associated |
| 5611 | 5777 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 5612 | 5778 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 5613 | 5779 | ** schema memory is shared with other database connections due to |
| 5614 | 5780 | ** [shared cache mode] being enabled. |
| 5615 | 5781 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 5616 | 5782 | ** |
| 5617 | -** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> | |
| 5783 | +** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> | |
| 5618 | 5784 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5619 | 5785 | ** and lookaside memory used by all prepared statements associated with |
| 5620 | 5786 | ** the database connection.)^ |
| 5621 | 5787 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 5622 | 5788 | ** </dd> |
| @@ -5634,11 +5800,11 @@ | ||
| 5634 | 5800 | |
| 5635 | 5801 | /* |
| 5636 | 5802 | ** CAPI3REF: Prepared Statement Status |
| 5637 | 5803 | ** |
| 5638 | 5804 | ** ^(Each prepared statement maintains various |
| 5639 | -** [SQLITE_STMTSTATUS_SORT | counters] that measure the number | |
| 5805 | +** [SQLITE_STMTSTATUS counters] that measure the number | |
| 5640 | 5806 | ** of times it has performed specific operations.)^ These counters can |
| 5641 | 5807 | ** be used to monitor the performance characteristics of the prepared |
| 5642 | 5808 | ** statements. For example, if the number of table steps greatly exceeds |
| 5643 | 5809 | ** the number of table searches or result rows, that would tend to indicate |
| 5644 | 5810 | ** that the prepared statement is using a full table scan rather than |
| @@ -5645,11 +5811,11 @@ | ||
| 5645 | 5811 | ** an index. |
| 5646 | 5812 | ** |
| 5647 | 5813 | ** ^(This interface is used to retrieve and reset counter values from |
| 5648 | 5814 | ** a [prepared statement]. The first argument is the prepared statement |
| 5649 | 5815 | ** object to be interrogated. The second argument |
| 5650 | -** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] | |
| 5816 | +** is an integer code for a specific [SQLITE_STMTSTATUS counter] | |
| 5651 | 5817 | ** to be interrogated.)^ |
| 5652 | 5818 | ** ^The current value of the requested counter is returned. |
| 5653 | 5819 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 5654 | 5820 | ** interface call returns. |
| 5655 | 5821 | ** |
| @@ -5657,28 +5823,29 @@ | ||
| 5657 | 5823 | */ |
| 5658 | 5824 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 5659 | 5825 | |
| 5660 | 5826 | /* |
| 5661 | 5827 | ** CAPI3REF: Status Parameters for prepared statements |
| 5828 | +** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} | |
| 5662 | 5829 | ** |
| 5663 | 5830 | ** These preprocessor macros define integer codes that name counter |
| 5664 | 5831 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 5665 | 5832 | ** The meanings of the various counters are as follows: |
| 5666 | 5833 | ** |
| 5667 | 5834 | ** <dl> |
| 5668 | -** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> | |
| 5835 | +** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> | |
| 5669 | 5836 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 5670 | 5837 | ** a table as part of a full table scan. Large numbers for this counter |
| 5671 | 5838 | ** may indicate opportunities for performance improvement through |
| 5672 | 5839 | ** careful use of indices.</dd> |
| 5673 | 5840 | ** |
| 5674 | -** <dt>SQLITE_STMTSTATUS_SORT</dt> | |
| 5841 | +** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt> | |
| 5675 | 5842 | ** <dd>^This is the number of sort operations that have occurred. |
| 5676 | 5843 | ** A non-zero value in this counter may indicate an opportunity to |
| 5677 | 5844 | ** improvement performance through careful use of indices.</dd> |
| 5678 | 5845 | ** |
| 5679 | -** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> | |
| 5846 | +** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> | |
| 5680 | 5847 | ** <dd>^This is the number of rows inserted into transient indices that |
| 5681 | 5848 | ** were created automatically in order to help joins run faster. |
| 5682 | 5849 | ** A non-zero value in this counter may indicate an opportunity to |
| 5683 | 5850 | ** improvement performance by adding permanent indices that do not |
| 5684 | 5851 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -5725,10 +5892,11 @@ | ||
| 5725 | 5892 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 5726 | 5893 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 5727 | 5894 | ** the application may discard the parameter after the call to |
| 5728 | 5895 | ** [sqlite3_config()] returns.)^ |
| 5729 | 5896 | ** |
| 5897 | +** [[the xInit() page cache method]] | |
| 5730 | 5898 | ** ^(The xInit() method is called once for each effective |
| 5731 | 5899 | ** call to [sqlite3_initialize()])^ |
| 5732 | 5900 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 5733 | 5901 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 5734 | 5902 | ** The intent of the xInit() method is to set up global data structures |
| @@ -5735,10 +5903,11 @@ | ||
| 5735 | 5903 | ** required by the custom page cache implementation. |
| 5736 | 5904 | ** ^(If the xInit() method is NULL, then the |
| 5737 | 5905 | ** built-in default page cache is used instead of the application defined |
| 5738 | 5906 | ** page cache.)^ |
| 5739 | 5907 | ** |
| 5908 | +** [[the xShutdown() page cache method]] | |
| 5740 | 5909 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 5741 | 5910 | ** It can be used to clean up |
| 5742 | 5911 | ** any outstanding resources before process shutdown, if required. |
| 5743 | 5912 | ** ^The xShutdown() method may be NULL. |
| 5744 | 5913 | ** |
| @@ -5749,10 +5918,11 @@ | ||
| 5749 | 5918 | ** in multithreaded applications. |
| 5750 | 5919 | ** |
| 5751 | 5920 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 5752 | 5921 | ** call to xShutdown(). |
| 5753 | 5922 | ** |
| 5923 | +** [[the xCreate() page cache methods]] | |
| 5754 | 5924 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 5755 | 5925 | ** SQLite will typically create one cache instance for each open database file, |
| 5756 | 5926 | ** though this is not guaranteed. ^The |
| 5757 | 5927 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 5758 | 5928 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -5773,20 +5943,23 @@ | ||
| 5773 | 5943 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 5774 | 5944 | ** false will always have the "discard" flag set to true. |
| 5775 | 5945 | ** ^Hence, a cache created with bPurgeable false will |
| 5776 | 5946 | ** never contain any unpinned pages. |
| 5777 | 5947 | ** |
| 5948 | +** [[the xCachesize() page cache method]] | |
| 5778 | 5949 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 5779 | 5950 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 5780 | 5951 | ** instance passed as the first argument. This is the value configured using |
| 5781 | 5952 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 5782 | 5953 | ** parameter, the implementation is not required to do anything with this |
| 5783 | 5954 | ** value; it is advisory only. |
| 5784 | 5955 | ** |
| 5956 | +** [[the xPagecount() page cache methods]] | |
| 5785 | 5957 | ** The xPagecount() method must return the number of pages currently |
| 5786 | 5958 | ** stored in the cache, both pinned and unpinned. |
| 5787 | 5959 | ** |
| 5960 | +** [[the xFetch() page cache methods]] | |
| 5788 | 5961 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 5789 | 5962 | ** the page, or a NULL pointer. |
| 5790 | 5963 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 5791 | 5964 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 5792 | 5965 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -5811,10 +5984,11 @@ | ||
| 5811 | 5984 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 5812 | 5985 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 5813 | 5986 | ** attempt to unpin one or more cache pages by spilling the content of |
| 5814 | 5987 | ** pinned pages to disk and synching the operating system disk cache. |
| 5815 | 5988 | ** |
| 5989 | +** [[the xUnpin() page cache method]] | |
| 5816 | 5990 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 5817 | 5991 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 5818 | 5992 | ** then the page must be evicted from the cache. |
| 5819 | 5993 | ** ^If the discard parameter is |
| 5820 | 5994 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -5823,10 +5997,11 @@ | ||
| 5823 | 5997 | ** |
| 5824 | 5998 | ** The cache must not perform any reference counting. A single |
| 5825 | 5999 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 5826 | 6000 | ** to xFetch(). |
| 5827 | 6001 | ** |
| 6002 | +** [[the xRekey() page cache methods]] | |
| 5828 | 6003 | ** The xRekey() method is used to change the key value associated with the |
| 5829 | 6004 | ** page passed as the second argument. If the cache |
| 5830 | 6005 | ** previously contains an entry associated with newKey, it must be |
| 5831 | 6006 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 5832 | 6007 | ** to be pinned. |
| @@ -5835,10 +6010,11 @@ | ||
| 5835 | 6010 | ** existing cache entries with page numbers (keys) greater than or equal |
| 5836 | 6011 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 5837 | 6012 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 5838 | 6013 | ** they can be safely discarded. |
| 5839 | 6014 | ** |
| 6015 | +** [[the xDestroy() page cache method]] | |
| 5840 | 6016 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 5841 | 6017 | ** All resources associated with the specified cache should be freed. ^After |
| 5842 | 6018 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 5843 | 6019 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 5844 | 6020 | ** functions. |
| @@ -5897,11 +6073,11 @@ | ||
| 5897 | 6073 | ** associated with the backup operation. |
| 5898 | 6074 | ** </ol>)^ |
| 5899 | 6075 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 5900 | 6076 | ** successful call to sqlite3_backup_init(). |
| 5901 | 6077 | ** |
| 5902 | -** <b>sqlite3_backup_init()</b> | |
| 6078 | +** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b> | |
| 5903 | 6079 | ** |
| 5904 | 6080 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 5905 | 6081 | ** [database connection] associated with the destination database |
| 5906 | 6082 | ** and the database name, respectively. |
| 5907 | 6083 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -5924,11 +6100,11 @@ | ||
| 5924 | 6100 | ** [sqlite3_backup] object. |
| 5925 | 6101 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 5926 | 6102 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 5927 | 6103 | ** operation. |
| 5928 | 6104 | ** |
| 5929 | -** <b>sqlite3_backup_step()</b> | |
| 6105 | +** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b> | |
| 5930 | 6106 | ** |
| 5931 | 6107 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 5932 | 6108 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 5933 | 6109 | ** ^If N is negative, all remaining source pages are copied. |
| 5934 | 6110 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -5981,11 +6157,11 @@ | ||
| 5981 | 6157 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 5982 | 6158 | ** database is modified by the using the same database connection as is used |
| 5983 | 6159 | ** by the backup operation, then the backup database is automatically |
| 5984 | 6160 | ** updated at the same time. |
| 5985 | 6161 | ** |
| 5986 | -** <b>sqlite3_backup_finish()</b> | |
| 6162 | +** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b> | |
| 5987 | 6163 | ** |
| 5988 | 6164 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 5989 | 6165 | ** application wishes to abandon the backup operation, the application |
| 5990 | 6166 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 5991 | 6167 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6004,11 +6180,12 @@ | ||
| 6004 | 6180 | ** |
| 6005 | 6181 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6006 | 6182 | ** is not a permanent error and does not affect the return value of |
| 6007 | 6183 | ** sqlite3_backup_finish(). |
| 6008 | 6184 | ** |
| 6009 | -** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b> | |
| 6185 | +** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] | |
| 6186 | +** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> | |
| 6010 | 6187 | ** |
| 6011 | 6188 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6012 | 6189 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6013 | 6190 | ** up and the total number of pages in the source database file. |
| 6014 | 6191 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6389,10 +6566,97 @@ | ||
| 6389 | 6566 | ** each of these values. |
| 6390 | 6567 | */ |
| 6391 | 6568 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 6392 | 6569 | #define SQLITE_CHECKPOINT_FULL 1 |
| 6393 | 6570 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 6571 | + | |
| 6572 | +/* | |
| 6573 | +** CAPI3REF: Virtual Table Interface Configuration | |
| 6574 | +** | |
| 6575 | +** This function may be called by either the [xConnect] or [xCreate] method | |
| 6576 | +** of a [virtual table] implementation to configure | |
| 6577 | +** various facets of the virtual table interface. | |
| 6578 | +** | |
| 6579 | +** If this interface is invoked outside the context of an xConnect or | |
| 6580 | +** xCreate virtual table method then the behavior is undefined. | |
| 6581 | +** | |
| 6582 | +** At present, there is only one option that may be configured using | |
| 6583 | +** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options | |
| 6584 | +** may be added in the future. | |
| 6585 | +*/ | |
| 6586 | +SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); | |
| 6587 | + | |
| 6588 | +/* | |
| 6589 | +** CAPI3REF: Virtual Table Configuration Options | |
| 6590 | +** | |
| 6591 | +** These macros define the various options to the | |
| 6592 | +** [sqlite3_vtab_config()] interface that [virtual table] implementations | |
| 6593 | +** can use to customize and optimize their behavior. | |
| 6594 | +** | |
| 6595 | +** <dl> | |
| 6596 | +** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT | |
| 6597 | +** <dd>Calls of the form | |
| 6598 | +** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, | |
| 6599 | +** where X is an integer. If X is zero, then the [virtual table] whose | |
| 6600 | +** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not | |
| 6601 | +** support constraints. In this configuration (which is the default) if | |
| 6602 | +** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire | |
| 6603 | +** statement is rolled back as if [ON CONFLICT | OR ABORT] had been | |
| 6604 | +** specified as part of the users SQL statement, regardless of the actual | |
| 6605 | +** ON CONFLICT mode specified. | |
| 6606 | +** | |
| 6607 | +** If X is non-zero, then the virtual table implementation guarantees | |
| 6608 | +** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before | |
| 6609 | +** any modifications to internal or persistent data structures have been made. | |
| 6610 | +** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite | |
| 6611 | +** is able to roll back a statement or database transaction, and abandon | |
| 6612 | +** or continue processing the current SQL statement as appropriate. | |
| 6613 | +** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns | |
| 6614 | +** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode | |
| 6615 | +** had been ABORT. | |
| 6616 | +** | |
| 6617 | +** Virtual table implementations that are required to handle OR REPLACE | |
| 6618 | +** must do so within the [xUpdate] method. If a call to the | |
| 6619 | +** [sqlite3_vtab_on_conflict()] function indicates that the current ON | |
| 6620 | +** CONFLICT policy is REPLACE, the virtual table implementation should | |
| 6621 | +** silently replace the appropriate rows within the xUpdate callback and | |
| 6622 | +** return SQLITE_OK. Or, if this is not possible, it may return | |
| 6623 | +** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT | |
| 6624 | +** constraint handling. | |
| 6625 | +** </dl> | |
| 6626 | +*/ | |
| 6627 | +#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 | |
| 6628 | + | |
| 6629 | +/* | |
| 6630 | +** CAPI3REF: Determine The Virtual Table Conflict Policy | |
| 6631 | +** | |
| 6632 | +** This function may only be called from within a call to the [xUpdate] method | |
| 6633 | +** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The | |
| 6634 | +** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], | |
| 6635 | +** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode | |
| 6636 | +** of the SQL statement that triggered the call to the [xUpdate] method of the | |
| 6637 | +** [virtual table]. | |
| 6638 | +*/ | |
| 6639 | +SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); | |
| 6640 | + | |
| 6641 | +/* | |
| 6642 | +** CAPI3REF: Conflict resolution modes | |
| 6643 | +** | |
| 6644 | +** These constants are returned by [sqlite3_vtab_on_conflict()] to | |
| 6645 | +** inform a [virtual table] implementation what the [ON CONFLICT] mode | |
| 6646 | +** is for the SQL statement being evaluated. | |
| 6647 | +** | |
| 6648 | +** Note that the [SQLITE_IGNORE] constant is also used as a potential | |
| 6649 | +** return value from the [sqlite3_set_authorizer()] callback and that | |
| 6650 | +** [SQLITE_ABORT] is also a [result code]. | |
| 6651 | +*/ | |
| 6652 | +#define SQLITE_ROLLBACK 1 | |
| 6653 | +/* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ | |
| 6654 | +#define SQLITE_FAIL 3 | |
| 6655 | +/* #define SQLITE_ABORT 4 // Also an error code */ | |
| 6656 | +#define SQLITE_REPLACE 5 | |
| 6657 | + | |
| 6394 | 6658 | |
| 6395 | 6659 | |
| 6396 | 6660 | /* |
| 6397 | 6661 | ** Undo the hack that converts floating point types to integer for |
| 6398 | 6662 | ** builds on processors without floating point support. |
| 6399 | 6663 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -105,13 +105,13 @@ | |
| 105 | ** |
| 106 | ** See also: [sqlite3_libversion()], |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.6" |
| 111 | #define SQLITE_VERSION_NUMBER 3007006 |
| 112 | #define SQLITE_SOURCE_ID "2011-04-12 01:58:40 f9d43fa363d54beab6f45db005abac0a7c0c47a7" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -373,11 +373,12 @@ | |
| 373 | ** Many SQLite functions return an integer result code from the set shown |
| 374 | ** here in order to indicates success or failure. |
| 375 | ** |
| 376 | ** New error codes may be added in future versions of SQLite. |
| 377 | ** |
| 378 | ** See also: [SQLITE_IOERR_READ | extended result codes] |
| 379 | */ |
| 380 | #define SQLITE_OK 0 /* Successful result */ |
| 381 | /* beginning-of-error-codes */ |
| 382 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 383 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -450,28 +451,31 @@ | |
| 450 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 451 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 452 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 453 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 454 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 455 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 456 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 457 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 458 | |
| 459 | /* |
| 460 | ** CAPI3REF: Flags For File Open Operations |
| 461 | ** |
| 462 | ** These bit values are intended for use in the |
| 463 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 464 | ** in the 4th parameter to the xOpen method of the |
| 465 | ** [sqlite3_vfs] object. |
| 466 | */ |
| 467 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 468 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 469 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 470 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 471 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 472 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 473 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 474 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 475 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 476 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 477 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -578,21 +582,22 @@ | |
| 578 | }; |
| 579 | |
| 580 | /* |
| 581 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 582 | ** |
| 583 | ** Every file opened by the [sqlite3_vfs] xOpen method populates an |
| 584 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 585 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 586 | ** This object defines the methods used to perform various operations |
| 587 | ** against the open file represented by the [sqlite3_file] object. |
| 588 | ** |
| 589 | ** If the xOpen method sets the sqlite3_file.pMethods element |
| 590 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 591 | ** may be invoked even if the xOpen reported that it failed. The |
| 592 | ** only way to prevent a call to xClose following a failed xOpen |
| 593 | ** is for the xOpen to set the sqlite3_file.pMethods element to NULL. |
| 594 | ** |
| 595 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 596 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 597 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 598 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -757,10 +762,11 @@ | |
| 757 | */ |
| 758 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 759 | |
| 760 | /* |
| 761 | ** CAPI3REF: OS Interface Object |
| 762 | ** |
| 763 | ** An instance of the sqlite3_vfs object defines the interface between |
| 764 | ** the SQLite core and the underlying operating system. The "vfs" |
| 765 | ** in the name of the object stands for "virtual file system". |
| 766 | ** |
| @@ -789,10 +795,11 @@ | |
| 789 | ** object once the object has been registered. |
| 790 | ** |
| 791 | ** The zName field holds the name of the VFS module. The name must |
| 792 | ** be unique across all VFS modules. |
| 793 | ** |
| 794 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 795 | ** is either a NULL pointer or string obtained |
| 796 | ** from xFullPathname() with an optional suffix added. |
| 797 | ** ^If a suffix is added to the zFilename parameter, it will |
| 798 | ** consist of a single "-" character followed by no more than |
| @@ -866,10 +873,11 @@ | |
| 866 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 867 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 868 | ** element will be valid after xOpen returns regardless of the success |
| 869 | ** or failure of the xOpen call. |
| 870 | ** |
| 871 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 872 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 873 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 874 | ** to test whether a file is at least readable. The file can be a |
| 875 | ** directory. |
| @@ -1112,13 +1120,13 @@ | |
| 1112 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1113 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1114 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1115 | ** |
| 1116 | ** The first argument to sqlite3_config() is an integer |
| 1117 | ** [SQLITE_CONFIG_SINGLETHREAD | configuration option] that determines |
| 1118 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1119 | ** vary depending on the [SQLITE_CONFIG_SINGLETHREAD | configuration option] |
| 1120 | ** in the first argument. |
| 1121 | ** |
| 1122 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1123 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1124 | ** then this routine returns a non-zero [error code]. |
| @@ -1224,10 +1232,11 @@ | |
| 1224 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1225 | }; |
| 1226 | |
| 1227 | /* |
| 1228 | ** CAPI3REF: Configuration Options |
| 1229 | ** |
| 1230 | ** These constants are the available integer configuration options that |
| 1231 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1232 | ** |
| 1233 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1236,11 +1245,11 @@ | |
| 1236 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1237 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1238 | ** is invoked. |
| 1239 | ** |
| 1240 | ** <dl> |
| 1241 | ** <dt>SQLITE_CONFIG_SINGLETHREAD</dt> |
| 1242 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1243 | ** [threading mode] to Single-thread. In other words, it disables |
| 1244 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1245 | ** by a single thread. ^If SQLite is compiled with |
| 1246 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1247,11 +1256,11 @@ | |
| 1247 | ** it is not possible to change the [threading mode] from its default |
| 1248 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1249 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1250 | ** configuration option.</dd> |
| 1251 | ** |
| 1252 | ** <dt>SQLITE_CONFIG_MULTITHREAD</dt> |
| 1253 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1254 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1255 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1256 | ** The application is responsible for serializing access to |
| 1257 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1261,11 +1270,11 @@ | |
| 1261 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1262 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1263 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1264 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1265 | ** |
| 1266 | ** <dt>SQLITE_CONFIG_SERIALIZED</dt> |
| 1267 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1268 | ** [threading mode] to Serialized. In other words, this option enables |
| 1269 | ** all mutexes including the recursive |
| 1270 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1271 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1277,27 +1286,27 @@ | |
| 1277 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1278 | ** it is not possible to set the Serialized [threading mode] and |
| 1279 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1280 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1281 | ** |
| 1282 | ** <dt>SQLITE_CONFIG_MALLOC</dt> |
| 1283 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1284 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1285 | ** alternative low-level memory allocation routines to be used in place of |
| 1286 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1287 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1288 | ** before the [sqlite3_config()] call returns.</dd> |
| 1289 | ** |
| 1290 | ** <dt>SQLITE_CONFIG_GETMALLOC</dt> |
| 1291 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1292 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1293 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1294 | ** This option can be used to overload the default memory allocation |
| 1295 | ** routines with a wrapper that simulations memory allocation failure or |
| 1296 | ** tracks memory usage, for example. </dd> |
| 1297 | ** |
| 1298 | ** <dt>SQLITE_CONFIG_MEMSTATUS</dt> |
| 1299 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1300 | ** boolean, which enables or disables the collection of memory allocation |
| 1301 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1302 | ** following SQLite interfaces become non-operational: |
| 1303 | ** <ul> |
| @@ -1309,11 +1318,11 @@ | |
| 1309 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1310 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1311 | ** allocation statistics are disabled by default. |
| 1312 | ** </dd> |
| 1313 | ** |
| 1314 | ** <dt>SQLITE_CONFIG_SCRATCH</dt> |
| 1315 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1316 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1317 | ** aligned memory buffer from which the scratch allocations will be |
| 1318 | ** drawn, the size of each scratch allocation (sz), |
| 1319 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1325,11 +1334,11 @@ | |
| 1325 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1326 | ** times the database page size. ^If SQLite needs needs additional |
| 1327 | ** scratch memory beyond what is provided by this configuration option, then |
| 1328 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1329 | ** |
| 1330 | ** <dt>SQLITE_CONFIG_PAGECACHE</dt> |
| 1331 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1332 | ** the database page cache with the default page cache implemenation. |
| 1333 | ** This configuration should not be used if an application-define page |
| 1334 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1335 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1346,11 +1355,11 @@ | |
| 1346 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1347 | ** The pointer in the first argument must |
| 1348 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1349 | ** will be undefined.</dd> |
| 1350 | ** |
| 1351 | ** <dt>SQLITE_CONFIG_HEAP</dt> |
| 1352 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1353 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1354 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1355 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1356 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1363,11 +1372,11 @@ | |
| 1363 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1364 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1365 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1366 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1367 | ** |
| 1368 | ** <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1369 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1370 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1371 | ** alternative low-level mutex routines to be used in place |
| 1372 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1373 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1375,11 +1384,11 @@ | |
| 1375 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1376 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1377 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1378 | ** return [SQLITE_ERROR].</dd> |
| 1379 | ** |
| 1380 | ** <dt>SQLITE_CONFIG_GETMUTEX</dt> |
| 1381 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1382 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1383 | ** [sqlite3_mutex_methods] |
| 1384 | ** structure is filled with the currently defined mutex routines.)^ |
| 1385 | ** This option can be used to overload the default mutex allocation |
| @@ -1388,32 +1397,32 @@ | |
| 1388 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1389 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1390 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1391 | ** return [SQLITE_ERROR].</dd> |
| 1392 | ** |
| 1393 | ** <dt>SQLITE_CONFIG_LOOKASIDE</dt> |
| 1394 | ** <dd> ^(This option takes two arguments that determine the default |
| 1395 | ** memory allocation for the lookaside memory allocator on each |
| 1396 | ** [database connection]. The first argument is the |
| 1397 | ** size of each lookaside buffer slot and the second is the number of |
| 1398 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1399 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1400 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1401 | ** configuration on individual connections.)^ </dd> |
| 1402 | ** |
| 1403 | ** <dt>SQLITE_CONFIG_PCACHE</dt> |
| 1404 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1405 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1406 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1407 | ** object and uses it for page cache memory allocations.</dd> |
| 1408 | ** |
| 1409 | ** <dt>SQLITE_CONFIG_GETPCACHE</dt> |
| 1410 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1411 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1412 | ** page cache implementation into that object.)^ </dd> |
| 1413 | ** |
| 1414 | ** <dt>SQLITE_CONFIG_LOG</dt> |
| 1415 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1416 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1417 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1418 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1419 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1427,10 +1436,22 @@ | |
| 1427 | ** The SQLite logging interface is not reentrant; the logger function |
| 1428 | ** supplied by the application must not invoke any SQLite interface. |
| 1429 | ** In a multi-threaded application, the application-defined logger |
| 1430 | ** function must be threadsafe. </dd> |
| 1431 | ** |
| 1432 | ** </dl> |
| 1433 | */ |
| 1434 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1435 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 1436 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1445,10 +1466,11 @@ | |
| 1445 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 1446 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 1447 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 1448 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 1449 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 1450 | |
| 1451 | /* |
| 1452 | ** CAPI3REF: Database Connection Configuration Options |
| 1453 | ** |
| 1454 | ** These constants are the available integer configuration options that |
| @@ -1530,17 +1552,21 @@ | |
| 1530 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 1531 | ** is another alias for the rowid. |
| 1532 | ** |
| 1533 | ** ^This routine returns the [rowid] of the most recent |
| 1534 | ** successful [INSERT] into the database from the [database connection] |
| 1535 | ** in the first argument. ^If no successful [INSERT]s |
| 1536 | ** have ever occurred on that database connection, zero is returned. |
| 1537 | ** |
| 1538 | ** ^(If an [INSERT] occurs within a trigger, then the [rowid] of the inserted |
| 1539 | ** row is returned by this routine as long as the trigger is running. |
| 1540 | ** But once the trigger terminates, the value returned by this routine |
| 1541 | ** reverts to the last value inserted before the trigger fired.)^ |
| 1542 | ** |
| 1543 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 1544 | ** successful [INSERT] and does not change the value returned by this |
| 1545 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 1546 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2199,10 +2225,13 @@ | |
| 2199 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2200 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2201 | ** to signal SQLite whether or not the action is permitted. See the |
| 2202 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2203 | ** information. |
| 2204 | */ |
| 2205 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2206 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2207 | |
| 2208 | /* |
| @@ -2321,11 +2350,11 @@ | |
| 2321 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2322 | |
| 2323 | /* |
| 2324 | ** CAPI3REF: Opening A New Database Connection |
| 2325 | ** |
| 2326 | ** ^These routines open an SQLite database file whose name is given by the |
| 2327 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2328 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2329 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2330 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2331 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2348,11 +2377,11 @@ | |
| 2348 | ** except that it accepts two additional parameters for additional control |
| 2349 | ** over the new database connection. ^(The flags parameter to |
| 2350 | ** sqlite3_open_v2() can take one of |
| 2351 | ** the following three values, optionally combined with the |
| 2352 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2353 | ** and/or [SQLITE_OPEN_PRIVATECACHE] flags:)^ |
| 2354 | ** |
| 2355 | ** <dl> |
| 2356 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2357 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2358 | ** already exist, an error is returned.</dd>)^ |
| @@ -2367,13 +2396,12 @@ | |
| 2367 | ** it does not already exist. This is the behavior that is always used for |
| 2368 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2369 | ** </dl> |
| 2370 | ** |
| 2371 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2372 | ** combinations shown above or one of the combinations shown above combined |
| 2373 | ** with the [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], |
| 2374 | ** [SQLITE_OPEN_SHAREDCACHE] and/or [SQLITE_OPEN_PRIVATECACHE] flags, |
| 2375 | ** then the behavior is undefined. |
| 2376 | ** |
| 2377 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2378 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2379 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2383,10 +2411,15 @@ | |
| 2383 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2384 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2385 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2386 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2387 | ** participate in [shared cache mode] even if it is enabled. |
| 2388 | ** |
| 2389 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2390 | ** is created for the connection. ^This in-memory database will vanish when |
| 2391 | ** the database connection is closed. Future versions of SQLite might |
| 2392 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2396,14 +2429,115 @@ | |
| 2396 | ** |
| 2397 | ** ^If the filename is an empty string, then a private, temporary |
| 2398 | ** on-disk database will be created. ^This private database will be |
| 2399 | ** automatically deleted as soon as the database connection is closed. |
| 2400 | ** |
| 2401 | ** ^The fourth parameter to sqlite3_open_v2() is the name of the |
| 2402 | ** [sqlite3_vfs] object that defines the operating system interface that |
| 2403 | ** the new database connection should use. ^If the fourth parameter is |
| 2404 | ** a NULL pointer then the default [sqlite3_vfs] object is used. |
| 2405 | ** |
| 2406 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 2407 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 2408 | ** codepage is currently defined. Filenames containing international |
| 2409 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2421,10 +2555,30 @@ | |
| 2421 | const char *filename, /* Database filename (UTF-8) */ |
| 2422 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 2423 | int flags, /* Flags */ |
| 2424 | const char *zVfs /* Name of VFS module to use */ |
| 2425 | ); |
| 2426 | |
| 2427 | /* |
| 2428 | ** CAPI3REF: Error Codes And Messages |
| 2429 | ** |
| 2430 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -2537,47 +2691,49 @@ | |
| 2537 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 2538 | ** The synopsis of the meanings of the various limits is shown below. |
| 2539 | ** Additional information is available at [limits | Limits in SQLite]. |
| 2540 | ** |
| 2541 | ** <dl> |
| 2542 | ** ^(<dt>SQLITE_LIMIT_LENGTH</dt> |
| 2543 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 2544 | ** |
| 2545 | ** ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> |
| 2546 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 2547 | ** |
| 2548 | ** ^(<dt>SQLITE_LIMIT_COLUMN</dt> |
| 2549 | ** <dd>The maximum number of columns in a table definition or in the |
| 2550 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 2551 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 2552 | ** |
| 2553 | ** ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 2554 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 2555 | ** |
| 2556 | ** ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> |
| 2557 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 2558 | ** |
| 2559 | ** ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> |
| 2560 | ** <dd>The maximum number of instructions in a virtual machine program |
| 2561 | ** used to implement an SQL statement. This limit is not currently |
| 2562 | ** enforced, though that might be added in some future release of |
| 2563 | ** SQLite.</dd>)^ |
| 2564 | ** |
| 2565 | ** ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> |
| 2566 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 2567 | ** |
| 2568 | ** ^(<dt>SQLITE_LIMIT_ATTACHED</dt> |
| 2569 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 2570 | ** |
| 2571 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 2572 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 2573 | ** [GLOB] operators.</dd>)^ |
| 2574 | ** |
| 2575 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 2576 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 2577 | ** |
| 2578 | ** ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 2579 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 2580 | ** </dl> |
| 2581 | */ |
| 2582 | #define SQLITE_LIMIT_LENGTH 0 |
| 2583 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -4608,10 +4764,15 @@ | |
| 4608 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 4609 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 4610 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 4611 | void **ppArg); |
| 4612 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 4613 | }; |
| 4614 | |
| 4615 | /* |
| 4616 | ** CAPI3REF: Virtual Table Indexing Information |
| 4617 | ** KEYWORDS: sqlite3_index_info |
| @@ -5422,11 +5583,11 @@ | |
| 5422 | ** |
| 5423 | ** ^This interface is used to retrieve runtime status information |
| 5424 | ** about the performance of SQLite, and optionally to reset various |
| 5425 | ** highwater marks. ^The first argument is an integer code for |
| 5426 | ** the specific parameter to measure. ^(Recognized integer codes |
| 5427 | ** are of the form [SQLITE_STATUS_MEMORY_USED | SQLITE_STATUS_...].)^ |
| 5428 | ** ^The current value of the parameter is returned into *pCurrent. |
| 5429 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 5430 | ** resetFlag is true, then the highest record value is reset after |
| 5431 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 5432 | ** value. For those parameters |
| @@ -5449,82 +5610,84 @@ | |
| 5449 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 5450 | |
| 5451 | |
| 5452 | /* |
| 5453 | ** CAPI3REF: Status Parameters |
| 5454 | ** |
| 5455 | ** These integer constants designate various run-time status parameters |
| 5456 | ** that can be returned by [sqlite3_status()]. |
| 5457 | ** |
| 5458 | ** <dl> |
| 5459 | ** ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> |
| 5460 | ** <dd>This parameter is the current amount of memory checked out |
| 5461 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 5462 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 5463 | ** and internal memory usage by the SQLite library. Scratch memory |
| 5464 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 5465 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 5466 | ** this parameter. The amount returned is the sum of the allocation |
| 5467 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 5468 | ** |
| 5469 | ** ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> |
| 5470 | ** <dd>This parameter records the largest memory allocation request |
| 5471 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 5472 | ** internal equivalents). Only the value returned in the |
| 5473 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5474 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5475 | ** |
| 5476 | ** ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> |
| 5477 | ** <dd>This parameter records the number of separate memory allocations |
| 5478 | ** currently checked out.</dd>)^ |
| 5479 | ** |
| 5480 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> |
| 5481 | ** <dd>This parameter returns the number of pages used out of the |
| 5482 | ** [pagecache memory allocator] that was configured using |
| 5483 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 5484 | ** value returned is in pages, not in bytes.</dd>)^ |
| 5485 | ** |
| 5486 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 5487 | ** <dd>This parameter returns the number of bytes of page cache |
| 5488 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 5489 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 5490 | ** returned value includes allocations that overflowed because they |
| 5491 | ** where too large (they were larger than the "sz" parameter to |
| 5492 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 5493 | ** no space was left in the page cache.</dd>)^ |
| 5494 | ** |
| 5495 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> |
| 5496 | ** <dd>This parameter records the largest memory allocation request |
| 5497 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 5498 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5499 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5500 | ** |
| 5501 | ** ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> |
| 5502 | ** <dd>This parameter returns the number of allocations used out of the |
| 5503 | ** [scratch memory allocator] configured using |
| 5504 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 5505 | ** in bytes. Since a single thread may only have one scratch allocation |
| 5506 | ** outstanding at time, this parameter also reports the number of threads |
| 5507 | ** using scratch memory at the same time.</dd>)^ |
| 5508 | ** |
| 5509 | ** ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> |
| 5510 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 5511 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 5512 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 5513 | ** returned include overflows because the requested allocation was too |
| 5514 | ** larger (that is, because the requested allocation was larger than the |
| 5515 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 5516 | ** slots were available. |
| 5517 | ** </dd>)^ |
| 5518 | ** |
| 5519 | ** ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> |
| 5520 | ** <dd>This parameter records the largest memory allocation request |
| 5521 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 5522 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5523 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5524 | ** |
| 5525 | ** ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> |
| 5526 | ** <dd>This parameter records the deepest parser stack. It is only |
| 5527 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 5528 | ** </dl> |
| 5529 | ** |
| 5530 | ** New status parameters may be added from time to time. |
| @@ -5545,13 +5708,13 @@ | |
| 5545 | ** |
| 5546 | ** ^This interface is used to retrieve runtime status information |
| 5547 | ** about a single [database connection]. ^The first argument is the |
| 5548 | ** database connection object to be interrogated. ^The second argument |
| 5549 | ** is an integer constant, taken from the set of |
| 5550 | ** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros, that |
| 5551 | ** determines the parameter to interrogate. The set of |
| 5552 | ** [SQLITE_DBSTATUS_LOOKASIDE_USED | SQLITE_DBSTATUS_*] macros is likely |
| 5553 | ** to grow in future releases of SQLite. |
| 5554 | ** |
| 5555 | ** ^The current value of the requested parameter is written into *pCur |
| 5556 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 5557 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -5564,10 +5727,11 @@ | |
| 5564 | */ |
| 5565 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 5566 | |
| 5567 | /* |
| 5568 | ** CAPI3REF: Status Parameters for database connections |
| 5569 | ** |
| 5570 | ** These constants are the available integer "verbs" that can be passed as |
| 5571 | ** the second argument to the [sqlite3_db_status()] interface. |
| 5572 | ** |
| 5573 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -5575,48 +5739,50 @@ | |
| 5575 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 5576 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 5577 | ** if a discontinued or unsupported verb is invoked. |
| 5578 | ** |
| 5579 | ** <dl> |
| 5580 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> |
| 5581 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 5582 | ** checked out.</dd>)^ |
| 5583 | ** |
| 5584 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> |
| 5585 | ** <dd>This parameter returns the number malloc attempts that were |
| 5586 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 5587 | ** the current value is always zero.)^ |
| 5588 | ** |
| 5589 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 5590 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5591 | ** been satisfied using lookaside memory but failed due to the amount of |
| 5592 | ** memory requested being larger than the lookaside slot size. |
| 5593 | ** Only the high-water value is meaningful; |
| 5594 | ** the current value is always zero.)^ |
| 5595 | ** |
| 5596 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 5597 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5598 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 5599 | ** memory already being in use. |
| 5600 | ** Only the high-water value is meaningful; |
| 5601 | ** the current value is always zero.)^ |
| 5602 | ** |
| 5603 | ** ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> |
| 5604 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5605 | ** memory used by all pager caches associated with the database connection.)^ |
| 5606 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 5607 | ** |
| 5608 | ** ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> |
| 5609 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5610 | ** memory used to store the schema for all databases associated |
| 5611 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 5612 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 5613 | ** schema memory is shared with other database connections due to |
| 5614 | ** [shared cache mode] being enabled. |
| 5615 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 5616 | ** |
| 5617 | ** ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> |
| 5618 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5619 | ** and lookaside memory used by all prepared statements associated with |
| 5620 | ** the database connection.)^ |
| 5621 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 5622 | ** </dd> |
| @@ -5634,11 +5800,11 @@ | |
| 5634 | |
| 5635 | /* |
| 5636 | ** CAPI3REF: Prepared Statement Status |
| 5637 | ** |
| 5638 | ** ^(Each prepared statement maintains various |
| 5639 | ** [SQLITE_STMTSTATUS_SORT | counters] that measure the number |
| 5640 | ** of times it has performed specific operations.)^ These counters can |
| 5641 | ** be used to monitor the performance characteristics of the prepared |
| 5642 | ** statements. For example, if the number of table steps greatly exceeds |
| 5643 | ** the number of table searches or result rows, that would tend to indicate |
| 5644 | ** that the prepared statement is using a full table scan rather than |
| @@ -5645,11 +5811,11 @@ | |
| 5645 | ** an index. |
| 5646 | ** |
| 5647 | ** ^(This interface is used to retrieve and reset counter values from |
| 5648 | ** a [prepared statement]. The first argument is the prepared statement |
| 5649 | ** object to be interrogated. The second argument |
| 5650 | ** is an integer code for a specific [SQLITE_STMTSTATUS_SORT | counter] |
| 5651 | ** to be interrogated.)^ |
| 5652 | ** ^The current value of the requested counter is returned. |
| 5653 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 5654 | ** interface call returns. |
| 5655 | ** |
| @@ -5657,28 +5823,29 @@ | |
| 5657 | */ |
| 5658 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 5659 | |
| 5660 | /* |
| 5661 | ** CAPI3REF: Status Parameters for prepared statements |
| 5662 | ** |
| 5663 | ** These preprocessor macros define integer codes that name counter |
| 5664 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 5665 | ** The meanings of the various counters are as follows: |
| 5666 | ** |
| 5667 | ** <dl> |
| 5668 | ** <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> |
| 5669 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 5670 | ** a table as part of a full table scan. Large numbers for this counter |
| 5671 | ** may indicate opportunities for performance improvement through |
| 5672 | ** careful use of indices.</dd> |
| 5673 | ** |
| 5674 | ** <dt>SQLITE_STMTSTATUS_SORT</dt> |
| 5675 | ** <dd>^This is the number of sort operations that have occurred. |
| 5676 | ** A non-zero value in this counter may indicate an opportunity to |
| 5677 | ** improvement performance through careful use of indices.</dd> |
| 5678 | ** |
| 5679 | ** <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> |
| 5680 | ** <dd>^This is the number of rows inserted into transient indices that |
| 5681 | ** were created automatically in order to help joins run faster. |
| 5682 | ** A non-zero value in this counter may indicate an opportunity to |
| 5683 | ** improvement performance by adding permanent indices that do not |
| 5684 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -5725,10 +5892,11 @@ | |
| 5725 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 5726 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 5727 | ** the application may discard the parameter after the call to |
| 5728 | ** [sqlite3_config()] returns.)^ |
| 5729 | ** |
| 5730 | ** ^(The xInit() method is called once for each effective |
| 5731 | ** call to [sqlite3_initialize()])^ |
| 5732 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 5733 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 5734 | ** The intent of the xInit() method is to set up global data structures |
| @@ -5735,10 +5903,11 @@ | |
| 5735 | ** required by the custom page cache implementation. |
| 5736 | ** ^(If the xInit() method is NULL, then the |
| 5737 | ** built-in default page cache is used instead of the application defined |
| 5738 | ** page cache.)^ |
| 5739 | ** |
| 5740 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 5741 | ** It can be used to clean up |
| 5742 | ** any outstanding resources before process shutdown, if required. |
| 5743 | ** ^The xShutdown() method may be NULL. |
| 5744 | ** |
| @@ -5749,10 +5918,11 @@ | |
| 5749 | ** in multithreaded applications. |
| 5750 | ** |
| 5751 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 5752 | ** call to xShutdown(). |
| 5753 | ** |
| 5754 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 5755 | ** SQLite will typically create one cache instance for each open database file, |
| 5756 | ** though this is not guaranteed. ^The |
| 5757 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 5758 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -5773,20 +5943,23 @@ | |
| 5773 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 5774 | ** false will always have the "discard" flag set to true. |
| 5775 | ** ^Hence, a cache created with bPurgeable false will |
| 5776 | ** never contain any unpinned pages. |
| 5777 | ** |
| 5778 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 5779 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 5780 | ** instance passed as the first argument. This is the value configured using |
| 5781 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 5782 | ** parameter, the implementation is not required to do anything with this |
| 5783 | ** value; it is advisory only. |
| 5784 | ** |
| 5785 | ** The xPagecount() method must return the number of pages currently |
| 5786 | ** stored in the cache, both pinned and unpinned. |
| 5787 | ** |
| 5788 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 5789 | ** the page, or a NULL pointer. |
| 5790 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 5791 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 5792 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -5811,10 +5984,11 @@ | |
| 5811 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 5812 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 5813 | ** attempt to unpin one or more cache pages by spilling the content of |
| 5814 | ** pinned pages to disk and synching the operating system disk cache. |
| 5815 | ** |
| 5816 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 5817 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 5818 | ** then the page must be evicted from the cache. |
| 5819 | ** ^If the discard parameter is |
| 5820 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -5823,10 +5997,11 @@ | |
| 5823 | ** |
| 5824 | ** The cache must not perform any reference counting. A single |
| 5825 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 5826 | ** to xFetch(). |
| 5827 | ** |
| 5828 | ** The xRekey() method is used to change the key value associated with the |
| 5829 | ** page passed as the second argument. If the cache |
| 5830 | ** previously contains an entry associated with newKey, it must be |
| 5831 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 5832 | ** to be pinned. |
| @@ -5835,10 +6010,11 @@ | |
| 5835 | ** existing cache entries with page numbers (keys) greater than or equal |
| 5836 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 5837 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 5838 | ** they can be safely discarded. |
| 5839 | ** |
| 5840 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 5841 | ** All resources associated with the specified cache should be freed. ^After |
| 5842 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 5843 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 5844 | ** functions. |
| @@ -5897,11 +6073,11 @@ | |
| 5897 | ** associated with the backup operation. |
| 5898 | ** </ol>)^ |
| 5899 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 5900 | ** successful call to sqlite3_backup_init(). |
| 5901 | ** |
| 5902 | ** <b>sqlite3_backup_init()</b> |
| 5903 | ** |
| 5904 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 5905 | ** [database connection] associated with the destination database |
| 5906 | ** and the database name, respectively. |
| 5907 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -5924,11 +6100,11 @@ | |
| 5924 | ** [sqlite3_backup] object. |
| 5925 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 5926 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 5927 | ** operation. |
| 5928 | ** |
| 5929 | ** <b>sqlite3_backup_step()</b> |
| 5930 | ** |
| 5931 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 5932 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 5933 | ** ^If N is negative, all remaining source pages are copied. |
| 5934 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -5981,11 +6157,11 @@ | |
| 5981 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 5982 | ** database is modified by the using the same database connection as is used |
| 5983 | ** by the backup operation, then the backup database is automatically |
| 5984 | ** updated at the same time. |
| 5985 | ** |
| 5986 | ** <b>sqlite3_backup_finish()</b> |
| 5987 | ** |
| 5988 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 5989 | ** application wishes to abandon the backup operation, the application |
| 5990 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 5991 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6004,11 +6180,12 @@ | |
| 6004 | ** |
| 6005 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6006 | ** is not a permanent error and does not affect the return value of |
| 6007 | ** sqlite3_backup_finish(). |
| 6008 | ** |
| 6009 | ** <b>sqlite3_backup_remaining(), sqlite3_backup_pagecount()</b> |
| 6010 | ** |
| 6011 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6012 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6013 | ** up and the total number of pages in the source database file. |
| 6014 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6389,10 +6566,97 @@ | |
| 6389 | ** each of these values. |
| 6390 | */ |
| 6391 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 6392 | #define SQLITE_CHECKPOINT_FULL 1 |
| 6393 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 6394 | |
| 6395 | |
| 6396 | /* |
| 6397 | ** Undo the hack that converts floating point types to integer for |
| 6398 | ** builds on processors without floating point support. |
| 6399 |
| --- src/sqlite3.h | |
| +++ src/sqlite3.h | |
| @@ -105,13 +105,13 @@ | |
| 105 | ** |
| 106 | ** See also: [sqlite3_libversion()], |
| 107 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 108 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 109 | */ |
| 110 | #define SQLITE_VERSION "3.7.7" |
| 111 | #define SQLITE_VERSION_NUMBER 3007007 |
| 112 | #define SQLITE_SOURCE_ID "2011-05-20 01:50:01 2018d4e108872f2436df046636401b89cfde589d" |
| 113 | |
| 114 | /* |
| 115 | ** CAPI3REF: Run-Time Library Version Numbers |
| 116 | ** KEYWORDS: sqlite3_version, sqlite3_sourceid |
| 117 | ** |
| @@ -373,11 +373,12 @@ | |
| 373 | ** Many SQLite functions return an integer result code from the set shown |
| 374 | ** here in order to indicates success or failure. |
| 375 | ** |
| 376 | ** New error codes may be added in future versions of SQLite. |
| 377 | ** |
| 378 | ** See also: [SQLITE_IOERR_READ | extended result codes], |
| 379 | ** [sqlite3_vtab_on_conflict()] [SQLITE_ROLLBACK | result codes]. |
| 380 | */ |
| 381 | #define SQLITE_OK 0 /* Successful result */ |
| 382 | /* beginning-of-error-codes */ |
| 383 | #define SQLITE_ERROR 1 /* SQL error or missing database */ |
| 384 | #define SQLITE_INTERNAL 2 /* Internal logic error in SQLite */ |
| @@ -450,28 +451,31 @@ | |
| 451 | #define SQLITE_IOERR_CLOSE (SQLITE_IOERR | (16<<8)) |
| 452 | #define SQLITE_IOERR_DIR_CLOSE (SQLITE_IOERR | (17<<8)) |
| 453 | #define SQLITE_IOERR_SHMOPEN (SQLITE_IOERR | (18<<8)) |
| 454 | #define SQLITE_IOERR_SHMSIZE (SQLITE_IOERR | (19<<8)) |
| 455 | #define SQLITE_IOERR_SHMLOCK (SQLITE_IOERR | (20<<8)) |
| 456 | #define SQLITE_IOERR_SHMMAP (SQLITE_IOERR | (21<<8)) |
| 457 | #define SQLITE_IOERR_SEEK (SQLITE_IOERR | (22<<8)) |
| 458 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 459 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 460 | #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) |
| 461 | #define SQLITE_CORRUPT_VTAB (SQLITE_CORRUPT | (1<<8)) |
| 462 | |
| 463 | /* |
| 464 | ** CAPI3REF: Flags For File Open Operations |
| 465 | ** |
| 466 | ** These bit values are intended for use in the |
| 467 | ** 3rd parameter to the [sqlite3_open_v2()] interface and |
| 468 | ** in the 4th parameter to the [sqlite3_vfs.xOpen] method. |
| 469 | */ |
| 470 | #define SQLITE_OPEN_READONLY 0x00000001 /* Ok for sqlite3_open_v2() */ |
| 471 | #define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */ |
| 472 | #define SQLITE_OPEN_CREATE 0x00000004 /* Ok for sqlite3_open_v2() */ |
| 473 | #define SQLITE_OPEN_DELETEONCLOSE 0x00000008 /* VFS only */ |
| 474 | #define SQLITE_OPEN_EXCLUSIVE 0x00000010 /* VFS only */ |
| 475 | #define SQLITE_OPEN_AUTOPROXY 0x00000020 /* VFS only */ |
| 476 | #define SQLITE_OPEN_URI 0x00000040 /* Ok for sqlite3_open_v2() */ |
| 477 | #define SQLITE_OPEN_MAIN_DB 0x00000100 /* VFS only */ |
| 478 | #define SQLITE_OPEN_TEMP_DB 0x00000200 /* VFS only */ |
| 479 | #define SQLITE_OPEN_TRANSIENT_DB 0x00000400 /* VFS only */ |
| 480 | #define SQLITE_OPEN_MAIN_JOURNAL 0x00000800 /* VFS only */ |
| 481 | #define SQLITE_OPEN_TEMP_JOURNAL 0x00001000 /* VFS only */ |
| @@ -578,21 +582,22 @@ | |
| 582 | }; |
| 583 | |
| 584 | /* |
| 585 | ** CAPI3REF: OS Interface File Virtual Methods Object |
| 586 | ** |
| 587 | ** Every file opened by the [sqlite3_vfs.xOpen] method populates an |
| 588 | ** [sqlite3_file] object (or, more commonly, a subclass of the |
| 589 | ** [sqlite3_file] object) with a pointer to an instance of this object. |
| 590 | ** This object defines the methods used to perform various operations |
| 591 | ** against the open file represented by the [sqlite3_file] object. |
| 592 | ** |
| 593 | ** If the [sqlite3_vfs.xOpen] method sets the sqlite3_file.pMethods element |
| 594 | ** to a non-NULL pointer, then the sqlite3_io_methods.xClose method |
| 595 | ** may be invoked even if the [sqlite3_vfs.xOpen] reported that it failed. The |
| 596 | ** only way to prevent a call to xClose following a failed [sqlite3_vfs.xOpen] |
| 597 | ** is for the [sqlite3_vfs.xOpen] to set the sqlite3_file.pMethods element |
| 598 | ** to NULL. |
| 599 | ** |
| 600 | ** The flags argument to xSync may be one of [SQLITE_SYNC_NORMAL] or |
| 601 | ** [SQLITE_SYNC_FULL]. The first choice is the normal fsync(). |
| 602 | ** The second choice is a Mac OS X style fullsync. The [SQLITE_SYNC_DATAONLY] |
| 603 | ** flag may be ORed in to indicate that only the data of the file |
| @@ -757,10 +762,11 @@ | |
| 762 | */ |
| 763 | typedef struct sqlite3_mutex sqlite3_mutex; |
| 764 | |
| 765 | /* |
| 766 | ** CAPI3REF: OS Interface Object |
| 767 | ** KEYWORDS: VFS VFSes |
| 768 | ** |
| 769 | ** An instance of the sqlite3_vfs object defines the interface between |
| 770 | ** the SQLite core and the underlying operating system. The "vfs" |
| 771 | ** in the name of the object stands for "virtual file system". |
| 772 | ** |
| @@ -789,10 +795,11 @@ | |
| 795 | ** object once the object has been registered. |
| 796 | ** |
| 797 | ** The zName field holds the name of the VFS module. The name must |
| 798 | ** be unique across all VFS modules. |
| 799 | ** |
| 800 | ** [[sqlite3_vfs.xOpen]] |
| 801 | ** ^SQLite guarantees that the zFilename parameter to xOpen |
| 802 | ** is either a NULL pointer or string obtained |
| 803 | ** from xFullPathname() with an optional suffix added. |
| 804 | ** ^If a suffix is added to the zFilename parameter, it will |
| 805 | ** consist of a single "-" character followed by no more than |
| @@ -866,10 +873,11 @@ | |
| 873 | ** a valid [sqlite3_io_methods] object or to NULL. xOpen must do |
| 874 | ** this even if the open fails. SQLite expects that the sqlite3_file.pMethods |
| 875 | ** element will be valid after xOpen returns regardless of the success |
| 876 | ** or failure of the xOpen call. |
| 877 | ** |
| 878 | ** [[sqlite3_vfs.xAccess]] |
| 879 | ** ^The flags argument to xAccess() may be [SQLITE_ACCESS_EXISTS] |
| 880 | ** to test for the existence of a file, or [SQLITE_ACCESS_READWRITE] to |
| 881 | ** test whether a file is readable and writable, or [SQLITE_ACCESS_READ] |
| 882 | ** to test whether a file is at least readable. The file can be a |
| 883 | ** directory. |
| @@ -1112,13 +1120,13 @@ | |
| 1120 | ** [sqlite3_shutdown()] then it will return SQLITE_MISUSE. |
| 1121 | ** Note, however, that ^sqlite3_config() can be called as part of the |
| 1122 | ** implementation of an application-defined [sqlite3_os_init()]. |
| 1123 | ** |
| 1124 | ** The first argument to sqlite3_config() is an integer |
| 1125 | ** [configuration option] that determines |
| 1126 | ** what property of SQLite is to be configured. Subsequent arguments |
| 1127 | ** vary depending on the [configuration option] |
| 1128 | ** in the first argument. |
| 1129 | ** |
| 1130 | ** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK]. |
| 1131 | ** ^If the option is unknown or SQLite is unable to set the option |
| 1132 | ** then this routine returns a non-zero [error code]. |
| @@ -1224,10 +1232,11 @@ | |
| 1232 | void *pAppData; /* Argument to xInit() and xShutdown() */ |
| 1233 | }; |
| 1234 | |
| 1235 | /* |
| 1236 | ** CAPI3REF: Configuration Options |
| 1237 | ** KEYWORDS: {configuration option} |
| 1238 | ** |
| 1239 | ** These constants are the available integer configuration options that |
| 1240 | ** can be passed as the first argument to the [sqlite3_config()] interface. |
| 1241 | ** |
| 1242 | ** New configuration options may be added in future releases of SQLite. |
| @@ -1236,11 +1245,11 @@ | |
| 1245 | ** the call worked. The [sqlite3_config()] interface will return a |
| 1246 | ** non-zero [error code] if a discontinued or unsupported configuration option |
| 1247 | ** is invoked. |
| 1248 | ** |
| 1249 | ** <dl> |
| 1250 | ** [[SQLITE_CONFIG_SINGLETHREAD]] <dt>SQLITE_CONFIG_SINGLETHREAD</dt> |
| 1251 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1252 | ** [threading mode] to Single-thread. In other words, it disables |
| 1253 | ** all mutexing and puts SQLite into a mode where it can only be used |
| 1254 | ** by a single thread. ^If SQLite is compiled with |
| 1255 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| @@ -1247,11 +1256,11 @@ | |
| 1256 | ** it is not possible to change the [threading mode] from its default |
| 1257 | ** value of Single-thread and so [sqlite3_config()] will return |
| 1258 | ** [SQLITE_ERROR] if called with the SQLITE_CONFIG_SINGLETHREAD |
| 1259 | ** configuration option.</dd> |
| 1260 | ** |
| 1261 | ** [[SQLITE_CONFIG_MULTITHREAD]] <dt>SQLITE_CONFIG_MULTITHREAD</dt> |
| 1262 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1263 | ** [threading mode] to Multi-thread. In other words, it disables |
| 1264 | ** mutexing on [database connection] and [prepared statement] objects. |
| 1265 | ** The application is responsible for serializing access to |
| 1266 | ** [database connections] and [prepared statements]. But other mutexes |
| @@ -1261,11 +1270,11 @@ | |
| 1270 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1271 | ** it is not possible to set the Multi-thread [threading mode] and |
| 1272 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1273 | ** SQLITE_CONFIG_MULTITHREAD configuration option.</dd> |
| 1274 | ** |
| 1275 | ** [[SQLITE_CONFIG_SERIALIZED]] <dt>SQLITE_CONFIG_SERIALIZED</dt> |
| 1276 | ** <dd>There are no arguments to this option. ^This option sets the |
| 1277 | ** [threading mode] to Serialized. In other words, this option enables |
| 1278 | ** all mutexes including the recursive |
| 1279 | ** mutexes on [database connection] and [prepared statement] objects. |
| 1280 | ** In this mode (which is the default when SQLite is compiled with |
| @@ -1277,27 +1286,27 @@ | |
| 1286 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1287 | ** it is not possible to set the Serialized [threading mode] and |
| 1288 | ** [sqlite3_config()] will return [SQLITE_ERROR] if called with the |
| 1289 | ** SQLITE_CONFIG_SERIALIZED configuration option.</dd> |
| 1290 | ** |
| 1291 | ** [[SQLITE_CONFIG_MALLOC]] <dt>SQLITE_CONFIG_MALLOC</dt> |
| 1292 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1293 | ** instance of the [sqlite3_mem_methods] structure. The argument specifies |
| 1294 | ** alternative low-level memory allocation routines to be used in place of |
| 1295 | ** the memory allocation routines built into SQLite.)^ ^SQLite makes |
| 1296 | ** its own private copy of the content of the [sqlite3_mem_methods] structure |
| 1297 | ** before the [sqlite3_config()] call returns.</dd> |
| 1298 | ** |
| 1299 | ** [[SQLITE_CONFIG_GETMALLOC]] <dt>SQLITE_CONFIG_GETMALLOC</dt> |
| 1300 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1301 | ** instance of the [sqlite3_mem_methods] structure. The [sqlite3_mem_methods] |
| 1302 | ** structure is filled with the currently defined memory allocation routines.)^ |
| 1303 | ** This option can be used to overload the default memory allocation |
| 1304 | ** routines with a wrapper that simulations memory allocation failure or |
| 1305 | ** tracks memory usage, for example. </dd> |
| 1306 | ** |
| 1307 | ** [[SQLITE_CONFIG_MEMSTATUS]] <dt>SQLITE_CONFIG_MEMSTATUS</dt> |
| 1308 | ** <dd> ^This option takes single argument of type int, interpreted as a |
| 1309 | ** boolean, which enables or disables the collection of memory allocation |
| 1310 | ** statistics. ^(When memory allocation statistics are disabled, the |
| 1311 | ** following SQLite interfaces become non-operational: |
| 1312 | ** <ul> |
| @@ -1309,11 +1318,11 @@ | |
| 1318 | ** ^Memory allocation statistics are enabled by default unless SQLite is |
| 1319 | ** compiled with [SQLITE_DEFAULT_MEMSTATUS]=0 in which case memory |
| 1320 | ** allocation statistics are disabled by default. |
| 1321 | ** </dd> |
| 1322 | ** |
| 1323 | ** [[SQLITE_CONFIG_SCRATCH]] <dt>SQLITE_CONFIG_SCRATCH</dt> |
| 1324 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1325 | ** scratch memory. There are three arguments: A pointer an 8-byte |
| 1326 | ** aligned memory buffer from which the scratch allocations will be |
| 1327 | ** drawn, the size of each scratch allocation (sz), |
| 1328 | ** and the maximum number of scratch allocations (N). The sz |
| @@ -1325,11 +1334,11 @@ | |
| 1334 | ** ^SQLite will never require a scratch buffer that is more than 6 |
| 1335 | ** times the database page size. ^If SQLite needs needs additional |
| 1336 | ** scratch memory beyond what is provided by this configuration option, then |
| 1337 | ** [sqlite3_malloc()] will be used to obtain the memory needed.</dd> |
| 1338 | ** |
| 1339 | ** [[SQLITE_CONFIG_PAGECACHE]] <dt>SQLITE_CONFIG_PAGECACHE</dt> |
| 1340 | ** <dd> ^This option specifies a static memory buffer that SQLite can use for |
| 1341 | ** the database page cache with the default page cache implemenation. |
| 1342 | ** This configuration should not be used if an application-define page |
| 1343 | ** cache implementation is loaded using the SQLITE_CONFIG_PCACHE option. |
| 1344 | ** There are three arguments to this option: A pointer to 8-byte aligned |
| @@ -1346,11 +1355,11 @@ | |
| 1355 | ** SQLite goes to [sqlite3_malloc()] for the additional storage space. |
| 1356 | ** The pointer in the first argument must |
| 1357 | ** be aligned to an 8-byte boundary or subsequent behavior of SQLite |
| 1358 | ** will be undefined.</dd> |
| 1359 | ** |
| 1360 | ** [[SQLITE_CONFIG_HEAP]] <dt>SQLITE_CONFIG_HEAP</dt> |
| 1361 | ** <dd> ^This option specifies a static memory buffer that SQLite will use |
| 1362 | ** for all of its dynamic memory allocation needs beyond those provided |
| 1363 | ** for by [SQLITE_CONFIG_SCRATCH] and [SQLITE_CONFIG_PAGECACHE]. |
| 1364 | ** There are three arguments: An 8-byte aligned pointer to the memory, |
| 1365 | ** the number of bytes in the memory buffer, and the minimum allocation size. |
| @@ -1363,11 +1372,11 @@ | |
| 1372 | ** The first pointer (the memory pointer) must be aligned to an 8-byte |
| 1373 | ** boundary or subsequent behavior of SQLite will be undefined. |
| 1374 | ** The minimum allocation size is capped at 2^12. Reasonable values |
| 1375 | ** for the minimum allocation size are 2^5 through 2^8.</dd> |
| 1376 | ** |
| 1377 | ** [[SQLITE_CONFIG_MUTEX]] <dt>SQLITE_CONFIG_MUTEX</dt> |
| 1378 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1379 | ** instance of the [sqlite3_mutex_methods] structure. The argument specifies |
| 1380 | ** alternative low-level mutex routines to be used in place |
| 1381 | ** the mutex routines built into SQLite.)^ ^SQLite makes a copy of the |
| 1382 | ** content of the [sqlite3_mutex_methods] structure before the call to |
| @@ -1375,11 +1384,11 @@ | |
| 1384 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1385 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1386 | ** [sqlite3_config()] with the SQLITE_CONFIG_MUTEX configuration option will |
| 1387 | ** return [SQLITE_ERROR].</dd> |
| 1388 | ** |
| 1389 | ** [[SQLITE_CONFIG_GETMUTEX]] <dt>SQLITE_CONFIG_GETMUTEX</dt> |
| 1390 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1391 | ** instance of the [sqlite3_mutex_methods] structure. The |
| 1392 | ** [sqlite3_mutex_methods] |
| 1393 | ** structure is filled with the currently defined mutex routines.)^ |
| 1394 | ** This option can be used to overload the default mutex allocation |
| @@ -1388,32 +1397,32 @@ | |
| 1397 | ** the [SQLITE_THREADSAFE | SQLITE_THREADSAFE=0] compile-time option then |
| 1398 | ** the entire mutexing subsystem is omitted from the build and hence calls to |
| 1399 | ** [sqlite3_config()] with the SQLITE_CONFIG_GETMUTEX configuration option will |
| 1400 | ** return [SQLITE_ERROR].</dd> |
| 1401 | ** |
| 1402 | ** [[SQLITE_CONFIG_LOOKASIDE]] <dt>SQLITE_CONFIG_LOOKASIDE</dt> |
| 1403 | ** <dd> ^(This option takes two arguments that determine the default |
| 1404 | ** memory allocation for the lookaside memory allocator on each |
| 1405 | ** [database connection]. The first argument is the |
| 1406 | ** size of each lookaside buffer slot and the second is the number of |
| 1407 | ** slots allocated to each database connection.)^ ^(This option sets the |
| 1408 | ** <i>default</i> lookaside size. The [SQLITE_DBCONFIG_LOOKASIDE] |
| 1409 | ** verb to [sqlite3_db_config()] can be used to change the lookaside |
| 1410 | ** configuration on individual connections.)^ </dd> |
| 1411 | ** |
| 1412 | ** [[SQLITE_CONFIG_PCACHE]] <dt>SQLITE_CONFIG_PCACHE</dt> |
| 1413 | ** <dd> ^(This option takes a single argument which is a pointer to |
| 1414 | ** an [sqlite3_pcache_methods] object. This object specifies the interface |
| 1415 | ** to a custom page cache implementation.)^ ^SQLite makes a copy of the |
| 1416 | ** object and uses it for page cache memory allocations.</dd> |
| 1417 | ** |
| 1418 | ** [[SQLITE_CONFIG_GETPCACHE]] <dt>SQLITE_CONFIG_GETPCACHE</dt> |
| 1419 | ** <dd> ^(This option takes a single argument which is a pointer to an |
| 1420 | ** [sqlite3_pcache_methods] object. SQLite copies of the current |
| 1421 | ** page cache implementation into that object.)^ </dd> |
| 1422 | ** |
| 1423 | ** [[SQLITE_CONFIG_LOG]] <dt>SQLITE_CONFIG_LOG</dt> |
| 1424 | ** <dd> ^The SQLITE_CONFIG_LOG option takes two arguments: a pointer to a |
| 1425 | ** function with a call signature of void(*)(void*,int,const char*), |
| 1426 | ** and a pointer to void. ^If the function pointer is not NULL, it is |
| 1427 | ** invoked by [sqlite3_log()] to process each logging event. ^If the |
| 1428 | ** function pointer is NULL, the [sqlite3_log()] interface becomes a no-op. |
| @@ -1427,10 +1436,22 @@ | |
| 1436 | ** The SQLite logging interface is not reentrant; the logger function |
| 1437 | ** supplied by the application must not invoke any SQLite interface. |
| 1438 | ** In a multi-threaded application, the application-defined logger |
| 1439 | ** function must be threadsafe. </dd> |
| 1440 | ** |
| 1441 | ** [[SQLITE_CONFIG_URI]] <dt>SQLITE_CONFIG_URI |
| 1442 | ** <dd> This option takes a single argument of type int. If non-zero, then |
| 1443 | ** URI handling is globally enabled. If the parameter is zero, then URI handling |
| 1444 | ** is globally disabled. If URI handling is globally enabled, all filenames |
| 1445 | ** passed to [sqlite3_open()], [sqlite3_open_v2()], [sqlite3_open16()] or |
| 1446 | ** specified as part of [ATTACH] commands are interpreted as URIs, regardless |
| 1447 | ** of whether or not the [SQLITE_OPEN_URI] flag is set when the database |
| 1448 | ** connection is opened. If it is globally disabled, filenames are |
| 1449 | ** only interpreted as URIs if the SQLITE_OPEN_URI flag is set when the |
| 1450 | ** database connection is opened. By default, URI handling is globally |
| 1451 | ** disabled. The default value may be changed by compiling with the |
| 1452 | ** [SQLITE_USE_URI] symbol defined. |
| 1453 | ** </dl> |
| 1454 | */ |
| 1455 | #define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */ |
| 1456 | #define SQLITE_CONFIG_MULTITHREAD 2 /* nil */ |
| 1457 | #define SQLITE_CONFIG_SERIALIZED 3 /* nil */ |
| @@ -1445,10 +1466,11 @@ | |
| 1466 | /* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */ |
| 1467 | #define SQLITE_CONFIG_LOOKASIDE 13 /* int int */ |
| 1468 | #define SQLITE_CONFIG_PCACHE 14 /* sqlite3_pcache_methods* */ |
| 1469 | #define SQLITE_CONFIG_GETPCACHE 15 /* sqlite3_pcache_methods* */ |
| 1470 | #define SQLITE_CONFIG_LOG 16 /* xFunc, void* */ |
| 1471 | #define SQLITE_CONFIG_URI 17 /* int */ |
| 1472 | |
| 1473 | /* |
| 1474 | ** CAPI3REF: Database Connection Configuration Options |
| 1475 | ** |
| 1476 | ** These constants are the available integer configuration options that |
| @@ -1530,17 +1552,21 @@ | |
| 1552 | ** the table has a column of type [INTEGER PRIMARY KEY] then that column |
| 1553 | ** is another alias for the rowid. |
| 1554 | ** |
| 1555 | ** ^This routine returns the [rowid] of the most recent |
| 1556 | ** successful [INSERT] into the database from the [database connection] |
| 1557 | ** in the first argument. ^As of SQLite version 3.7.7, this routines |
| 1558 | ** records the last insert rowid of both ordinary tables and [virtual tables]. |
| 1559 | ** ^If no successful [INSERT]s |
| 1560 | ** have ever occurred on that database connection, zero is returned. |
| 1561 | ** |
| 1562 | ** ^(If an [INSERT] occurs within a trigger or within a [virtual table] |
| 1563 | ** method, then this routine will return the [rowid] of the inserted |
| 1564 | ** row as long as the trigger or virtual table method is running. |
| 1565 | ** But once the trigger or virtual table method ends, the value returned |
| 1566 | ** by this routine reverts to what it was before the trigger or virtual |
| 1567 | ** table method began.)^ |
| 1568 | ** |
| 1569 | ** ^An [INSERT] that fails due to a constraint violation is not a |
| 1570 | ** successful [INSERT] and does not change the value returned by this |
| 1571 | ** routine. ^Thus INSERT OR FAIL, INSERT OR IGNORE, INSERT OR ROLLBACK, |
| 1572 | ** and INSERT OR ABORT make no changes to the return value of this |
| @@ -2199,10 +2225,13 @@ | |
| 2225 | ** The [sqlite3_set_authorizer | authorizer callback function] must |
| 2226 | ** return either [SQLITE_OK] or one of these two constants in order |
| 2227 | ** to signal SQLite whether or not the action is permitted. See the |
| 2228 | ** [sqlite3_set_authorizer | authorizer documentation] for additional |
| 2229 | ** information. |
| 2230 | ** |
| 2231 | ** Note that SQLITE_IGNORE is also used as a [SQLITE_ROLLBACK | return code] |
| 2232 | ** from the [sqlite3_vtab_on_conflict()] interface. |
| 2233 | */ |
| 2234 | #define SQLITE_DENY 1 /* Abort the SQL statement with an error */ |
| 2235 | #define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ |
| 2236 | |
| 2237 | /* |
| @@ -2321,11 +2350,11 @@ | |
| 2350 | SQLITE_API void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); |
| 2351 | |
| 2352 | /* |
| 2353 | ** CAPI3REF: Opening A New Database Connection |
| 2354 | ** |
| 2355 | ** ^These routines open an SQLite database file as specified by the |
| 2356 | ** filename argument. ^The filename argument is interpreted as UTF-8 for |
| 2357 | ** sqlite3_open() and sqlite3_open_v2() and as UTF-16 in the native byte |
| 2358 | ** order for sqlite3_open16(). ^(A [database connection] handle is usually |
| 2359 | ** returned in *ppDb, even if an error occurs. The only exception is that |
| 2360 | ** if SQLite is unable to allocate memory to hold the [sqlite3] object, |
| @@ -2348,11 +2377,11 @@ | |
| 2377 | ** except that it accepts two additional parameters for additional control |
| 2378 | ** over the new database connection. ^(The flags parameter to |
| 2379 | ** sqlite3_open_v2() can take one of |
| 2380 | ** the following three values, optionally combined with the |
| 2381 | ** [SQLITE_OPEN_NOMUTEX], [SQLITE_OPEN_FULLMUTEX], [SQLITE_OPEN_SHAREDCACHE], |
| 2382 | ** [SQLITE_OPEN_PRIVATECACHE], and/or [SQLITE_OPEN_URI] flags:)^ |
| 2383 | ** |
| 2384 | ** <dl> |
| 2385 | ** ^(<dt>[SQLITE_OPEN_READONLY]</dt> |
| 2386 | ** <dd>The database is opened in read-only mode. If the database does not |
| 2387 | ** already exist, an error is returned.</dd>)^ |
| @@ -2367,13 +2396,12 @@ | |
| 2396 | ** it does not already exist. This is the behavior that is always used for |
| 2397 | ** sqlite3_open() and sqlite3_open16().</dd>)^ |
| 2398 | ** </dl> |
| 2399 | ** |
| 2400 | ** If the 3rd parameter to sqlite3_open_v2() is not one of the |
| 2401 | ** combinations shown above optionally combined with other |
| 2402 | ** [SQLITE_OPEN_READONLY | SQLITE_OPEN_* bits] |
| 2403 | ** then the behavior is undefined. |
| 2404 | ** |
| 2405 | ** ^If the [SQLITE_OPEN_NOMUTEX] flag is set, then the database connection |
| 2406 | ** opens in the multi-thread [threading mode] as long as the single-thread |
| 2407 | ** mode has not been set at compile-time or start-time. ^If the |
| @@ -2383,10 +2411,15 @@ | |
| 2411 | ** ^The [SQLITE_OPEN_SHAREDCACHE] flag causes the database connection to be |
| 2412 | ** eligible to use [shared cache mode], regardless of whether or not shared |
| 2413 | ** cache is enabled using [sqlite3_enable_shared_cache()]. ^The |
| 2414 | ** [SQLITE_OPEN_PRIVATECACHE] flag causes the database connection to not |
| 2415 | ** participate in [shared cache mode] even if it is enabled. |
| 2416 | ** |
| 2417 | ** ^The fourth parameter to sqlite3_open_v2() is the name of the |
| 2418 | ** [sqlite3_vfs] object that defines the operating system interface that |
| 2419 | ** the new database connection should use. ^If the fourth parameter is |
| 2420 | ** a NULL pointer then the default [sqlite3_vfs] object is used. |
| 2421 | ** |
| 2422 | ** ^If the filename is ":memory:", then a private, temporary in-memory database |
| 2423 | ** is created for the connection. ^This in-memory database will vanish when |
| 2424 | ** the database connection is closed. Future versions of SQLite might |
| 2425 | ** make use of additional special filenames that begin with the ":" character. |
| @@ -2396,14 +2429,115 @@ | |
| 2429 | ** |
| 2430 | ** ^If the filename is an empty string, then a private, temporary |
| 2431 | ** on-disk database will be created. ^This private database will be |
| 2432 | ** automatically deleted as soon as the database connection is closed. |
| 2433 | ** |
| 2434 | ** [[URI filenames in sqlite3_open()]] <h3>URI Filenames</h3> |
| 2435 | ** |
| 2436 | ** ^If [URI filename] interpretation is enabled, and the filename argument |
| 2437 | ** begins with "file:", then the filename is interpreted as a URI. ^URI |
| 2438 | ** filename interpretation is enabled if the [SQLITE_OPEN_URI] flag is |
| 2439 | ** is set in the fourth argument to sqlite3_open_v2(), or if it has |
| 2440 | ** been enabled globally using the [SQLITE_CONFIG_URI] option with the |
| 2441 | ** [sqlite3_config()] method or by the [SQLITE_USE_URI] compile-time option. |
| 2442 | ** As of SQLite version 3.7.7, URI filename interpretation is turned off |
| 2443 | ** by default, but future releases of SQLite might enable URI filename |
| 2444 | ** intepretation by default. See "[URI filenames]" for additional |
| 2445 | ** information. |
| 2446 | ** |
| 2447 | ** URI filenames are parsed according to RFC 3986. ^If the URI contains an |
| 2448 | ** authority, then it must be either an empty string or the string |
| 2449 | ** "localhost". ^If the authority is not an empty string or "localhost", an |
| 2450 | ** error is returned to the caller. ^The fragment component of a URI, if |
| 2451 | ** present, is ignored. |
| 2452 | ** |
| 2453 | ** ^SQLite uses the path component of the URI as the name of the disk file |
| 2454 | ** which contains the database. ^If the path begins with a '/' character, |
| 2455 | ** then it is interpreted as an absolute path. ^If the path does not begin |
| 2456 | ** with a '/' (meaning that the authority section is omitted from the URI) |
| 2457 | ** then the path is interpreted as a relative path. |
| 2458 | ** ^On windows, the first component of an absolute path |
| 2459 | ** is a drive specification (e.g. "C:"). |
| 2460 | ** |
| 2461 | ** [[core URI query parameters]] |
| 2462 | ** The query component of a URI may contain parameters that are interpreted |
| 2463 | ** either by SQLite itself, or by a [VFS | custom VFS implementation]. |
| 2464 | ** SQLite interprets the following three query parameters: |
| 2465 | ** |
| 2466 | ** <ul> |
| 2467 | ** <li> <b>vfs</b>: ^The "vfs" parameter may be used to specify the name of |
| 2468 | ** a VFS object that provides the operating system interface that should |
| 2469 | ** be used to access the database file on disk. ^If this option is set to |
| 2470 | ** an empty string the default VFS object is used. ^Specifying an unknown |
| 2471 | ** VFS is an error. ^If sqlite3_open_v2() is used and the vfs option is |
| 2472 | ** present, then the VFS specified by the option takes precedence over |
| 2473 | ** the value passed as the fourth parameter to sqlite3_open_v2(). |
| 2474 | ** |
| 2475 | ** <li> <b>mode</b>: ^(The mode parameter may be set to either "ro", "rw" or |
| 2476 | ** "rwc". Attempting to set it to any other value is an error)^. |
| 2477 | ** ^If "ro" is specified, then the database is opened for read-only |
| 2478 | ** access, just as if the [SQLITE_OPEN_READONLY] flag had been set in the |
| 2479 | ** third argument to sqlite3_prepare_v2(). ^If the mode option is set to |
| 2480 | ** "rw", then the database is opened for read-write (but not create) |
| 2481 | ** access, as if SQLITE_OPEN_READWRITE (but not SQLITE_OPEN_CREATE) had |
| 2482 | ** been set. ^Value "rwc" is equivalent to setting both |
| 2483 | ** SQLITE_OPEN_READWRITE and SQLITE_OPEN_CREATE. ^If sqlite3_open_v2() is |
| 2484 | ** used, it is an error to specify a value for the mode parameter that is |
| 2485 | ** less restrictive than that specified by the flags passed as the third |
| 2486 | ** parameter. |
| 2487 | ** |
| 2488 | ** <li> <b>cache</b>: ^The cache parameter may be set to either "shared" or |
| 2489 | ** "private". ^Setting it to "shared" is equivalent to setting the |
| 2490 | ** SQLITE_OPEN_SHAREDCACHE bit in the flags argument passed to |
| 2491 | ** sqlite3_open_v2(). ^Setting the cache parameter to "private" is |
| 2492 | ** equivalent to setting the SQLITE_OPEN_PRIVATECACHE bit. |
| 2493 | ** ^If sqlite3_open_v2() is used and the "cache" parameter is present in |
| 2494 | ** a URI filename, its value overrides any behaviour requested by setting |
| 2495 | ** SQLITE_OPEN_PRIVATECACHE or SQLITE_OPEN_SHAREDCACHE flag. |
| 2496 | ** </ul> |
| 2497 | ** |
| 2498 | ** ^Specifying an unknown parameter in the query component of a URI is not an |
| 2499 | ** error. Future versions of SQLite might understand additional query |
| 2500 | ** parameters. See "[query parameters with special meaning to SQLite]" for |
| 2501 | ** additional information. |
| 2502 | ** |
| 2503 | ** [[URI filename examples]] <h3>URI filename examples</h3> |
| 2504 | ** |
| 2505 | ** <table border="1" align=center cellpadding=5> |
| 2506 | ** <tr><th> URI filenames <th> Results |
| 2507 | ** <tr><td> file:data.db <td> |
| 2508 | ** Open the file "data.db" in the current directory. |
| 2509 | ** <tr><td> file:/home/fred/data.db<br> |
| 2510 | ** file:///home/fred/data.db <br> |
| 2511 | ** file://localhost/home/fred/data.db <br> <td> |
| 2512 | ** Open the database file "/home/fred/data.db". |
| 2513 | ** <tr><td> file://darkstar/home/fred/data.db <td> |
| 2514 | ** An error. "darkstar" is not a recognized authority. |
| 2515 | ** <tr><td style="white-space:nowrap"> |
| 2516 | ** file:///C:/Documents%20and%20Settings/fred/Desktop/data.db |
| 2517 | ** <td> Windows only: Open the file "data.db" on fred's desktop on drive |
| 2518 | ** C:. Note that the %20 escaping in this example is not strictly |
| 2519 | ** necessary - space characters can be used literally |
| 2520 | ** in URI filenames. |
| 2521 | ** <tr><td> file:data.db?mode=ro&cache=private <td> |
| 2522 | ** Open file "data.db" in the current directory for read-only access. |
| 2523 | ** Regardless of whether or not shared-cache mode is enabled by |
| 2524 | ** default, use a private cache. |
| 2525 | ** <tr><td> file:/home/fred/data.db?vfs=unix-nolock <td> |
| 2526 | ** Open file "/home/fred/data.db". Use the special VFS "unix-nolock". |
| 2527 | ** <tr><td> file:data.db?mode=readonly <td> |
| 2528 | ** An error. "readonly" is not a valid option for the "mode" parameter. |
| 2529 | ** </table> |
| 2530 | ** |
| 2531 | ** ^URI hexadecimal escape sequences (%HH) are supported within the path and |
| 2532 | ** query components of a URI. A hexadecimal escape sequence consists of a |
| 2533 | ** percent sign - "%" - followed by exactly two hexadecimal digits |
| 2534 | ** specifying an octet value. ^Before the path or query components of a |
| 2535 | ** URI filename are interpreted, they are encoded using UTF-8 and all |
| 2536 | ** hexadecimal escape sequences replaced by a single byte containing the |
| 2537 | ** corresponding octet. If this process generates an invalid UTF-8 encoding, |
| 2538 | ** the results are undefined. |
| 2539 | ** |
| 2540 | ** <b>Note to Windows users:</b> The encoding used for the filename argument |
| 2541 | ** of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever |
| 2542 | ** codepage is currently defined. Filenames containing international |
| 2543 | ** characters must be converted to UTF-8 prior to passing them into |
| @@ -2421,10 +2555,30 @@ | |
| 2555 | const char *filename, /* Database filename (UTF-8) */ |
| 2556 | sqlite3 **ppDb, /* OUT: SQLite db handle */ |
| 2557 | int flags, /* Flags */ |
| 2558 | const char *zVfs /* Name of VFS module to use */ |
| 2559 | ); |
| 2560 | |
| 2561 | /* |
| 2562 | ** CAPI3REF: Obtain Values For URI Parameters |
| 2563 | ** |
| 2564 | ** This is a utility routine, useful to VFS implementations, that checks |
| 2565 | ** to see if a database file was a URI that contained a specific query |
| 2566 | ** parameter, and if so obtains the value of the query parameter. |
| 2567 | ** |
| 2568 | ** The zFilename argument is the filename pointer passed into the xOpen() |
| 2569 | ** method of a VFS implementation. The zParam argument is the name of the |
| 2570 | ** query parameter we seek. This routine returns the value of the zParam |
| 2571 | ** parameter if it exists. If the parameter does not exist, this routine |
| 2572 | ** returns a NULL pointer. |
| 2573 | ** |
| 2574 | ** If the zFilename argument to this function is not a pointer that SQLite |
| 2575 | ** passed into the xOpen VFS method, then the behavior of this routine |
| 2576 | ** is undefined and probably undesirable. |
| 2577 | */ |
| 2578 | SQLITE_API const char *sqlite3_uri_parameter(const char *zFilename, const char *zParam); |
| 2579 | |
| 2580 | |
| 2581 | /* |
| 2582 | ** CAPI3REF: Error Codes And Messages |
| 2583 | ** |
| 2584 | ** ^The sqlite3_errcode() interface returns the numeric [result code] or |
| @@ -2537,47 +2691,49 @@ | |
| 2691 | ** that can be lowered at run-time using [sqlite3_limit()]. |
| 2692 | ** The synopsis of the meanings of the various limits is shown below. |
| 2693 | ** Additional information is available at [limits | Limits in SQLite]. |
| 2694 | ** |
| 2695 | ** <dl> |
| 2696 | ** [[SQLITE_LIMIT_LENGTH]] ^(<dt>SQLITE_LIMIT_LENGTH</dt> |
| 2697 | ** <dd>The maximum size of any string or BLOB or table row, in bytes.<dd>)^ |
| 2698 | ** |
| 2699 | ** [[SQLITE_LIMIT_SQL_LENGTH]] ^(<dt>SQLITE_LIMIT_SQL_LENGTH</dt> |
| 2700 | ** <dd>The maximum length of an SQL statement, in bytes.</dd>)^ |
| 2701 | ** |
| 2702 | ** [[SQLITE_LIMIT_COLUMN]] ^(<dt>SQLITE_LIMIT_COLUMN</dt> |
| 2703 | ** <dd>The maximum number of columns in a table definition or in the |
| 2704 | ** result set of a [SELECT] or the maximum number of columns in an index |
| 2705 | ** or in an ORDER BY or GROUP BY clause.</dd>)^ |
| 2706 | ** |
| 2707 | ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt> |
| 2708 | ** <dd>The maximum depth of the parse tree on any expression.</dd>)^ |
| 2709 | ** |
| 2710 | ** [[SQLITE_LIMIT_COMPOUND_SELECT]] ^(<dt>SQLITE_LIMIT_COMPOUND_SELECT</dt> |
| 2711 | ** <dd>The maximum number of terms in a compound SELECT statement.</dd>)^ |
| 2712 | ** |
| 2713 | ** [[SQLITE_LIMIT_VDBE_OP]] ^(<dt>SQLITE_LIMIT_VDBE_OP</dt> |
| 2714 | ** <dd>The maximum number of instructions in a virtual machine program |
| 2715 | ** used to implement an SQL statement. This limit is not currently |
| 2716 | ** enforced, though that might be added in some future release of |
| 2717 | ** SQLite.</dd>)^ |
| 2718 | ** |
| 2719 | ** [[SQLITE_LIMIT_FUNCTION_ARG]] ^(<dt>SQLITE_LIMIT_FUNCTION_ARG</dt> |
| 2720 | ** <dd>The maximum number of arguments on a function.</dd>)^ |
| 2721 | ** |
| 2722 | ** [[SQLITE_LIMIT_ATTACHED]] ^(<dt>SQLITE_LIMIT_ATTACHED</dt> |
| 2723 | ** <dd>The maximum number of [ATTACH | attached databases].)^</dd> |
| 2724 | ** |
| 2725 | ** [[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]] |
| 2726 | ** ^(<dt>SQLITE_LIMIT_LIKE_PATTERN_LENGTH</dt> |
| 2727 | ** <dd>The maximum length of the pattern argument to the [LIKE] or |
| 2728 | ** [GLOB] operators.</dd>)^ |
| 2729 | ** |
| 2730 | ** [[SQLITE_LIMIT_VARIABLE_NUMBER]] |
| 2731 | ** ^(<dt>SQLITE_LIMIT_VARIABLE_NUMBER</dt> |
| 2732 | ** <dd>The maximum index number of any [parameter] in an SQL statement.)^ |
| 2733 | ** |
| 2734 | ** [[SQLITE_LIMIT_TRIGGER_DEPTH]] ^(<dt>SQLITE_LIMIT_TRIGGER_DEPTH</dt> |
| 2735 | ** <dd>The maximum depth of recursion for triggers.</dd>)^ |
| 2736 | ** </dl> |
| 2737 | */ |
| 2738 | #define SQLITE_LIMIT_LENGTH 0 |
| 2739 | #define SQLITE_LIMIT_SQL_LENGTH 1 |
| @@ -4608,10 +4764,15 @@ | |
| 4764 | int (*xRollback)(sqlite3_vtab *pVTab); |
| 4765 | int (*xFindFunction)(sqlite3_vtab *pVtab, int nArg, const char *zName, |
| 4766 | void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), |
| 4767 | void **ppArg); |
| 4768 | int (*xRename)(sqlite3_vtab *pVtab, const char *zNew); |
| 4769 | /* The methods above are in version 1 of the sqlite_module object. Those |
| 4770 | ** below are for version 2 and greater. */ |
| 4771 | int (*xSavepoint)(sqlite3_vtab *pVTab, int); |
| 4772 | int (*xRelease)(sqlite3_vtab *pVTab, int); |
| 4773 | int (*xRollbackTo)(sqlite3_vtab *pVTab, int); |
| 4774 | }; |
| 4775 | |
| 4776 | /* |
| 4777 | ** CAPI3REF: Virtual Table Indexing Information |
| 4778 | ** KEYWORDS: sqlite3_index_info |
| @@ -5422,11 +5583,11 @@ | |
| 5583 | ** |
| 5584 | ** ^This interface is used to retrieve runtime status information |
| 5585 | ** about the performance of SQLite, and optionally to reset various |
| 5586 | ** highwater marks. ^The first argument is an integer code for |
| 5587 | ** the specific parameter to measure. ^(Recognized integer codes |
| 5588 | ** are of the form [status parameters | SQLITE_STATUS_...].)^ |
| 5589 | ** ^The current value of the parameter is returned into *pCurrent. |
| 5590 | ** ^The highest recorded value is returned in *pHighwater. ^If the |
| 5591 | ** resetFlag is true, then the highest record value is reset after |
| 5592 | ** *pHighwater is written. ^(Some parameters do not record the highest |
| 5593 | ** value. For those parameters |
| @@ -5449,82 +5610,84 @@ | |
| 5610 | SQLITE_API int sqlite3_status(int op, int *pCurrent, int *pHighwater, int resetFlag); |
| 5611 | |
| 5612 | |
| 5613 | /* |
| 5614 | ** CAPI3REF: Status Parameters |
| 5615 | ** KEYWORDS: {status parameters} |
| 5616 | ** |
| 5617 | ** These integer constants designate various run-time status parameters |
| 5618 | ** that can be returned by [sqlite3_status()]. |
| 5619 | ** |
| 5620 | ** <dl> |
| 5621 | ** [[SQLITE_STATUS_MEMORY_USED]] ^(<dt>SQLITE_STATUS_MEMORY_USED</dt> |
| 5622 | ** <dd>This parameter is the current amount of memory checked out |
| 5623 | ** using [sqlite3_malloc()], either directly or indirectly. The |
| 5624 | ** figure includes calls made to [sqlite3_malloc()] by the application |
| 5625 | ** and internal memory usage by the SQLite library. Scratch memory |
| 5626 | ** controlled by [SQLITE_CONFIG_SCRATCH] and auxiliary page-cache |
| 5627 | ** memory controlled by [SQLITE_CONFIG_PAGECACHE] is not included in |
| 5628 | ** this parameter. The amount returned is the sum of the allocation |
| 5629 | ** sizes as reported by the xSize method in [sqlite3_mem_methods].</dd>)^ |
| 5630 | ** |
| 5631 | ** [[SQLITE_STATUS_MALLOC_SIZE]] ^(<dt>SQLITE_STATUS_MALLOC_SIZE</dt> |
| 5632 | ** <dd>This parameter records the largest memory allocation request |
| 5633 | ** handed to [sqlite3_malloc()] or [sqlite3_realloc()] (or their |
| 5634 | ** internal equivalents). Only the value returned in the |
| 5635 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5636 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5637 | ** |
| 5638 | ** [[SQLITE_STATUS_MALLOC_COUNT]] ^(<dt>SQLITE_STATUS_MALLOC_COUNT</dt> |
| 5639 | ** <dd>This parameter records the number of separate memory allocations |
| 5640 | ** currently checked out.</dd>)^ |
| 5641 | ** |
| 5642 | ** [[SQLITE_STATUS_PAGECACHE_USED]] ^(<dt>SQLITE_STATUS_PAGECACHE_USED</dt> |
| 5643 | ** <dd>This parameter returns the number of pages used out of the |
| 5644 | ** [pagecache memory allocator] that was configured using |
| 5645 | ** [SQLITE_CONFIG_PAGECACHE]. The |
| 5646 | ** value returned is in pages, not in bytes.</dd>)^ |
| 5647 | ** |
| 5648 | ** [[SQLITE_STATUS_PAGECACHE_OVERFLOW]] |
| 5649 | ** ^(<dt>SQLITE_STATUS_PAGECACHE_OVERFLOW</dt> |
| 5650 | ** <dd>This parameter returns the number of bytes of page cache |
| 5651 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_PAGECACHE] |
| 5652 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The |
| 5653 | ** returned value includes allocations that overflowed because they |
| 5654 | ** where too large (they were larger than the "sz" parameter to |
| 5655 | ** [SQLITE_CONFIG_PAGECACHE]) and allocations that overflowed because |
| 5656 | ** no space was left in the page cache.</dd>)^ |
| 5657 | ** |
| 5658 | ** [[SQLITE_STATUS_PAGECACHE_SIZE]] ^(<dt>SQLITE_STATUS_PAGECACHE_SIZE</dt> |
| 5659 | ** <dd>This parameter records the largest memory allocation request |
| 5660 | ** handed to [pagecache memory allocator]. Only the value returned in the |
| 5661 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5662 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5663 | ** |
| 5664 | ** [[SQLITE_STATUS_SCRATCH_USED]] ^(<dt>SQLITE_STATUS_SCRATCH_USED</dt> |
| 5665 | ** <dd>This parameter returns the number of allocations used out of the |
| 5666 | ** [scratch memory allocator] configured using |
| 5667 | ** [SQLITE_CONFIG_SCRATCH]. The value returned is in allocations, not |
| 5668 | ** in bytes. Since a single thread may only have one scratch allocation |
| 5669 | ** outstanding at time, this parameter also reports the number of threads |
| 5670 | ** using scratch memory at the same time.</dd>)^ |
| 5671 | ** |
| 5672 | ** [[SQLITE_STATUS_SCRATCH_OVERFLOW]] ^(<dt>SQLITE_STATUS_SCRATCH_OVERFLOW</dt> |
| 5673 | ** <dd>This parameter returns the number of bytes of scratch memory |
| 5674 | ** allocation which could not be satisfied by the [SQLITE_CONFIG_SCRATCH] |
| 5675 | ** buffer and where forced to overflow to [sqlite3_malloc()]. The values |
| 5676 | ** returned include overflows because the requested allocation was too |
| 5677 | ** larger (that is, because the requested allocation was larger than the |
| 5678 | ** "sz" parameter to [SQLITE_CONFIG_SCRATCH]) and because no scratch buffer |
| 5679 | ** slots were available. |
| 5680 | ** </dd>)^ |
| 5681 | ** |
| 5682 | ** [[SQLITE_STATUS_SCRATCH_SIZE]] ^(<dt>SQLITE_STATUS_SCRATCH_SIZE</dt> |
| 5683 | ** <dd>This parameter records the largest memory allocation request |
| 5684 | ** handed to [scratch memory allocator]. Only the value returned in the |
| 5685 | ** *pHighwater parameter to [sqlite3_status()] is of interest. |
| 5686 | ** The value written into the *pCurrent parameter is undefined.</dd>)^ |
| 5687 | ** |
| 5688 | ** [[SQLITE_STATUS_PARSER_STACK]] ^(<dt>SQLITE_STATUS_PARSER_STACK</dt> |
| 5689 | ** <dd>This parameter records the deepest parser stack. It is only |
| 5690 | ** meaningful if SQLite is compiled with [YYTRACKMAXSTACKDEPTH].</dd>)^ |
| 5691 | ** </dl> |
| 5692 | ** |
| 5693 | ** New status parameters may be added from time to time. |
| @@ -5545,13 +5708,13 @@ | |
| 5708 | ** |
| 5709 | ** ^This interface is used to retrieve runtime status information |
| 5710 | ** about a single [database connection]. ^The first argument is the |
| 5711 | ** database connection object to be interrogated. ^The second argument |
| 5712 | ** is an integer constant, taken from the set of |
| 5713 | ** [SQLITE_DBSTATUS options], that |
| 5714 | ** determines the parameter to interrogate. The set of |
| 5715 | ** [SQLITE_DBSTATUS options] is likely |
| 5716 | ** to grow in future releases of SQLite. |
| 5717 | ** |
| 5718 | ** ^The current value of the requested parameter is written into *pCur |
| 5719 | ** and the highest instantaneous value is written into *pHiwtr. ^If |
| 5720 | ** the resetFlg is true, then the highest instantaneous value is |
| @@ -5564,10 +5727,11 @@ | |
| 5727 | */ |
| 5728 | SQLITE_API int sqlite3_db_status(sqlite3*, int op, int *pCur, int *pHiwtr, int resetFlg); |
| 5729 | |
| 5730 | /* |
| 5731 | ** CAPI3REF: Status Parameters for database connections |
| 5732 | ** KEYWORDS: {SQLITE_DBSTATUS options} |
| 5733 | ** |
| 5734 | ** These constants are the available integer "verbs" that can be passed as |
| 5735 | ** the second argument to the [sqlite3_db_status()] interface. |
| 5736 | ** |
| 5737 | ** New verbs may be added in future releases of SQLite. Existing verbs |
| @@ -5575,48 +5739,50 @@ | |
| 5739 | ** [sqlite3_db_status()] to make sure that the call worked. |
| 5740 | ** The [sqlite3_db_status()] interface will return a non-zero error code |
| 5741 | ** if a discontinued or unsupported verb is invoked. |
| 5742 | ** |
| 5743 | ** <dl> |
| 5744 | ** [[SQLITE_DBSTATUS_LOOKASIDE_USED]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_USED</dt> |
| 5745 | ** <dd>This parameter returns the number of lookaside memory slots currently |
| 5746 | ** checked out.</dd>)^ |
| 5747 | ** |
| 5748 | ** [[SQLITE_DBSTATUS_LOOKASIDE_HIT]] ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_HIT</dt> |
| 5749 | ** <dd>This parameter returns the number malloc attempts that were |
| 5750 | ** satisfied using lookaside memory. Only the high-water value is meaningful; |
| 5751 | ** the current value is always zero.)^ |
| 5752 | ** |
| 5753 | ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE]] |
| 5754 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_SIZE</dt> |
| 5755 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5756 | ** been satisfied using lookaside memory but failed due to the amount of |
| 5757 | ** memory requested being larger than the lookaside slot size. |
| 5758 | ** Only the high-water value is meaningful; |
| 5759 | ** the current value is always zero.)^ |
| 5760 | ** |
| 5761 | ** [[SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL]] |
| 5762 | ** ^(<dt>SQLITE_DBSTATUS_LOOKASIDE_MISS_FULL</dt> |
| 5763 | ** <dd>This parameter returns the number malloc attempts that might have |
| 5764 | ** been satisfied using lookaside memory but failed due to all lookaside |
| 5765 | ** memory already being in use. |
| 5766 | ** Only the high-water value is meaningful; |
| 5767 | ** the current value is always zero.)^ |
| 5768 | ** |
| 5769 | ** [[SQLITE_DBSTATUS_CACHE_USED]] ^(<dt>SQLITE_DBSTATUS_CACHE_USED</dt> |
| 5770 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5771 | ** memory used by all pager caches associated with the database connection.)^ |
| 5772 | ** ^The highwater mark associated with SQLITE_DBSTATUS_CACHE_USED is always 0. |
| 5773 | ** |
| 5774 | ** [[SQLITE_DBSTATUS_SCHEMA_USED]] ^(<dt>SQLITE_DBSTATUS_SCHEMA_USED</dt> |
| 5775 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5776 | ** memory used to store the schema for all databases associated |
| 5777 | ** with the connection - main, temp, and any [ATTACH]-ed databases.)^ |
| 5778 | ** ^The full amount of memory used by the schemas is reported, even if the |
| 5779 | ** schema memory is shared with other database connections due to |
| 5780 | ** [shared cache mode] being enabled. |
| 5781 | ** ^The highwater mark associated with SQLITE_DBSTATUS_SCHEMA_USED is always 0. |
| 5782 | ** |
| 5783 | ** [[SQLITE_DBSTATUS_STMT_USED]] ^(<dt>SQLITE_DBSTATUS_STMT_USED</dt> |
| 5784 | ** <dd>This parameter returns the approximate number of of bytes of heap |
| 5785 | ** and lookaside memory used by all prepared statements associated with |
| 5786 | ** the database connection.)^ |
| 5787 | ** ^The highwater mark associated with SQLITE_DBSTATUS_STMT_USED is always 0. |
| 5788 | ** </dd> |
| @@ -5634,11 +5800,11 @@ | |
| 5800 | |
| 5801 | /* |
| 5802 | ** CAPI3REF: Prepared Statement Status |
| 5803 | ** |
| 5804 | ** ^(Each prepared statement maintains various |
| 5805 | ** [SQLITE_STMTSTATUS counters] that measure the number |
| 5806 | ** of times it has performed specific operations.)^ These counters can |
| 5807 | ** be used to monitor the performance characteristics of the prepared |
| 5808 | ** statements. For example, if the number of table steps greatly exceeds |
| 5809 | ** the number of table searches or result rows, that would tend to indicate |
| 5810 | ** that the prepared statement is using a full table scan rather than |
| @@ -5645,11 +5811,11 @@ | |
| 5811 | ** an index. |
| 5812 | ** |
| 5813 | ** ^(This interface is used to retrieve and reset counter values from |
| 5814 | ** a [prepared statement]. The first argument is the prepared statement |
| 5815 | ** object to be interrogated. The second argument |
| 5816 | ** is an integer code for a specific [SQLITE_STMTSTATUS counter] |
| 5817 | ** to be interrogated.)^ |
| 5818 | ** ^The current value of the requested counter is returned. |
| 5819 | ** ^If the resetFlg is true, then the counter is reset to zero after this |
| 5820 | ** interface call returns. |
| 5821 | ** |
| @@ -5657,28 +5823,29 @@ | |
| 5823 | */ |
| 5824 | SQLITE_API int sqlite3_stmt_status(sqlite3_stmt*, int op,int resetFlg); |
| 5825 | |
| 5826 | /* |
| 5827 | ** CAPI3REF: Status Parameters for prepared statements |
| 5828 | ** KEYWORDS: {SQLITE_STMTSTATUS counter} {SQLITE_STMTSTATUS counters} |
| 5829 | ** |
| 5830 | ** These preprocessor macros define integer codes that name counter |
| 5831 | ** values associated with the [sqlite3_stmt_status()] interface. |
| 5832 | ** The meanings of the various counters are as follows: |
| 5833 | ** |
| 5834 | ** <dl> |
| 5835 | ** [[SQLITE_STMTSTATUS_FULLSCAN_STEP]] <dt>SQLITE_STMTSTATUS_FULLSCAN_STEP</dt> |
| 5836 | ** <dd>^This is the number of times that SQLite has stepped forward in |
| 5837 | ** a table as part of a full table scan. Large numbers for this counter |
| 5838 | ** may indicate opportunities for performance improvement through |
| 5839 | ** careful use of indices.</dd> |
| 5840 | ** |
| 5841 | ** [[SQLITE_STMTSTATUS_SORT]] <dt>SQLITE_STMTSTATUS_SORT</dt> |
| 5842 | ** <dd>^This is the number of sort operations that have occurred. |
| 5843 | ** A non-zero value in this counter may indicate an opportunity to |
| 5844 | ** improvement performance through careful use of indices.</dd> |
| 5845 | ** |
| 5846 | ** [[SQLITE_STMTSTATUS_AUTOINDEX]] <dt>SQLITE_STMTSTATUS_AUTOINDEX</dt> |
| 5847 | ** <dd>^This is the number of rows inserted into transient indices that |
| 5848 | ** were created automatically in order to help joins run faster. |
| 5849 | ** A non-zero value in this counter may indicate an opportunity to |
| 5850 | ** improvement performance by adding permanent indices that do not |
| 5851 | ** need to be reinitialized each time the statement is run.</dd> |
| @@ -5725,10 +5892,11 @@ | |
| 5892 | ** ^(The contents of the sqlite3_pcache_methods structure are copied to an |
| 5893 | ** internal buffer by SQLite within the call to [sqlite3_config]. Hence |
| 5894 | ** the application may discard the parameter after the call to |
| 5895 | ** [sqlite3_config()] returns.)^ |
| 5896 | ** |
| 5897 | ** [[the xInit() page cache method]] |
| 5898 | ** ^(The xInit() method is called once for each effective |
| 5899 | ** call to [sqlite3_initialize()])^ |
| 5900 | ** (usually only once during the lifetime of the process). ^(The xInit() |
| 5901 | ** method is passed a copy of the sqlite3_pcache_methods.pArg value.)^ |
| 5902 | ** The intent of the xInit() method is to set up global data structures |
| @@ -5735,10 +5903,11 @@ | |
| 5903 | ** required by the custom page cache implementation. |
| 5904 | ** ^(If the xInit() method is NULL, then the |
| 5905 | ** built-in default page cache is used instead of the application defined |
| 5906 | ** page cache.)^ |
| 5907 | ** |
| 5908 | ** [[the xShutdown() page cache method]] |
| 5909 | ** ^The xShutdown() method is called by [sqlite3_shutdown()]. |
| 5910 | ** It can be used to clean up |
| 5911 | ** any outstanding resources before process shutdown, if required. |
| 5912 | ** ^The xShutdown() method may be NULL. |
| 5913 | ** |
| @@ -5749,10 +5918,11 @@ | |
| 5918 | ** in multithreaded applications. |
| 5919 | ** |
| 5920 | ** ^SQLite will never invoke xInit() more than once without an intervening |
| 5921 | ** call to xShutdown(). |
| 5922 | ** |
| 5923 | ** [[the xCreate() page cache methods]] |
| 5924 | ** ^SQLite invokes the xCreate() method to construct a new cache instance. |
| 5925 | ** SQLite will typically create one cache instance for each open database file, |
| 5926 | ** though this is not guaranteed. ^The |
| 5927 | ** first parameter, szPage, is the size in bytes of the pages that must |
| 5928 | ** be allocated by the cache. ^szPage will not be a power of two. ^szPage |
| @@ -5773,20 +5943,23 @@ | |
| 5943 | ** ^In other words, calls to xUnpin() on a cache with bPurgeable set to |
| 5944 | ** false will always have the "discard" flag set to true. |
| 5945 | ** ^Hence, a cache created with bPurgeable false will |
| 5946 | ** never contain any unpinned pages. |
| 5947 | ** |
| 5948 | ** [[the xCachesize() page cache method]] |
| 5949 | ** ^(The xCachesize() method may be called at any time by SQLite to set the |
| 5950 | ** suggested maximum cache-size (number of pages stored by) the cache |
| 5951 | ** instance passed as the first argument. This is the value configured using |
| 5952 | ** the SQLite "[PRAGMA cache_size]" command.)^ As with the bPurgeable |
| 5953 | ** parameter, the implementation is not required to do anything with this |
| 5954 | ** value; it is advisory only. |
| 5955 | ** |
| 5956 | ** [[the xPagecount() page cache methods]] |
| 5957 | ** The xPagecount() method must return the number of pages currently |
| 5958 | ** stored in the cache, both pinned and unpinned. |
| 5959 | ** |
| 5960 | ** [[the xFetch() page cache methods]] |
| 5961 | ** The xFetch() method locates a page in the cache and returns a pointer to |
| 5962 | ** the page, or a NULL pointer. |
| 5963 | ** A "page", in this context, means a buffer of szPage bytes aligned at an |
| 5964 | ** 8-byte boundary. The page to be fetched is determined by the key. ^The |
| 5965 | ** mimimum key value is 1. After it has been retrieved using xFetch, the page |
| @@ -5811,10 +5984,11 @@ | |
| 5984 | ** will only use a createFlag of 2 after a prior call with a createFlag of 1 |
| 5985 | ** failed.)^ In between the to xFetch() calls, SQLite may |
| 5986 | ** attempt to unpin one or more cache pages by spilling the content of |
| 5987 | ** pinned pages to disk and synching the operating system disk cache. |
| 5988 | ** |
| 5989 | ** [[the xUnpin() page cache method]] |
| 5990 | ** ^xUnpin() is called by SQLite with a pointer to a currently pinned page |
| 5991 | ** as its second argument. If the third parameter, discard, is non-zero, |
| 5992 | ** then the page must be evicted from the cache. |
| 5993 | ** ^If the discard parameter is |
| 5994 | ** zero, then the page may be discarded or retained at the discretion of |
| @@ -5823,10 +5997,11 @@ | |
| 5997 | ** |
| 5998 | ** The cache must not perform any reference counting. A single |
| 5999 | ** call to xUnpin() unpins the page regardless of the number of prior calls |
| 6000 | ** to xFetch(). |
| 6001 | ** |
| 6002 | ** [[the xRekey() page cache methods]] |
| 6003 | ** The xRekey() method is used to change the key value associated with the |
| 6004 | ** page passed as the second argument. If the cache |
| 6005 | ** previously contains an entry associated with newKey, it must be |
| 6006 | ** discarded. ^Any prior cache entry associated with newKey is guaranteed not |
| 6007 | ** to be pinned. |
| @@ -5835,10 +6010,11 @@ | |
| 6010 | ** existing cache entries with page numbers (keys) greater than or equal |
| 6011 | ** to the value of the iLimit parameter passed to xTruncate(). If any |
| 6012 | ** of these pages are pinned, they are implicitly unpinned, meaning that |
| 6013 | ** they can be safely discarded. |
| 6014 | ** |
| 6015 | ** [[the xDestroy() page cache method]] |
| 6016 | ** ^The xDestroy() method is used to delete a cache allocated by xCreate(). |
| 6017 | ** All resources associated with the specified cache should be freed. ^After |
| 6018 | ** calling the xDestroy() method, SQLite considers the [sqlite3_pcache*] |
| 6019 | ** handle invalid, and will not use it with any other sqlite3_pcache_methods |
| 6020 | ** functions. |
| @@ -5897,11 +6073,11 @@ | |
| 6073 | ** associated with the backup operation. |
| 6074 | ** </ol>)^ |
| 6075 | ** There should be exactly one call to sqlite3_backup_finish() for each |
| 6076 | ** successful call to sqlite3_backup_init(). |
| 6077 | ** |
| 6078 | ** [[sqlite3_backup_init()]] <b>sqlite3_backup_init()</b> |
| 6079 | ** |
| 6080 | ** ^The D and N arguments to sqlite3_backup_init(D,N,S,M) are the |
| 6081 | ** [database connection] associated with the destination database |
| 6082 | ** and the database name, respectively. |
| 6083 | ** ^The database name is "main" for the main database, "temp" for the |
| @@ -5924,11 +6100,11 @@ | |
| 6100 | ** [sqlite3_backup] object. |
| 6101 | ** ^The [sqlite3_backup] object may be used with the sqlite3_backup_step() and |
| 6102 | ** sqlite3_backup_finish() functions to perform the specified backup |
| 6103 | ** operation. |
| 6104 | ** |
| 6105 | ** [[sqlite3_backup_step()]] <b>sqlite3_backup_step()</b> |
| 6106 | ** |
| 6107 | ** ^Function sqlite3_backup_step(B,N) will copy up to N pages between |
| 6108 | ** the source and destination databases specified by [sqlite3_backup] object B. |
| 6109 | ** ^If N is negative, all remaining source pages are copied. |
| 6110 | ** ^If sqlite3_backup_step(B,N) successfully copies N pages and there |
| @@ -5981,11 +6157,11 @@ | |
| 6157 | ** restarted by the next call to sqlite3_backup_step(). ^If the source |
| 6158 | ** database is modified by the using the same database connection as is used |
| 6159 | ** by the backup operation, then the backup database is automatically |
| 6160 | ** updated at the same time. |
| 6161 | ** |
| 6162 | ** [[sqlite3_backup_finish()]] <b>sqlite3_backup_finish()</b> |
| 6163 | ** |
| 6164 | ** When sqlite3_backup_step() has returned [SQLITE_DONE], or when the |
| 6165 | ** application wishes to abandon the backup operation, the application |
| 6166 | ** should destroy the [sqlite3_backup] by passing it to sqlite3_backup_finish(). |
| 6167 | ** ^The sqlite3_backup_finish() interfaces releases all |
| @@ -6004,11 +6180,12 @@ | |
| 6180 | ** |
| 6181 | ** ^A return of [SQLITE_BUSY] or [SQLITE_LOCKED] from sqlite3_backup_step() |
| 6182 | ** is not a permanent error and does not affect the return value of |
| 6183 | ** sqlite3_backup_finish(). |
| 6184 | ** |
| 6185 | ** [[sqlite3_backup__remaining()]] [[sqlite3_backup_pagecount()]] |
| 6186 | ** <b>sqlite3_backup_remaining() and sqlite3_backup_pagecount()</b> |
| 6187 | ** |
| 6188 | ** ^Each call to sqlite3_backup_step() sets two values inside |
| 6189 | ** the [sqlite3_backup] object: the number of pages still to be backed |
| 6190 | ** up and the total number of pages in the source database file. |
| 6191 | ** The sqlite3_backup_remaining() and sqlite3_backup_pagecount() interfaces |
| @@ -6389,10 +6566,97 @@ | |
| 6566 | ** each of these values. |
| 6567 | */ |
| 6568 | #define SQLITE_CHECKPOINT_PASSIVE 0 |
| 6569 | #define SQLITE_CHECKPOINT_FULL 1 |
| 6570 | #define SQLITE_CHECKPOINT_RESTART 2 |
| 6571 | |
| 6572 | /* |
| 6573 | ** CAPI3REF: Virtual Table Interface Configuration |
| 6574 | ** |
| 6575 | ** This function may be called by either the [xConnect] or [xCreate] method |
| 6576 | ** of a [virtual table] implementation to configure |
| 6577 | ** various facets of the virtual table interface. |
| 6578 | ** |
| 6579 | ** If this interface is invoked outside the context of an xConnect or |
| 6580 | ** xCreate virtual table method then the behavior is undefined. |
| 6581 | ** |
| 6582 | ** At present, there is only one option that may be configured using |
| 6583 | ** this function. (See [SQLITE_VTAB_CONSTRAINT_SUPPORT].) Further options |
| 6584 | ** may be added in the future. |
| 6585 | */ |
| 6586 | SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...); |
| 6587 | |
| 6588 | /* |
| 6589 | ** CAPI3REF: Virtual Table Configuration Options |
| 6590 | ** |
| 6591 | ** These macros define the various options to the |
| 6592 | ** [sqlite3_vtab_config()] interface that [virtual table] implementations |
| 6593 | ** can use to customize and optimize their behavior. |
| 6594 | ** |
| 6595 | ** <dl> |
| 6596 | ** <dt>SQLITE_VTAB_CONSTRAINT_SUPPORT |
| 6597 | ** <dd>Calls of the form |
| 6598 | ** [sqlite3_vtab_config](db,SQLITE_VTAB_CONSTRAINT_SUPPORT,X) are supported, |
| 6599 | ** where X is an integer. If X is zero, then the [virtual table] whose |
| 6600 | ** [xCreate] or [xConnect] method invoked [sqlite3_vtab_config()] does not |
| 6601 | ** support constraints. In this configuration (which is the default) if |
| 6602 | ** a call to the [xUpdate] method returns [SQLITE_CONSTRAINT], then the entire |
| 6603 | ** statement is rolled back as if [ON CONFLICT | OR ABORT] had been |
| 6604 | ** specified as part of the users SQL statement, regardless of the actual |
| 6605 | ** ON CONFLICT mode specified. |
| 6606 | ** |
| 6607 | ** If X is non-zero, then the virtual table implementation guarantees |
| 6608 | ** that if [xUpdate] returns [SQLITE_CONSTRAINT], it will do so before |
| 6609 | ** any modifications to internal or persistent data structures have been made. |
| 6610 | ** If the [ON CONFLICT] mode is ABORT, FAIL, IGNORE or ROLLBACK, SQLite |
| 6611 | ** is able to roll back a statement or database transaction, and abandon |
| 6612 | ** or continue processing the current SQL statement as appropriate. |
| 6613 | ** If the ON CONFLICT mode is REPLACE and the [xUpdate] method returns |
| 6614 | ** [SQLITE_CONSTRAINT], SQLite handles this as if the ON CONFLICT mode |
| 6615 | ** had been ABORT. |
| 6616 | ** |
| 6617 | ** Virtual table implementations that are required to handle OR REPLACE |
| 6618 | ** must do so within the [xUpdate] method. If a call to the |
| 6619 | ** [sqlite3_vtab_on_conflict()] function indicates that the current ON |
| 6620 | ** CONFLICT policy is REPLACE, the virtual table implementation should |
| 6621 | ** silently replace the appropriate rows within the xUpdate callback and |
| 6622 | ** return SQLITE_OK. Or, if this is not possible, it may return |
| 6623 | ** SQLITE_CONSTRAINT, in which case SQLite falls back to OR ABORT |
| 6624 | ** constraint handling. |
| 6625 | ** </dl> |
| 6626 | */ |
| 6627 | #define SQLITE_VTAB_CONSTRAINT_SUPPORT 1 |
| 6628 | |
| 6629 | /* |
| 6630 | ** CAPI3REF: Determine The Virtual Table Conflict Policy |
| 6631 | ** |
| 6632 | ** This function may only be called from within a call to the [xUpdate] method |
| 6633 | ** of a [virtual table] implementation for an INSERT or UPDATE operation. ^The |
| 6634 | ** value returned is one of [SQLITE_ROLLBACK], [SQLITE_IGNORE], [SQLITE_FAIL], |
| 6635 | ** [SQLITE_ABORT], or [SQLITE_REPLACE], according to the [ON CONFLICT] mode |
| 6636 | ** of the SQL statement that triggered the call to the [xUpdate] method of the |
| 6637 | ** [virtual table]. |
| 6638 | */ |
| 6639 | SQLITE_API int sqlite3_vtab_on_conflict(sqlite3 *); |
| 6640 | |
| 6641 | /* |
| 6642 | ** CAPI3REF: Conflict resolution modes |
| 6643 | ** |
| 6644 | ** These constants are returned by [sqlite3_vtab_on_conflict()] to |
| 6645 | ** inform a [virtual table] implementation what the [ON CONFLICT] mode |
| 6646 | ** is for the SQL statement being evaluated. |
| 6647 | ** |
| 6648 | ** Note that the [SQLITE_IGNORE] constant is also used as a potential |
| 6649 | ** return value from the [sqlite3_set_authorizer()] callback and that |
| 6650 | ** [SQLITE_ABORT] is also a [result code]. |
| 6651 | */ |
| 6652 | #define SQLITE_ROLLBACK 1 |
| 6653 | /* #define SQLITE_IGNORE 2 // Also used by sqlite3_authorizer() callback */ |
| 6654 | #define SQLITE_FAIL 3 |
| 6655 | /* #define SQLITE_ABORT 4 // Also an error code */ |
| 6656 | #define SQLITE_REPLACE 5 |
| 6657 | |
| 6658 | |
| 6659 | |
| 6660 | /* |
| 6661 | ** Undo the hack that converts floating point types to integer for |
| 6662 | ** builds on processors without floating point support. |
| 6663 |
+14
-14
| --- src/stash.c | ||
| +++ src/stash.c | ||
| @@ -185,33 +185,33 @@ | ||
| 185 | 185 | blob_zero(&delta); |
| 186 | 186 | if( rid==0 ){ |
| 187 | 187 | db_ephemeral_blob(&q, 5, &delta); |
| 188 | 188 | blob_write_to_file(&delta, zNPath); |
| 189 | 189 | file_setexe(zNPath, isExec); |
| 190 | - printf("ADD %s\n", zNew); | |
| 190 | + fossil_print("ADD %s\n", zNew); | |
| 191 | 191 | }else if( isRemoved ){ |
| 192 | - printf("DELETE %s\n", zOrig); | |
| 193 | - unlink(zOPath); | |
| 192 | + fossil_print("DELETE %s\n", zOrig); | |
| 193 | + file_delete(zOPath); | |
| 194 | 194 | }else{ |
| 195 | 195 | Blob a, b, out, disk; |
| 196 | 196 | db_ephemeral_blob(&q, 5, &delta); |
| 197 | 197 | blob_read_from_file(&disk, zOPath); |
| 198 | 198 | content_get(rid, &a); |
| 199 | 199 | blob_delta_apply(&a, &delta, &b); |
| 200 | 200 | if( blob_compare(&disk, &a)==0 ){ |
| 201 | 201 | blob_write_to_file(&b, zNPath); |
| 202 | 202 | file_setexe(zNPath, isExec); |
| 203 | - printf("UPDATE %s\n", zNew); | |
| 203 | + fossil_print("UPDATE %s\n", zNew); | |
| 204 | 204 | }else{ |
| 205 | 205 | int rc = merge_3way(&a, zOPath, &b, &out); |
| 206 | 206 | blob_write_to_file(&out, zNPath); |
| 207 | 207 | file_setexe(zNPath, isExec); |
| 208 | 208 | if( rc ){ |
| 209 | - printf("CONFLICT %s\n", zNew); | |
| 209 | + fossil_print("CONFLICT %s\n", zNew); | |
| 210 | 210 | nConflict++; |
| 211 | 211 | }else{ |
| 212 | - printf("MERGE %s\n", zNew); | |
| 212 | + fossil_print("MERGE %s\n", zNew); | |
| 213 | 213 | } |
| 214 | 214 | blob_reset(&out); |
| 215 | 215 | } |
| 216 | 216 | blob_reset(&a); |
| 217 | 217 | blob_reset(&b); |
| @@ -218,16 +218,16 @@ | ||
| 218 | 218 | blob_reset(&disk); |
| 219 | 219 | } |
| 220 | 220 | blob_reset(&delta); |
| 221 | 221 | if( fossil_strcmp(zOrig,zNew)!=0 ){ |
| 222 | 222 | undo_save(zOrig); |
| 223 | - unlink(zOPath); | |
| 223 | + file_delete(zOPath); | |
| 224 | 224 | } |
| 225 | 225 | } |
| 226 | 226 | db_finalize(&q); |
| 227 | 227 | if( nConflict ){ |
| 228 | - printf("WARNING: merge conflicts - see messages above for details.\n"); | |
| 228 | + fossil_print("WARNING: merge conflicts - see messages above for details.\n"); | |
| 229 | 229 | } |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | /* |
| 233 | 233 | ** Show the diffs associate with a single stash. |
| @@ -248,25 +248,25 @@ | ||
| 248 | 248 | const char *zNew = db_column_text(&q, 4); |
| 249 | 249 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 250 | 250 | Blob delta; |
| 251 | 251 | if( rid==0 ){ |
| 252 | 252 | db_ephemeral_blob(&q, 5, &delta); |
| 253 | - printf("ADDED %s\n", zNew); | |
| 253 | + fossil_print("ADDED %s\n", zNew); | |
| 254 | 254 | diff_print_index(zNew); |
| 255 | 255 | diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0); |
| 256 | 256 | }else if( isRemoved ){ |
| 257 | - printf("DELETE %s\n", zOrig); | |
| 257 | + fossil_print("DELETE %s\n", zOrig); | |
| 258 | 258 | blob_read_from_file(&delta, zOPath); |
| 259 | 259 | diff_print_index(zNew); |
| 260 | 260 | diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0); |
| 261 | 261 | }else{ |
| 262 | 262 | Blob a, b, disk; |
| 263 | 263 | db_ephemeral_blob(&q, 5, &delta); |
| 264 | 264 | blob_read_from_file(&disk, zOPath); |
| 265 | 265 | content_get(rid, &a); |
| 266 | 266 | blob_delta_apply(&a, &delta, &b); |
| 267 | - printf("CHANGED %s\n", zNew); | |
| 267 | + fossil_print("CHANGED %s\n", zNew); | |
| 268 | 268 | diff_file_mem(&disk, &b, zNew, zDiffCmd, 0); |
| 269 | 269 | blob_reset(&a); |
| 270 | 270 | blob_reset(&b); |
| 271 | 271 | blob_reset(&disk); |
| 272 | 272 | } |
| @@ -413,23 +413,23 @@ | ||
| 413 | 413 | " ORDER BY ctime DESC" |
| 414 | 414 | ); |
| 415 | 415 | while( db_step(&q)==SQLITE_ROW ){ |
| 416 | 416 | const char *zCom; |
| 417 | 417 | n++; |
| 418 | - printf("%5d: [%.14s] on %s\n", | |
| 418 | + fossil_print("%5d: [%.14s] on %s\n", | |
| 419 | 419 | db_column_int(&q, 0), |
| 420 | 420 | db_column_text(&q, 1), |
| 421 | 421 | db_column_text(&q, 3) |
| 422 | 422 | ); |
| 423 | 423 | zCom = db_column_text(&q, 2); |
| 424 | 424 | if( zCom && zCom[0] ){ |
| 425 | - printf(" "); | |
| 425 | + fossil_print(" "); | |
| 426 | 426 | comment_print(zCom, 7, 79); |
| 427 | 427 | } |
| 428 | 428 | } |
| 429 | 429 | db_finalize(&q); |
| 430 | - if( n==0 ) printf("empty stash\n"); | |
| 430 | + if( n==0 ) fossil_print("empty stash\n"); | |
| 431 | 431 | }else |
| 432 | 432 | if( memcmp(zCmd, "drop", nCmd)==0 ){ |
| 433 | 433 | int allFlag = find_option("all", 0, 0)!=0; |
| 434 | 434 | if( g.argc>4 ) usage("stash apply STASHID"); |
| 435 | 435 | if( allFlag ){ |
| 436 | 436 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -185,33 +185,33 @@ | |
| 185 | blob_zero(&delta); |
| 186 | if( rid==0 ){ |
| 187 | db_ephemeral_blob(&q, 5, &delta); |
| 188 | blob_write_to_file(&delta, zNPath); |
| 189 | file_setexe(zNPath, isExec); |
| 190 | printf("ADD %s\n", zNew); |
| 191 | }else if( isRemoved ){ |
| 192 | printf("DELETE %s\n", zOrig); |
| 193 | unlink(zOPath); |
| 194 | }else{ |
| 195 | Blob a, b, out, disk; |
| 196 | db_ephemeral_blob(&q, 5, &delta); |
| 197 | blob_read_from_file(&disk, zOPath); |
| 198 | content_get(rid, &a); |
| 199 | blob_delta_apply(&a, &delta, &b); |
| 200 | if( blob_compare(&disk, &a)==0 ){ |
| 201 | blob_write_to_file(&b, zNPath); |
| 202 | file_setexe(zNPath, isExec); |
| 203 | printf("UPDATE %s\n", zNew); |
| 204 | }else{ |
| 205 | int rc = merge_3way(&a, zOPath, &b, &out); |
| 206 | blob_write_to_file(&out, zNPath); |
| 207 | file_setexe(zNPath, isExec); |
| 208 | if( rc ){ |
| 209 | printf("CONFLICT %s\n", zNew); |
| 210 | nConflict++; |
| 211 | }else{ |
| 212 | printf("MERGE %s\n", zNew); |
| 213 | } |
| 214 | blob_reset(&out); |
| 215 | } |
| 216 | blob_reset(&a); |
| 217 | blob_reset(&b); |
| @@ -218,16 +218,16 @@ | |
| 218 | blob_reset(&disk); |
| 219 | } |
| 220 | blob_reset(&delta); |
| 221 | if( fossil_strcmp(zOrig,zNew)!=0 ){ |
| 222 | undo_save(zOrig); |
| 223 | unlink(zOPath); |
| 224 | } |
| 225 | } |
| 226 | db_finalize(&q); |
| 227 | if( nConflict ){ |
| 228 | printf("WARNING: merge conflicts - see messages above for details.\n"); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | ** Show the diffs associate with a single stash. |
| @@ -248,25 +248,25 @@ | |
| 248 | const char *zNew = db_column_text(&q, 4); |
| 249 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 250 | Blob delta; |
| 251 | if( rid==0 ){ |
| 252 | db_ephemeral_blob(&q, 5, &delta); |
| 253 | printf("ADDED %s\n", zNew); |
| 254 | diff_print_index(zNew); |
| 255 | diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0); |
| 256 | }else if( isRemoved ){ |
| 257 | printf("DELETE %s\n", zOrig); |
| 258 | blob_read_from_file(&delta, zOPath); |
| 259 | diff_print_index(zNew); |
| 260 | diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0); |
| 261 | }else{ |
| 262 | Blob a, b, disk; |
| 263 | db_ephemeral_blob(&q, 5, &delta); |
| 264 | blob_read_from_file(&disk, zOPath); |
| 265 | content_get(rid, &a); |
| 266 | blob_delta_apply(&a, &delta, &b); |
| 267 | printf("CHANGED %s\n", zNew); |
| 268 | diff_file_mem(&disk, &b, zNew, zDiffCmd, 0); |
| 269 | blob_reset(&a); |
| 270 | blob_reset(&b); |
| 271 | blob_reset(&disk); |
| 272 | } |
| @@ -413,23 +413,23 @@ | |
| 413 | " ORDER BY ctime DESC" |
| 414 | ); |
| 415 | while( db_step(&q)==SQLITE_ROW ){ |
| 416 | const char *zCom; |
| 417 | n++; |
| 418 | printf("%5d: [%.14s] on %s\n", |
| 419 | db_column_int(&q, 0), |
| 420 | db_column_text(&q, 1), |
| 421 | db_column_text(&q, 3) |
| 422 | ); |
| 423 | zCom = db_column_text(&q, 2); |
| 424 | if( zCom && zCom[0] ){ |
| 425 | printf(" "); |
| 426 | comment_print(zCom, 7, 79); |
| 427 | } |
| 428 | } |
| 429 | db_finalize(&q); |
| 430 | if( n==0 ) printf("empty stash\n"); |
| 431 | }else |
| 432 | if( memcmp(zCmd, "drop", nCmd)==0 ){ |
| 433 | int allFlag = find_option("all", 0, 0)!=0; |
| 434 | if( g.argc>4 ) usage("stash apply STASHID"); |
| 435 | if( allFlag ){ |
| 436 |
| --- src/stash.c | |
| +++ src/stash.c | |
| @@ -185,33 +185,33 @@ | |
| 185 | blob_zero(&delta); |
| 186 | if( rid==0 ){ |
| 187 | db_ephemeral_blob(&q, 5, &delta); |
| 188 | blob_write_to_file(&delta, zNPath); |
| 189 | file_setexe(zNPath, isExec); |
| 190 | fossil_print("ADD %s\n", zNew); |
| 191 | }else if( isRemoved ){ |
| 192 | fossil_print("DELETE %s\n", zOrig); |
| 193 | file_delete(zOPath); |
| 194 | }else{ |
| 195 | Blob a, b, out, disk; |
| 196 | db_ephemeral_blob(&q, 5, &delta); |
| 197 | blob_read_from_file(&disk, zOPath); |
| 198 | content_get(rid, &a); |
| 199 | blob_delta_apply(&a, &delta, &b); |
| 200 | if( blob_compare(&disk, &a)==0 ){ |
| 201 | blob_write_to_file(&b, zNPath); |
| 202 | file_setexe(zNPath, isExec); |
| 203 | fossil_print("UPDATE %s\n", zNew); |
| 204 | }else{ |
| 205 | int rc = merge_3way(&a, zOPath, &b, &out); |
| 206 | blob_write_to_file(&out, zNPath); |
| 207 | file_setexe(zNPath, isExec); |
| 208 | if( rc ){ |
| 209 | fossil_print("CONFLICT %s\n", zNew); |
| 210 | nConflict++; |
| 211 | }else{ |
| 212 | fossil_print("MERGE %s\n", zNew); |
| 213 | } |
| 214 | blob_reset(&out); |
| 215 | } |
| 216 | blob_reset(&a); |
| 217 | blob_reset(&b); |
| @@ -218,16 +218,16 @@ | |
| 218 | blob_reset(&disk); |
| 219 | } |
| 220 | blob_reset(&delta); |
| 221 | if( fossil_strcmp(zOrig,zNew)!=0 ){ |
| 222 | undo_save(zOrig); |
| 223 | file_delete(zOPath); |
| 224 | } |
| 225 | } |
| 226 | db_finalize(&q); |
| 227 | if( nConflict ){ |
| 228 | fossil_print("WARNING: merge conflicts - see messages above for details.\n"); |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | /* |
| 233 | ** Show the diffs associate with a single stash. |
| @@ -248,25 +248,25 @@ | |
| 248 | const char *zNew = db_column_text(&q, 4); |
| 249 | char *zOPath = mprintf("%s%s", g.zLocalRoot, zOrig); |
| 250 | Blob delta; |
| 251 | if( rid==0 ){ |
| 252 | db_ephemeral_blob(&q, 5, &delta); |
| 253 | fossil_print("ADDED %s\n", zNew); |
| 254 | diff_print_index(zNew); |
| 255 | diff_file_mem(&empty, &delta, zNew, zDiffCmd, 0); |
| 256 | }else if( isRemoved ){ |
| 257 | fossil_print("DELETE %s\n", zOrig); |
| 258 | blob_read_from_file(&delta, zOPath); |
| 259 | diff_print_index(zNew); |
| 260 | diff_file_mem(&delta, &empty, zOrig, zDiffCmd, 0); |
| 261 | }else{ |
| 262 | Blob a, b, disk; |
| 263 | db_ephemeral_blob(&q, 5, &delta); |
| 264 | blob_read_from_file(&disk, zOPath); |
| 265 | content_get(rid, &a); |
| 266 | blob_delta_apply(&a, &delta, &b); |
| 267 | fossil_print("CHANGED %s\n", zNew); |
| 268 | diff_file_mem(&disk, &b, zNew, zDiffCmd, 0); |
| 269 | blob_reset(&a); |
| 270 | blob_reset(&b); |
| 271 | blob_reset(&disk); |
| 272 | } |
| @@ -413,23 +413,23 @@ | |
| 413 | " ORDER BY ctime DESC" |
| 414 | ); |
| 415 | while( db_step(&q)==SQLITE_ROW ){ |
| 416 | const char *zCom; |
| 417 | n++; |
| 418 | fossil_print("%5d: [%.14s] on %s\n", |
| 419 | db_column_int(&q, 0), |
| 420 | db_column_text(&q, 1), |
| 421 | db_column_text(&q, 3) |
| 422 | ); |
| 423 | zCom = db_column_text(&q, 2); |
| 424 | if( zCom && zCom[0] ){ |
| 425 | fossil_print(" "); |
| 426 | comment_print(zCom, 7, 79); |
| 427 | } |
| 428 | } |
| 429 | db_finalize(&q); |
| 430 | if( n==0 ) fossil_print("empty stash\n"); |
| 431 | }else |
| 432 | if( memcmp(zCmd, "drop", nCmd)==0 ){ |
| 433 | int allFlag = find_option("all", 0, 0)!=0; |
| 434 | if( g.argc>4 ) usage("stash apply STASHID"); |
| 435 | if( allFlag ){ |
| 436 |
+11
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -800,17 +800,28 @@ | ||
| 800 | 800 | |
| 801 | 801 | /* |
| 802 | 802 | ** WEBPAGE: test_env |
| 803 | 803 | */ |
| 804 | 804 | void page_test_env(void){ |
| 805 | + char c; | |
| 806 | + int i; | |
| 807 | + char zCap[30]; | |
| 805 | 808 | login_check_credentials(); |
| 806 | 809 | style_header("Environment Test"); |
| 807 | 810 | #if !defined(_WIN32) |
| 808 | 811 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 809 | 812 | #endif |
| 810 | 813 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 811 | 814 | @ g.zTop = %h(g.zTop)<br /> |
| 815 | + for(i=0, c='a'; c<='z'; c++){ | |
| 816 | + if( login_has_capability(&c, 1) ) zCap[i++] = c; | |
| 817 | + } | |
| 818 | + zCap[i] = 0; | |
| 819 | + @ g.userUid = %d(g.userUid)<br /> | |
| 820 | + @ g.zLogin = %h(g.zLogin)<br /> | |
| 821 | + @ capabilities = %s(zCap)<br /> | |
| 822 | + @ <hr> | |
| 812 | 823 | cgi_print_all(); |
| 813 | 824 | if( g.okSetup ){ |
| 814 | 825 | const char *zRedir = P("redirect"); |
| 815 | 826 | if( zRedir ) cgi_redirect(zRedir); |
| 816 | 827 | } |
| 817 | 828 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -800,17 +800,28 @@ | |
| 800 | |
| 801 | /* |
| 802 | ** WEBPAGE: test_env |
| 803 | */ |
| 804 | void page_test_env(void){ |
| 805 | login_check_credentials(); |
| 806 | style_header("Environment Test"); |
| 807 | #if !defined(_WIN32) |
| 808 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 809 | #endif |
| 810 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 811 | @ g.zTop = %h(g.zTop)<br /> |
| 812 | cgi_print_all(); |
| 813 | if( g.okSetup ){ |
| 814 | const char *zRedir = P("redirect"); |
| 815 | if( zRedir ) cgi_redirect(zRedir); |
| 816 | } |
| 817 |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -800,17 +800,28 @@ | |
| 800 | |
| 801 | /* |
| 802 | ** WEBPAGE: test_env |
| 803 | */ |
| 804 | void page_test_env(void){ |
| 805 | char c; |
| 806 | int i; |
| 807 | char zCap[30]; |
| 808 | login_check_credentials(); |
| 809 | style_header("Environment Test"); |
| 810 | #if !defined(_WIN32) |
| 811 | @ uid=%d(getuid()), gid=%d(getgid())<br /> |
| 812 | #endif |
| 813 | @ g.zBaseURL = %h(g.zBaseURL)<br /> |
| 814 | @ g.zTop = %h(g.zTop)<br /> |
| 815 | for(i=0, c='a'; c<='z'; c++){ |
| 816 | if( login_has_capability(&c, 1) ) zCap[i++] = c; |
| 817 | } |
| 818 | zCap[i] = 0; |
| 819 | @ g.userUid = %d(g.userUid)<br /> |
| 820 | @ g.zLogin = %h(g.zLogin)<br /> |
| 821 | @ capabilities = %s(zCap)<br /> |
| 822 | @ <hr> |
| 823 | cgi_print_all(); |
| 824 | if( g.okSetup ){ |
| 825 | const char *zRedir = P("redirect"); |
| 826 | if( zRedir ) cgi_redirect(zRedir); |
| 827 | } |
| 828 |
+5
-5
| --- src/sync.c | ||
| +++ src/sync.c | ||
| @@ -76,11 +76,11 @@ | ||
| 76 | 76 | ** autosync, or something? |
| 77 | 77 | */ |
| 78 | 78 | configSync = CONFIGSET_SHUN; |
| 79 | 79 | } |
| 80 | 80 | #endif |
| 81 | - printf("Autosync: %s\n", g.urlCanonical); | |
| 81 | + fossil_print("Autosync: %s\n", g.urlCanonical); | |
| 82 | 82 | url_enable_proxy("via proxy: "); |
| 83 | 83 | rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0); |
| 84 | 84 | if( rc ) fossil_warning("Autosync failed"); |
| 85 | 85 | return rc; |
| 86 | 86 | } |
| @@ -102,11 +102,11 @@ | ||
| 102 | 102 | db_find_and_open_repository(0, 0); |
| 103 | 103 | db_open_config(0); |
| 104 | 104 | if( g.argc==2 ){ |
| 105 | 105 | zUrl = db_get("last-sync-url", 0); |
| 106 | 106 | zPw = unobscure(db_get("last-sync-pw", 0)); |
| 107 | - if( db_get_boolean("auto-sync",1) ) configSync = CONFIGSET_SHUN; | |
| 107 | + if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN; | |
| 108 | 108 | }else if( g.argc==3 ){ |
| 109 | 109 | zUrl = g.argv[2]; |
| 110 | 110 | } |
| 111 | 111 | if( zUrl==0 ){ |
| 112 | 112 | if( urlOptional ) fossil_exit(0); |
| @@ -124,11 +124,11 @@ | ||
| 124 | 124 | db_set("last-sync-url", g.urlCanonical, 0); |
| 125 | 125 | if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0); |
| 126 | 126 | } |
| 127 | 127 | user_select(); |
| 128 | 128 | if( g.argc==2 ){ |
| 129 | - printf("Server: %s\n", g.urlCanonical); | |
| 129 | + fossil_print("Server: %s\n", g.urlCanonical); | |
| 130 | 130 | } |
| 131 | 131 | url_enable_proxy("via proxy: "); |
| 132 | 132 | *pConfigSync = configSync; |
| 133 | 133 | } |
| 134 | 134 | |
| @@ -263,12 +263,12 @@ | ||
| 263 | 263 | } |
| 264 | 264 | } |
| 265 | 265 | } |
| 266 | 266 | zUrl = db_get("last-sync-url", 0); |
| 267 | 267 | if( zUrl==0 ){ |
| 268 | - printf("off\n"); | |
| 268 | + fossil_print("off\n"); | |
| 269 | 269 | return; |
| 270 | 270 | }else{ |
| 271 | 271 | url_parse(zUrl); |
| 272 | - printf("%s\n", g.urlCanonical); | |
| 272 | + fossil_print("%s\n", g.urlCanonical); | |
| 273 | 273 | } |
| 274 | 274 | } |
| 275 | 275 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -76,11 +76,11 @@ | |
| 76 | ** autosync, or something? |
| 77 | */ |
| 78 | configSync = CONFIGSET_SHUN; |
| 79 | } |
| 80 | #endif |
| 81 | printf("Autosync: %s\n", g.urlCanonical); |
| 82 | url_enable_proxy("via proxy: "); |
| 83 | rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0); |
| 84 | if( rc ) fossil_warning("Autosync failed"); |
| 85 | return rc; |
| 86 | } |
| @@ -102,11 +102,11 @@ | |
| 102 | db_find_and_open_repository(0, 0); |
| 103 | db_open_config(0); |
| 104 | if( g.argc==2 ){ |
| 105 | zUrl = db_get("last-sync-url", 0); |
| 106 | zPw = unobscure(db_get("last-sync-pw", 0)); |
| 107 | if( db_get_boolean("auto-sync",1) ) configSync = CONFIGSET_SHUN; |
| 108 | }else if( g.argc==3 ){ |
| 109 | zUrl = g.argv[2]; |
| 110 | } |
| 111 | if( zUrl==0 ){ |
| 112 | if( urlOptional ) fossil_exit(0); |
| @@ -124,11 +124,11 @@ | |
| 124 | db_set("last-sync-url", g.urlCanonical, 0); |
| 125 | if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0); |
| 126 | } |
| 127 | user_select(); |
| 128 | if( g.argc==2 ){ |
| 129 | printf("Server: %s\n", g.urlCanonical); |
| 130 | } |
| 131 | url_enable_proxy("via proxy: "); |
| 132 | *pConfigSync = configSync; |
| 133 | } |
| 134 | |
| @@ -263,12 +263,12 @@ | |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | zUrl = db_get("last-sync-url", 0); |
| 267 | if( zUrl==0 ){ |
| 268 | printf("off\n"); |
| 269 | return; |
| 270 | }else{ |
| 271 | url_parse(zUrl); |
| 272 | printf("%s\n", g.urlCanonical); |
| 273 | } |
| 274 | } |
| 275 |
| --- src/sync.c | |
| +++ src/sync.c | |
| @@ -76,11 +76,11 @@ | |
| 76 | ** autosync, or something? |
| 77 | */ |
| 78 | configSync = CONFIGSET_SHUN; |
| 79 | } |
| 80 | #endif |
| 81 | fossil_print("Autosync: %s\n", g.urlCanonical); |
| 82 | url_enable_proxy("via proxy: "); |
| 83 | rc = client_sync((flags & AUTOSYNC_PUSH)!=0, 1, 0, 0, configSync, 0); |
| 84 | if( rc ) fossil_warning("Autosync failed"); |
| 85 | return rc; |
| 86 | } |
| @@ -102,11 +102,11 @@ | |
| 102 | db_find_and_open_repository(0, 0); |
| 103 | db_open_config(0); |
| 104 | if( g.argc==2 ){ |
| 105 | zUrl = db_get("last-sync-url", 0); |
| 106 | zPw = unobscure(db_get("last-sync-pw", 0)); |
| 107 | if( db_get_boolean("auto-shun",1) ) configSync = CONFIGSET_SHUN; |
| 108 | }else if( g.argc==3 ){ |
| 109 | zUrl = g.argv[2]; |
| 110 | } |
| 111 | if( zUrl==0 ){ |
| 112 | if( urlOptional ) fossil_exit(0); |
| @@ -124,11 +124,11 @@ | |
| 124 | db_set("last-sync-url", g.urlCanonical, 0); |
| 125 | if( g.urlPasswd ) db_set("last-sync-pw", obscure(g.urlPasswd), 0); |
| 126 | } |
| 127 | user_select(); |
| 128 | if( g.argc==2 ){ |
| 129 | fossil_print("Server: %s\n", g.urlCanonical); |
| 130 | } |
| 131 | url_enable_proxy("via proxy: "); |
| 132 | *pConfigSync = configSync; |
| 133 | } |
| 134 | |
| @@ -263,12 +263,12 @@ | |
| 263 | } |
| 264 | } |
| 265 | } |
| 266 | zUrl = db_get("last-sync-url", 0); |
| 267 | if( zUrl==0 ){ |
| 268 | fossil_print("off\n"); |
| 269 | return; |
| 270 | }else{ |
| 271 | url_parse(zUrl); |
| 272 | fossil_print("%s\n", g.urlCanonical); |
| 273 | } |
| 274 | } |
| 275 |
+5
-5
| --- src/tag.c | ||
| +++ src/tag.c | ||
| @@ -438,11 +438,11 @@ | ||
| 438 | 438 | " AND tagxref.tagtype>0" |
| 439 | 439 | " AND blob.rid=tagxref.rid", |
| 440 | 440 | g.argv[3] |
| 441 | 441 | ); |
| 442 | 442 | while( db_step(&q)==SQLITE_ROW ){ |
| 443 | - printf("%s\n", db_column_text(&q, 0)); | |
| 443 | + fossil_print("%s\n", db_column_text(&q, 0)); | |
| 444 | 444 | } |
| 445 | 445 | db_finalize(&q); |
| 446 | 446 | }else{ |
| 447 | 447 | int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", |
| 448 | 448 | g.argv[3]); |
| @@ -473,13 +473,13 @@ | ||
| 473 | 473 | " ORDER BY tagname" |
| 474 | 474 | ); |
| 475 | 475 | while( db_step(&q)==SQLITE_ROW ){ |
| 476 | 476 | const char *zName = db_column_text(&q, 0); |
| 477 | 477 | if( fRaw ){ |
| 478 | - printf("%s\n", zName); | |
| 478 | + fossil_print("%s\n", zName); | |
| 479 | 479 | }else if( strncmp(zName, "sym-", 4)==0 ){ |
| 480 | - printf("%s\n", &zName[4]); | |
| 480 | + fossil_print("%s\n", &zName[4]); | |
| 481 | 481 | } |
| 482 | 482 | } |
| 483 | 483 | db_finalize(&q); |
| 484 | 484 | }else if( g.argc==4 ){ |
| 485 | 485 | int rid = name_to_rid(g.argv[3]); |
| @@ -497,13 +497,13 @@ | ||
| 497 | 497 | if( fRaw==0 ){ |
| 498 | 498 | if( strncmp(zName, "sym-", 4)!=0 ) continue; |
| 499 | 499 | zName += 4; |
| 500 | 500 | } |
| 501 | 501 | if( zValue && zValue[0] ){ |
| 502 | - printf("%s=%s\n", zName, zValue); | |
| 502 | + fossil_print("%s=%s\n", zName, zValue); | |
| 503 | 503 | }else{ |
| 504 | - printf("%s\n", zName); | |
| 504 | + fossil_print("%s\n", zName); | |
| 505 | 505 | } |
| 506 | 506 | } |
| 507 | 507 | db_finalize(&q); |
| 508 | 508 | }else{ |
| 509 | 509 | usage("tag list ?CHECK-IN?"); |
| 510 | 510 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -438,11 +438,11 @@ | |
| 438 | " AND tagxref.tagtype>0" |
| 439 | " AND blob.rid=tagxref.rid", |
| 440 | g.argv[3] |
| 441 | ); |
| 442 | while( db_step(&q)==SQLITE_ROW ){ |
| 443 | printf("%s\n", db_column_text(&q, 0)); |
| 444 | } |
| 445 | db_finalize(&q); |
| 446 | }else{ |
| 447 | int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", |
| 448 | g.argv[3]); |
| @@ -473,13 +473,13 @@ | |
| 473 | " ORDER BY tagname" |
| 474 | ); |
| 475 | while( db_step(&q)==SQLITE_ROW ){ |
| 476 | const char *zName = db_column_text(&q, 0); |
| 477 | if( fRaw ){ |
| 478 | printf("%s\n", zName); |
| 479 | }else if( strncmp(zName, "sym-", 4)==0 ){ |
| 480 | printf("%s\n", &zName[4]); |
| 481 | } |
| 482 | } |
| 483 | db_finalize(&q); |
| 484 | }else if( g.argc==4 ){ |
| 485 | int rid = name_to_rid(g.argv[3]); |
| @@ -497,13 +497,13 @@ | |
| 497 | if( fRaw==0 ){ |
| 498 | if( strncmp(zName, "sym-", 4)!=0 ) continue; |
| 499 | zName += 4; |
| 500 | } |
| 501 | if( zValue && zValue[0] ){ |
| 502 | printf("%s=%s\n", zName, zValue); |
| 503 | }else{ |
| 504 | printf("%s\n", zName); |
| 505 | } |
| 506 | } |
| 507 | db_finalize(&q); |
| 508 | }else{ |
| 509 | usage("tag list ?CHECK-IN?"); |
| 510 |
| --- src/tag.c | |
| +++ src/tag.c | |
| @@ -438,11 +438,11 @@ | |
| 438 | " AND tagxref.tagtype>0" |
| 439 | " AND blob.rid=tagxref.rid", |
| 440 | g.argv[3] |
| 441 | ); |
| 442 | while( db_step(&q)==SQLITE_ROW ){ |
| 443 | fossil_print("%s\n", db_column_text(&q, 0)); |
| 444 | } |
| 445 | db_finalize(&q); |
| 446 | }else{ |
| 447 | int tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", |
| 448 | g.argv[3]); |
| @@ -473,13 +473,13 @@ | |
| 473 | " ORDER BY tagname" |
| 474 | ); |
| 475 | while( db_step(&q)==SQLITE_ROW ){ |
| 476 | const char *zName = db_column_text(&q, 0); |
| 477 | if( fRaw ){ |
| 478 | fossil_print("%s\n", zName); |
| 479 | }else if( strncmp(zName, "sym-", 4)==0 ){ |
| 480 | fossil_print("%s\n", &zName[4]); |
| 481 | } |
| 482 | } |
| 483 | db_finalize(&q); |
| 484 | }else if( g.argc==4 ){ |
| 485 | int rid = name_to_rid(g.argv[3]); |
| @@ -497,13 +497,13 @@ | |
| 497 | if( fRaw==0 ){ |
| 498 | if( strncmp(zName, "sym-", 4)!=0 ) continue; |
| 499 | zName += 4; |
| 500 | } |
| 501 | if( zValue && zValue[0] ){ |
| 502 | fossil_print("%s=%s\n", zName, zValue); |
| 503 | }else{ |
| 504 | fossil_print("%s\n", zName); |
| 505 | } |
| 506 | } |
| 507 | db_finalize(&q); |
| 508 | }else{ |
| 509 | usage("tag list ?CHECK-IN?"); |
| 510 |
+19
-33
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -97,32 +97,10 @@ | ||
| 97 | 97 | }else{ |
| 98 | 98 | @ %s(zU) |
| 99 | 99 | } |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | -/* | |
| 103 | -** Count the number of primary non-branch children for the given check-in. | |
| 104 | -** | |
| 105 | -** A primary child is one where the parent is the primary parent, not | |
| 106 | -** a merge parent. | |
| 107 | -** | |
| 108 | -** A non-branch child is one which is on the same branch as the parent. | |
| 109 | -*/ | |
| 110 | -int count_nonbranch_children(int pid){ | |
| 111 | - int nNonBranch; | |
| 112 | - static const char zSql[] = | |
| 113 | - @ SELECT count(*) FROM plink | |
| 114 | - @ WHERE pid=%d AND isprim | |
| 115 | - @ AND coalesce((SELECT value FROM tagxref | |
| 116 | - @ WHERE tagid=%d AND rid=plink.pid), 'trunk') | |
| 117 | - @ =coalesce((SELECT value FROM tagxref | |
| 118 | - @ WHERE tagid=%d AND rid=plink.cid), 'trunk') | |
| 119 | - ; | |
| 120 | - nNonBranch = db_int(0, zSql, pid, TAG_BRANCH, TAG_BRANCH); | |
| 121 | - return nNonBranch; | |
| 122 | -} | |
| 123 | - | |
| 124 | 102 | /* |
| 125 | 103 | ** Allowed flags for the tmFlags argument to www_print_timeline |
| 126 | 104 | */ |
| 127 | 105 | #if INTERFACE |
| 128 | 106 | #define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */ |
| @@ -344,17 +322,19 @@ | ||
| 344 | 322 | if( xExtra ){ |
| 345 | 323 | xExtra(rid); |
| 346 | 324 | } |
| 347 | 325 | |
| 348 | 326 | /* Generate the file-change list if requested */ |
| 349 | - if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' ){ | |
| 327 | + if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.okHistory ){ | |
| 350 | 328 | int inUl = 0; |
| 351 | 329 | if( !fchngQueryInit ){ |
| 352 | 330 | db_prepare(&fchngQuery, |
| 353 | 331 | "SELECT (pid==0) AS isnew," |
| 354 | 332 | " (fid==0) AS isdel," |
| 355 | - " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name" | |
| 333 | + " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name," | |
| 334 | + " (SELECT uuid FROM blob WHERE rid=fid)," | |
| 335 | + " (SELECT uuid FROM blob WHERE rid=pid)" | |
| 356 | 336 | " FROM mlink" |
| 357 | 337 | " WHERE mid=:mid AND pid!=fid" |
| 358 | 338 | " ORDER BY 3" |
| 359 | 339 | ); |
| 360 | 340 | fchngQueryInit = 1; |
| @@ -362,20 +342,26 @@ | ||
| 362 | 342 | db_bind_int(&fchngQuery, ":mid", rid); |
| 363 | 343 | while( db_step(&fchngQuery)==SQLITE_ROW ){ |
| 364 | 344 | const char *zFilename = db_column_text(&fchngQuery, 2); |
| 365 | 345 | int isNew = db_column_int(&fchngQuery, 0); |
| 366 | 346 | int isDel = db_column_int(&fchngQuery, 1); |
| 347 | + const char *zOld = db_column_text(&fchngQuery, 4); | |
| 348 | + const char *zNew = db_column_text(&fchngQuery, 3); | |
| 367 | 349 | if( !inUl ){ |
| 368 | 350 | @ <ul class="filelist"> |
| 369 | 351 | inUl = 1; |
| 370 | 352 | } |
| 371 | 353 | if( isNew ){ |
| 372 | - @ <li> %h(zFilename) (new file)</li> | |
| 354 | + @ <li> %h(zFilename) (new file) | |
| 355 | + @ <a href="%s(g.zTop)/artifact/%S(zNew)" target="diffwindow">[view] | |
| 356 | + @ </a></li> | |
| 373 | 357 | }else if( isDel ){ |
| 374 | 358 | @ <li> %h(zFilename) (deleted)</li> |
| 375 | 359 | }else{ |
| 376 | - @ <li> %h(zFilename) </li> | |
| 360 | + @ <li> %h(zFilename) | |
| 361 | + @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)" | |
| 362 | + @ target="diffwindow">[diff]</a></li> | |
| 377 | 363 | } |
| 378 | 364 | } |
| 379 | 365 | db_reset(&fchngQuery); |
| 380 | 366 | if( inUl ){ |
| 381 | 367 | @ </ul> |
| @@ -740,23 +726,23 @@ | ||
| 740 | 726 | ** the event identified by rid. |
| 741 | 727 | */ |
| 742 | 728 | static void timeline_add_dividers(const char *zDate, int rid){ |
| 743 | 729 | char *zToDel = 0; |
| 744 | 730 | if( zDate==0 ){ |
| 745 | - zToDel = db_text(0,"SELECT datetime(mtime,'localtime') FROM event" | |
| 731 | + zToDel = db_text(0,"SELECT julianday(mtime,'localtime') FROM event" | |
| 746 | 732 | " WHERE objid=%d", rid); |
| 747 | 733 | zDate = zToDel; |
| 748 | 734 | if( zDate==0 ) zDate = "1"; |
| 749 | 735 | } |
| 750 | 736 | db_multi_exec( |
| 751 | 737 | "INSERT INTO timeline(rid,sortby,etype)" |
| 752 | - "VALUES(-1,julianday(%Q,'utc')-5.0e-6,'div')", | |
| 738 | + "VALUES(-1,julianday(%Q,'utc')-1.0e-5,'div')", | |
| 753 | 739 | zDate |
| 754 | 740 | ); |
| 755 | 741 | db_multi_exec( |
| 756 | 742 | "INSERT INTO timeline(rid,sortby,etype)" |
| 757 | - "VALUES(-2,julianday(%Q,'utc')+5.0e-6,'div')", | |
| 743 | + "VALUES(-2,julianday(%Q,'utc')+1.0e-5,'div')", | |
| 758 | 744 | zDate |
| 759 | 745 | ); |
| 760 | 746 | fossil_free(zToDel); |
| 761 | 747 | } |
| 762 | 748 | |
| @@ -1217,16 +1203,16 @@ | ||
| 1217 | 1203 | char zPrefix[80]; |
| 1218 | 1204 | char zUuid[UUID_SIZE+1]; |
| 1219 | 1205 | |
| 1220 | 1206 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1221 | 1207 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 1222 | - printf("=== %.10s ===\n", zDate); | |
| 1208 | + fossil_print("=== %.10s ===\n", zDate); | |
| 1223 | 1209 | memcpy(zPrevDate, zDate, 10); |
| 1224 | 1210 | nLine++; |
| 1225 | 1211 | } |
| 1226 | 1212 | if( zCom==0 ) zCom = ""; |
| 1227 | - printf("%.8s ", &zDate[11]); | |
| 1213 | + fossil_print("%.8s ", &zDate[11]); | |
| 1228 | 1214 | zPrefix[0] = 0; |
| 1229 | 1215 | if( nParent>1 ){ |
| 1230 | 1216 | sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* "); |
| 1231 | 1217 | n = strlen(zPrefix); |
| 1232 | 1218 | } |
| @@ -1467,13 +1453,13 @@ | ||
| 1467 | 1453 | " FROM plink p, plink c" |
| 1468 | 1454 | " WHERE p.cid=c.pid AND p.mtime>c.mtime" |
| 1469 | 1455 | ); |
| 1470 | 1456 | while( db_step(&q)==SQLITE_ROW ){ |
| 1471 | 1457 | if( !showDetail ){ |
| 1472 | - printf("%s\n", db_column_text(&q, 1)); | |
| 1458 | + fossil_print("%s\n", db_column_text(&q, 1)); | |
| 1473 | 1459 | }else{ |
| 1474 | - printf("%.14s -> %.14s %s -> %s\n", | |
| 1460 | + fossil_print("%.14s -> %.14s %s -> %s\n", | |
| 1475 | 1461 | db_column_text(&q, 0), |
| 1476 | 1462 | db_column_text(&q, 1), |
| 1477 | 1463 | db_column_text(&q, 2), |
| 1478 | 1464 | db_column_text(&q, 3)); |
| 1479 | 1465 | } |
| 1480 | 1466 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -97,32 +97,10 @@ | |
| 97 | }else{ |
| 98 | @ %s(zU) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /* |
| 103 | ** Count the number of primary non-branch children for the given check-in. |
| 104 | ** |
| 105 | ** A primary child is one where the parent is the primary parent, not |
| 106 | ** a merge parent. |
| 107 | ** |
| 108 | ** A non-branch child is one which is on the same branch as the parent. |
| 109 | */ |
| 110 | int count_nonbranch_children(int pid){ |
| 111 | int nNonBranch; |
| 112 | static const char zSql[] = |
| 113 | @ SELECT count(*) FROM plink |
| 114 | @ WHERE pid=%d AND isprim |
| 115 | @ AND coalesce((SELECT value FROM tagxref |
| 116 | @ WHERE tagid=%d AND rid=plink.pid), 'trunk') |
| 117 | @ =coalesce((SELECT value FROM tagxref |
| 118 | @ WHERE tagid=%d AND rid=plink.cid), 'trunk') |
| 119 | ; |
| 120 | nNonBranch = db_int(0, zSql, pid, TAG_BRANCH, TAG_BRANCH); |
| 121 | return nNonBranch; |
| 122 | } |
| 123 | |
| 124 | /* |
| 125 | ** Allowed flags for the tmFlags argument to www_print_timeline |
| 126 | */ |
| 127 | #if INTERFACE |
| 128 | #define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */ |
| @@ -344,17 +322,19 @@ | |
| 344 | if( xExtra ){ |
| 345 | xExtra(rid); |
| 346 | } |
| 347 | |
| 348 | /* Generate the file-change list if requested */ |
| 349 | if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' ){ |
| 350 | int inUl = 0; |
| 351 | if( !fchngQueryInit ){ |
| 352 | db_prepare(&fchngQuery, |
| 353 | "SELECT (pid==0) AS isnew," |
| 354 | " (fid==0) AS isdel," |
| 355 | " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name" |
| 356 | " FROM mlink" |
| 357 | " WHERE mid=:mid AND pid!=fid" |
| 358 | " ORDER BY 3" |
| 359 | ); |
| 360 | fchngQueryInit = 1; |
| @@ -362,20 +342,26 @@ | |
| 362 | db_bind_int(&fchngQuery, ":mid", rid); |
| 363 | while( db_step(&fchngQuery)==SQLITE_ROW ){ |
| 364 | const char *zFilename = db_column_text(&fchngQuery, 2); |
| 365 | int isNew = db_column_int(&fchngQuery, 0); |
| 366 | int isDel = db_column_int(&fchngQuery, 1); |
| 367 | if( !inUl ){ |
| 368 | @ <ul class="filelist"> |
| 369 | inUl = 1; |
| 370 | } |
| 371 | if( isNew ){ |
| 372 | @ <li> %h(zFilename) (new file)</li> |
| 373 | }else if( isDel ){ |
| 374 | @ <li> %h(zFilename) (deleted)</li> |
| 375 | }else{ |
| 376 | @ <li> %h(zFilename) </li> |
| 377 | } |
| 378 | } |
| 379 | db_reset(&fchngQuery); |
| 380 | if( inUl ){ |
| 381 | @ </ul> |
| @@ -740,23 +726,23 @@ | |
| 740 | ** the event identified by rid. |
| 741 | */ |
| 742 | static void timeline_add_dividers(const char *zDate, int rid){ |
| 743 | char *zToDel = 0; |
| 744 | if( zDate==0 ){ |
| 745 | zToDel = db_text(0,"SELECT datetime(mtime,'localtime') FROM event" |
| 746 | " WHERE objid=%d", rid); |
| 747 | zDate = zToDel; |
| 748 | if( zDate==0 ) zDate = "1"; |
| 749 | } |
| 750 | db_multi_exec( |
| 751 | "INSERT INTO timeline(rid,sortby,etype)" |
| 752 | "VALUES(-1,julianday(%Q,'utc')-5.0e-6,'div')", |
| 753 | zDate |
| 754 | ); |
| 755 | db_multi_exec( |
| 756 | "INSERT INTO timeline(rid,sortby,etype)" |
| 757 | "VALUES(-2,julianday(%Q,'utc')+5.0e-6,'div')", |
| 758 | zDate |
| 759 | ); |
| 760 | fossil_free(zToDel); |
| 761 | } |
| 762 | |
| @@ -1217,16 +1203,16 @@ | |
| 1217 | char zPrefix[80]; |
| 1218 | char zUuid[UUID_SIZE+1]; |
| 1219 | |
| 1220 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1221 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 1222 | printf("=== %.10s ===\n", zDate); |
| 1223 | memcpy(zPrevDate, zDate, 10); |
| 1224 | nLine++; |
| 1225 | } |
| 1226 | if( zCom==0 ) zCom = ""; |
| 1227 | printf("%.8s ", &zDate[11]); |
| 1228 | zPrefix[0] = 0; |
| 1229 | if( nParent>1 ){ |
| 1230 | sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* "); |
| 1231 | n = strlen(zPrefix); |
| 1232 | } |
| @@ -1467,13 +1453,13 @@ | |
| 1467 | " FROM plink p, plink c" |
| 1468 | " WHERE p.cid=c.pid AND p.mtime>c.mtime" |
| 1469 | ); |
| 1470 | while( db_step(&q)==SQLITE_ROW ){ |
| 1471 | if( !showDetail ){ |
| 1472 | printf("%s\n", db_column_text(&q, 1)); |
| 1473 | }else{ |
| 1474 | printf("%.14s -> %.14s %s -> %s\n", |
| 1475 | db_column_text(&q, 0), |
| 1476 | db_column_text(&q, 1), |
| 1477 | db_column_text(&q, 2), |
| 1478 | db_column_text(&q, 3)); |
| 1479 | } |
| 1480 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -97,32 +97,10 @@ | |
| 97 | }else{ |
| 98 | @ %s(zU) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | /* |
| 103 | ** Allowed flags for the tmFlags argument to www_print_timeline |
| 104 | */ |
| 105 | #if INTERFACE |
| 106 | #define TIMELINE_ARTID 0x0001 /* Show artifact IDs on non-check-in lines */ |
| @@ -344,17 +322,19 @@ | |
| 322 | if( xExtra ){ |
| 323 | xExtra(rid); |
| 324 | } |
| 325 | |
| 326 | /* Generate the file-change list if requested */ |
| 327 | if( (tmFlags & TIMELINE_FCHANGES)!=0 && zType[0]=='c' && g.okHistory ){ |
| 328 | int inUl = 0; |
| 329 | if( !fchngQueryInit ){ |
| 330 | db_prepare(&fchngQuery, |
| 331 | "SELECT (pid==0) AS isnew," |
| 332 | " (fid==0) AS isdel," |
| 333 | " (SELECT name FROM filename WHERE fnid=mlink.fnid) AS name," |
| 334 | " (SELECT uuid FROM blob WHERE rid=fid)," |
| 335 | " (SELECT uuid FROM blob WHERE rid=pid)" |
| 336 | " FROM mlink" |
| 337 | " WHERE mid=:mid AND pid!=fid" |
| 338 | " ORDER BY 3" |
| 339 | ); |
| 340 | fchngQueryInit = 1; |
| @@ -362,20 +342,26 @@ | |
| 342 | db_bind_int(&fchngQuery, ":mid", rid); |
| 343 | while( db_step(&fchngQuery)==SQLITE_ROW ){ |
| 344 | const char *zFilename = db_column_text(&fchngQuery, 2); |
| 345 | int isNew = db_column_int(&fchngQuery, 0); |
| 346 | int isDel = db_column_int(&fchngQuery, 1); |
| 347 | const char *zOld = db_column_text(&fchngQuery, 4); |
| 348 | const char *zNew = db_column_text(&fchngQuery, 3); |
| 349 | if( !inUl ){ |
| 350 | @ <ul class="filelist"> |
| 351 | inUl = 1; |
| 352 | } |
| 353 | if( isNew ){ |
| 354 | @ <li> %h(zFilename) (new file) |
| 355 | @ <a href="%s(g.zTop)/artifact/%S(zNew)" target="diffwindow">[view] |
| 356 | @ </a></li> |
| 357 | }else if( isDel ){ |
| 358 | @ <li> %h(zFilename) (deleted)</li> |
| 359 | }else{ |
| 360 | @ <li> %h(zFilename) |
| 361 | @ <a href="%s(g.zTop)/fdiff?v1=%S(zOld)&v2=%S(zNew)" |
| 362 | @ target="diffwindow">[diff]</a></li> |
| 363 | } |
| 364 | } |
| 365 | db_reset(&fchngQuery); |
| 366 | if( inUl ){ |
| 367 | @ </ul> |
| @@ -740,23 +726,23 @@ | |
| 726 | ** the event identified by rid. |
| 727 | */ |
| 728 | static void timeline_add_dividers(const char *zDate, int rid){ |
| 729 | char *zToDel = 0; |
| 730 | if( zDate==0 ){ |
| 731 | zToDel = db_text(0,"SELECT julianday(mtime,'localtime') FROM event" |
| 732 | " WHERE objid=%d", rid); |
| 733 | zDate = zToDel; |
| 734 | if( zDate==0 ) zDate = "1"; |
| 735 | } |
| 736 | db_multi_exec( |
| 737 | "INSERT INTO timeline(rid,sortby,etype)" |
| 738 | "VALUES(-1,julianday(%Q,'utc')-1.0e-5,'div')", |
| 739 | zDate |
| 740 | ); |
| 741 | db_multi_exec( |
| 742 | "INSERT INTO timeline(rid,sortby,etype)" |
| 743 | "VALUES(-2,julianday(%Q,'utc')+1.0e-5,'div')", |
| 744 | zDate |
| 745 | ); |
| 746 | fossil_free(zToDel); |
| 747 | } |
| 748 | |
| @@ -1217,16 +1203,16 @@ | |
| 1203 | char zPrefix[80]; |
| 1204 | char zUuid[UUID_SIZE+1]; |
| 1205 | |
| 1206 | sqlite3_snprintf(sizeof(zUuid), zUuid, "%.10s", zId); |
| 1207 | if( memcmp(zDate, zPrevDate, 10) ){ |
| 1208 | fossil_print("=== %.10s ===\n", zDate); |
| 1209 | memcpy(zPrevDate, zDate, 10); |
| 1210 | nLine++; |
| 1211 | } |
| 1212 | if( zCom==0 ) zCom = ""; |
| 1213 | fossil_print("%.8s ", &zDate[11]); |
| 1214 | zPrefix[0] = 0; |
| 1215 | if( nParent>1 ){ |
| 1216 | sqlite3_snprintf(sizeof(zPrefix), zPrefix, "*MERGE* "); |
| 1217 | n = strlen(zPrefix); |
| 1218 | } |
| @@ -1467,13 +1453,13 @@ | |
| 1453 | " FROM plink p, plink c" |
| 1454 | " WHERE p.cid=c.pid AND p.mtime>c.mtime" |
| 1455 | ); |
| 1456 | while( db_step(&q)==SQLITE_ROW ){ |
| 1457 | if( !showDetail ){ |
| 1458 | fossil_print("%s\n", db_column_text(&q, 1)); |
| 1459 | }else{ |
| 1460 | fossil_print("%.14s -> %.14s %s -> %s\n", |
| 1461 | db_column_text(&q, 0), |
| 1462 | db_column_text(&q, 1), |
| 1463 | db_column_text(&q, 2), |
| 1464 | db_column_text(&q, 3)); |
| 1465 | } |
| 1466 |
+2
-1
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -216,11 +216,12 @@ | ||
| 216 | 216 | char *zTag = mprintf("tkt-%s", zTktUuid); |
| 217 | 217 | int tagid = tag_findid(zTag, 1); |
| 218 | 218 | Stmt q; |
| 219 | 219 | Manifest *pTicket; |
| 220 | 220 | int createFlag = 1; |
| 221 | - | |
| 221 | + | |
| 222 | + fossil_free(zTag); | |
| 222 | 223 | db_multi_exec( |
| 223 | 224 | "DELETE FROM ticket WHERE tkt_uuid=%Q", zTktUuid |
| 224 | 225 | ); |
| 225 | 226 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 226 | 227 | while( db_step(&q)==SQLITE_ROW ){ |
| 227 | 228 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -216,11 +216,12 @@ | |
| 216 | char *zTag = mprintf("tkt-%s", zTktUuid); |
| 217 | int tagid = tag_findid(zTag, 1); |
| 218 | Stmt q; |
| 219 | Manifest *pTicket; |
| 220 | int createFlag = 1; |
| 221 | |
| 222 | db_multi_exec( |
| 223 | "DELETE FROM ticket WHERE tkt_uuid=%Q", zTktUuid |
| 224 | ); |
| 225 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 226 | while( db_step(&q)==SQLITE_ROW ){ |
| 227 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -216,11 +216,12 @@ | |
| 216 | char *zTag = mprintf("tkt-%s", zTktUuid); |
| 217 | int tagid = tag_findid(zTag, 1); |
| 218 | Stmt q; |
| 219 | Manifest *pTicket; |
| 220 | int createFlag = 1; |
| 221 | |
| 222 | fossil_free(zTag); |
| 223 | db_multi_exec( |
| 224 | "DELETE FROM ticket WHERE tkt_uuid=%Q", zTktUuid |
| 225 | ); |
| 226 | db_prepare(&q, "SELECT rid FROM tagxref WHERE tagid=%d ORDER BY mtime",tagid); |
| 227 | while( db_step(&q)==SQLITE_ROW ){ |
| 228 |
+15
-14
| --- src/undo.c | ||
| +++ src/undo.c | ||
| @@ -58,19 +58,19 @@ | ||
| 58 | 58 | if( old_exists ){ |
| 59 | 59 | db_ephemeral_blob(&q, 0, &new); |
| 60 | 60 | } |
| 61 | 61 | if( old_exists ){ |
| 62 | 62 | if( new_exists ){ |
| 63 | - printf("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); | |
| 63 | + fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); | |
| 64 | 64 | }else{ |
| 65 | - printf("NEW %s\n", zPathname); | |
| 65 | + fossil_print("NEW %s\n", zPathname); | |
| 66 | 66 | } |
| 67 | 67 | blob_write_to_file(&new, zFullname); |
| 68 | 68 | file_setexe(zFullname, old_exe); |
| 69 | 69 | }else{ |
| 70 | - printf("DELETE %s\n", zPathname); | |
| 71 | - unlink(zFullname); | |
| 70 | + fossil_print("DELETE %s\n", zPathname); | |
| 71 | + file_delete(zFullname); | |
| 72 | 72 | } |
| 73 | 73 | blob_reset(&new); |
| 74 | 74 | free(zFullname); |
| 75 | 75 | db_finalize(&q); |
| 76 | 76 | db_prepare(&q, |
| @@ -297,11 +297,11 @@ | ||
| 297 | 297 | ** Complete the undo process is one is currently in process. |
| 298 | 298 | */ |
| 299 | 299 | void undo_finish(void){ |
| 300 | 300 | if( undoActive ){ |
| 301 | 301 | if( undoNeedRollback ){ |
| 302 | - printf("\"fossil undo\" is available to undo changes" | |
| 302 | + fossil_print("\"fossil undo\" is available to undo changes" | |
| 303 | 303 | " to the working checkout.\n"); |
| 304 | 304 | } |
| 305 | 305 | undoActive = 0; |
| 306 | 306 | undoNeedRollback = 0; |
| 307 | 307 | } |
| @@ -319,11 +319,11 @@ | ||
| 319 | 319 | void undo_rollback(void){ |
| 320 | 320 | if( !undoNeedRollback ) return; |
| 321 | 321 | assert( undoActive ); |
| 322 | 322 | undoNeedRollback = 0; |
| 323 | 323 | undoActive = 0; |
| 324 | - printf("Rolling back prior filesystem changes...\n"); | |
| 324 | + fossil_print("Rolling back prior filesystem changes...\n"); | |
| 325 | 325 | undo_all_filesystem(0); |
| 326 | 326 | } |
| 327 | 327 | |
| 328 | 328 | /* |
| 329 | 329 | ** COMMAND: undo |
| @@ -360,34 +360,35 @@ | ||
| 360 | 360 | verify_all_options(); |
| 361 | 361 | db_begin_transaction(); |
| 362 | 362 | undo_available = db_lget_int("undo_available", 0); |
| 363 | 363 | if( explainFlag ){ |
| 364 | 364 | if( undo_available==0 ){ |
| 365 | - printf("No undo or redo is available\n"); | |
| 365 | + fossil_print("No undo or redo is available\n"); | |
| 366 | 366 | }else{ |
| 367 | 367 | Stmt q; |
| 368 | 368 | int nChng = 0; |
| 369 | 369 | zCmd = undo_available==1 ? "undo" : "redo"; |
| 370 | - printf("A %s is available for the following command:\n\n %s %s\n\n", | |
| 371 | - zCmd, g.argv[0], db_lget("undo_cmdline", "???")); | |
| 370 | + fossil_print("A %s is available for the following command:\n\n" | |
| 371 | + " %s %s\n\n", | |
| 372 | + zCmd, g.argv[0], db_lget("undo_cmdline", "???")); | |
| 372 | 373 | db_prepare(&q, |
| 373 | 374 | "SELECT existsflag, pathname FROM undo ORDER BY pathname" |
| 374 | 375 | ); |
| 375 | 376 | while( db_step(&q)==SQLITE_ROW ){ |
| 376 | 377 | if( nChng==0 ){ |
| 377 | - printf("The following file changes would occur if the " | |
| 378 | - "command above is %sne:\n\n", zCmd); | |
| 378 | + fossil_print("The following file changes would occur if the " | |
| 379 | + "command above is %sne:\n\n", zCmd); | |
| 379 | 380 | } |
| 380 | 381 | nChng++; |
| 381 | - printf("%s %s\n", | |
| 382 | + fossil_print("%s %s\n", | |
| 382 | 383 | db_column_int(&q,0) ? "UPDATE" : "DELETE", |
| 383 | 384 | db_column_text(&q, 1) |
| 384 | 385 | ); |
| 385 | 386 | } |
| 386 | 387 | db_finalize(&q); |
| 387 | 388 | if( nChng==0 ){ |
| 388 | - printf("No file changes would occur with this undo/redo.\n"); | |
| 389 | + fossil_print("No file changes would occur with this undo/redo.\n"); | |
| 389 | 390 | } |
| 390 | 391 | } |
| 391 | 392 | }else{ |
| 392 | 393 | int vid1 = db_lget_int("checkout", 0); |
| 393 | 394 | int vid2; |
| @@ -410,11 +411,11 @@ | ||
| 410 | 411 | blob_reset(&path); |
| 411 | 412 | } |
| 412 | 413 | } |
| 413 | 414 | vid2 = db_lget_int("checkout", 0); |
| 414 | 415 | if( vid1!=vid2 ){ |
| 415 | - printf("--------------------\n"); | |
| 416 | + fossil_print("--------------------\n"); | |
| 416 | 417 | show_common_info(vid2, "updated-to:", 1, 0); |
| 417 | 418 | } |
| 418 | 419 | } |
| 419 | 420 | db_end_transaction(0); |
| 420 | 421 | } |
| 421 | 422 |
| --- src/undo.c | |
| +++ src/undo.c | |
| @@ -58,19 +58,19 @@ | |
| 58 | if( old_exists ){ |
| 59 | db_ephemeral_blob(&q, 0, &new); |
| 60 | } |
| 61 | if( old_exists ){ |
| 62 | if( new_exists ){ |
| 63 | printf("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); |
| 64 | }else{ |
| 65 | printf("NEW %s\n", zPathname); |
| 66 | } |
| 67 | blob_write_to_file(&new, zFullname); |
| 68 | file_setexe(zFullname, old_exe); |
| 69 | }else{ |
| 70 | printf("DELETE %s\n", zPathname); |
| 71 | unlink(zFullname); |
| 72 | } |
| 73 | blob_reset(&new); |
| 74 | free(zFullname); |
| 75 | db_finalize(&q); |
| 76 | db_prepare(&q, |
| @@ -297,11 +297,11 @@ | |
| 297 | ** Complete the undo process is one is currently in process. |
| 298 | */ |
| 299 | void undo_finish(void){ |
| 300 | if( undoActive ){ |
| 301 | if( undoNeedRollback ){ |
| 302 | printf("\"fossil undo\" is available to undo changes" |
| 303 | " to the working checkout.\n"); |
| 304 | } |
| 305 | undoActive = 0; |
| 306 | undoNeedRollback = 0; |
| 307 | } |
| @@ -319,11 +319,11 @@ | |
| 319 | void undo_rollback(void){ |
| 320 | if( !undoNeedRollback ) return; |
| 321 | assert( undoActive ); |
| 322 | undoNeedRollback = 0; |
| 323 | undoActive = 0; |
| 324 | printf("Rolling back prior filesystem changes...\n"); |
| 325 | undo_all_filesystem(0); |
| 326 | } |
| 327 | |
| 328 | /* |
| 329 | ** COMMAND: undo |
| @@ -360,34 +360,35 @@ | |
| 360 | verify_all_options(); |
| 361 | db_begin_transaction(); |
| 362 | undo_available = db_lget_int("undo_available", 0); |
| 363 | if( explainFlag ){ |
| 364 | if( undo_available==0 ){ |
| 365 | printf("No undo or redo is available\n"); |
| 366 | }else{ |
| 367 | Stmt q; |
| 368 | int nChng = 0; |
| 369 | zCmd = undo_available==1 ? "undo" : "redo"; |
| 370 | printf("A %s is available for the following command:\n\n %s %s\n\n", |
| 371 | zCmd, g.argv[0], db_lget("undo_cmdline", "???")); |
| 372 | db_prepare(&q, |
| 373 | "SELECT existsflag, pathname FROM undo ORDER BY pathname" |
| 374 | ); |
| 375 | while( db_step(&q)==SQLITE_ROW ){ |
| 376 | if( nChng==0 ){ |
| 377 | printf("The following file changes would occur if the " |
| 378 | "command above is %sne:\n\n", zCmd); |
| 379 | } |
| 380 | nChng++; |
| 381 | printf("%s %s\n", |
| 382 | db_column_int(&q,0) ? "UPDATE" : "DELETE", |
| 383 | db_column_text(&q, 1) |
| 384 | ); |
| 385 | } |
| 386 | db_finalize(&q); |
| 387 | if( nChng==0 ){ |
| 388 | printf("No file changes would occur with this undo/redo.\n"); |
| 389 | } |
| 390 | } |
| 391 | }else{ |
| 392 | int vid1 = db_lget_int("checkout", 0); |
| 393 | int vid2; |
| @@ -410,11 +411,11 @@ | |
| 410 | blob_reset(&path); |
| 411 | } |
| 412 | } |
| 413 | vid2 = db_lget_int("checkout", 0); |
| 414 | if( vid1!=vid2 ){ |
| 415 | printf("--------------------\n"); |
| 416 | show_common_info(vid2, "updated-to:", 1, 0); |
| 417 | } |
| 418 | } |
| 419 | db_end_transaction(0); |
| 420 | } |
| 421 |
| --- src/undo.c | |
| +++ src/undo.c | |
| @@ -58,19 +58,19 @@ | |
| 58 | if( old_exists ){ |
| 59 | db_ephemeral_blob(&q, 0, &new); |
| 60 | } |
| 61 | if( old_exists ){ |
| 62 | if( new_exists ){ |
| 63 | fossil_print("%s %s\n", redoFlag ? "REDO" : "UNDO", zPathname); |
| 64 | }else{ |
| 65 | fossil_print("NEW %s\n", zPathname); |
| 66 | } |
| 67 | blob_write_to_file(&new, zFullname); |
| 68 | file_setexe(zFullname, old_exe); |
| 69 | }else{ |
| 70 | fossil_print("DELETE %s\n", zPathname); |
| 71 | file_delete(zFullname); |
| 72 | } |
| 73 | blob_reset(&new); |
| 74 | free(zFullname); |
| 75 | db_finalize(&q); |
| 76 | db_prepare(&q, |
| @@ -297,11 +297,11 @@ | |
| 297 | ** Complete the undo process is one is currently in process. |
| 298 | */ |
| 299 | void undo_finish(void){ |
| 300 | if( undoActive ){ |
| 301 | if( undoNeedRollback ){ |
| 302 | fossil_print("\"fossil undo\" is available to undo changes" |
| 303 | " to the working checkout.\n"); |
| 304 | } |
| 305 | undoActive = 0; |
| 306 | undoNeedRollback = 0; |
| 307 | } |
| @@ -319,11 +319,11 @@ | |
| 319 | void undo_rollback(void){ |
| 320 | if( !undoNeedRollback ) return; |
| 321 | assert( undoActive ); |
| 322 | undoNeedRollback = 0; |
| 323 | undoActive = 0; |
| 324 | fossil_print("Rolling back prior filesystem changes...\n"); |
| 325 | undo_all_filesystem(0); |
| 326 | } |
| 327 | |
| 328 | /* |
| 329 | ** COMMAND: undo |
| @@ -360,34 +360,35 @@ | |
| 360 | verify_all_options(); |
| 361 | db_begin_transaction(); |
| 362 | undo_available = db_lget_int("undo_available", 0); |
| 363 | if( explainFlag ){ |
| 364 | if( undo_available==0 ){ |
| 365 | fossil_print("No undo or redo is available\n"); |
| 366 | }else{ |
| 367 | Stmt q; |
| 368 | int nChng = 0; |
| 369 | zCmd = undo_available==1 ? "undo" : "redo"; |
| 370 | fossil_print("A %s is available for the following command:\n\n" |
| 371 | " %s %s\n\n", |
| 372 | zCmd, g.argv[0], db_lget("undo_cmdline", "???")); |
| 373 | db_prepare(&q, |
| 374 | "SELECT existsflag, pathname FROM undo ORDER BY pathname" |
| 375 | ); |
| 376 | while( db_step(&q)==SQLITE_ROW ){ |
| 377 | if( nChng==0 ){ |
| 378 | fossil_print("The following file changes would occur if the " |
| 379 | "command above is %sne:\n\n", zCmd); |
| 380 | } |
| 381 | nChng++; |
| 382 | fossil_print("%s %s\n", |
| 383 | db_column_int(&q,0) ? "UPDATE" : "DELETE", |
| 384 | db_column_text(&q, 1) |
| 385 | ); |
| 386 | } |
| 387 | db_finalize(&q); |
| 388 | if( nChng==0 ){ |
| 389 | fossil_print("No file changes would occur with this undo/redo.\n"); |
| 390 | } |
| 391 | } |
| 392 | }else{ |
| 393 | int vid1 = db_lget_int("checkout", 0); |
| 394 | int vid2; |
| @@ -410,11 +411,11 @@ | |
| 411 | blob_reset(&path); |
| 412 | } |
| 413 | } |
| 414 | vid2 = db_lget_int("checkout", 0); |
| 415 | if( vid1!=vid2 ){ |
| 416 | fossil_print("--------------------\n"); |
| 417 | show_common_info(vid2, "updated-to:", 1, 0); |
| 418 | } |
| 419 | } |
| 420 | db_end_transaction(0); |
| 421 | } |
| 422 |
+30
-24
| --- src/update.c | ||
| +++ src/update.c | ||
| @@ -175,13 +175,18 @@ | ||
| 175 | 175 | } |
| 176 | 176 | } |
| 177 | 177 | tid = db_int(0, "SELECT rid FROM leaves, event" |
| 178 | 178 | " WHERE event.objid=leaves.rid" |
| 179 | 179 | " ORDER BY event.mtime DESC"); |
| 180 | + if( tid==0 ) tid = vid; | |
| 181 | + } | |
| 182 | + | |
| 183 | + if( tid==0 ){ | |
| 184 | + fossil_panic("Internal Error: unable to find a version to update to."); | |
| 180 | 185 | } |
| 181 | 186 | |
| 182 | - if( !verboseFlag && (tid==vid)) return; /* Nothing to update */ | |
| 187 | + if( tid==vid && !verboseFlag ) return; /* Nothing to update */ | |
| 183 | 188 | db_begin_transaction(); |
| 184 | 189 | vfile_check_signature(vid, 1, 0); |
| 185 | 190 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 186 | 191 | load_vfile_from_rid(tid); |
| 187 | 192 | |
| @@ -253,18 +258,18 @@ | ||
| 253 | 258 | if( debugFlag ){ |
| 254 | 259 | db_prepare(&q, |
| 255 | 260 | "SELECT rowid, fn, fnt, chnged, ridv, ridt, isexe FROM fv" |
| 256 | 261 | ); |
| 257 | 262 | while( db_step(&q)==SQLITE_ROW ){ |
| 258 | - printf("%3d: ridv=%-4d ridt=%-4d chnged=%d isexe=%d\n", | |
| 263 | + fossil_print("%3d: ridv=%-4d ridt=%-4d chnged=%d isexe=%d\n", | |
| 259 | 264 | db_column_int(&q, 0), |
| 260 | 265 | db_column_int(&q, 4), |
| 261 | 266 | db_column_int(&q, 5), |
| 262 | 267 | db_column_int(&q, 3), |
| 263 | 268 | db_column_int(&q, 6)); |
| 264 | - printf(" fnv = [%s]\n", db_column_text(&q, 1)); | |
| 265 | - printf(" fnt = [%s]\n", db_column_text(&q, 2)); | |
| 269 | + fossil_print(" fnv = [%s]\n", db_column_text(&q, 1)); | |
| 270 | + fossil_print(" fnt = [%s]\n", db_column_text(&q, 2)); | |
| 266 | 271 | } |
| 267 | 272 | db_finalize(&q); |
| 268 | 273 | } |
| 269 | 274 | |
| 270 | 275 | /* If FILES appear on the command-line, remove from the "fv" table |
| @@ -331,26 +336,26 @@ | ||
| 331 | 336 | nameChng = fossil_strcmp(zName, zNewName); |
| 332 | 337 | if( idv>0 && ridv==0 && idt>0 && ridt>0 ){ |
| 333 | 338 | /* Conflict. This file has been added to the current checkout |
| 334 | 339 | ** but also exists in the target checkout. Use the current version. |
| 335 | 340 | */ |
| 336 | - printf("CONFLICT %s\n", zName); | |
| 341 | + fossil_print("CONFLICT %s\n", zName); | |
| 337 | 342 | nConflict++; |
| 338 | 343 | }else if( idt>0 && idv==0 ){ |
| 339 | 344 | /* File added in the target. */ |
| 340 | - printf("ADD %s\n", zName); | |
| 345 | + fossil_print("ADD %s\n", zName); | |
| 341 | 346 | undo_save(zName); |
| 342 | 347 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 343 | 348 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){ |
| 344 | 349 | /* The file is unedited. Change it to the target version */ |
| 345 | 350 | undo_save(zName); |
| 346 | - printf("UPDATE %s\n", zName); | |
| 351 | + fossil_print("UPDATE %s\n", zName); | |
| 347 | 352 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 348 | 353 | }else if( idt>0 && idv>0 && file_size(zFullPath)<0 ){ |
| 349 | 354 | /* The file missing from the local check-out. Restore it to the |
| 350 | 355 | ** version that appears in the target. */ |
| 351 | - printf("UPDATE %s\n", zName); | |
| 356 | + fossil_print("UPDATE %s\n", zName); | |
| 352 | 357 | undo_save(zName); |
| 353 | 358 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 354 | 359 | }else if( idt==0 && idv>0 ){ |
| 355 | 360 | if( ridv==0 ){ |
| 356 | 361 | /* Added in current checkout. Continue to hold the file as |
| @@ -357,25 +362,26 @@ | ||
| 357 | 362 | ** as an addition */ |
| 358 | 363 | db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv); |
| 359 | 364 | }else if( chnged ){ |
| 360 | 365 | /* Edited locally but deleted from the target. Do not track the |
| 361 | 366 | ** file but keep the edited version around. */ |
| 362 | - printf("CONFLICT %s - edited locally but deleted by update\n", zName); | |
| 367 | + fossil_print("CONFLICT %s - edited locally but deleted by update\n", | |
| 368 | + zName); | |
| 363 | 369 | nConflict++; |
| 364 | 370 | }else{ |
| 365 | - printf("REMOVE %s\n", zName); | |
| 371 | + fossil_print("REMOVE %s\n", zName); | |
| 366 | 372 | undo_save(zName); |
| 367 | - if( !nochangeFlag ) unlink(zFullPath); | |
| 373 | + if( !nochangeFlag ) file_delete(zFullPath); | |
| 368 | 374 | } |
| 369 | 375 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){ |
| 370 | 376 | /* Merge the changes in the current tree into the target version */ |
| 371 | 377 | Blob r, t, v; |
| 372 | 378 | int rc; |
| 373 | 379 | if( nameChng ){ |
| 374 | - printf("MERGE %s -> %s\n", zName, zNewName); | |
| 380 | + fossil_print("MERGE %s -> %s\n", zName, zNewName); | |
| 375 | 381 | }else{ |
| 376 | - printf("MERGE %s\n", zName); | |
| 382 | + fossil_print("MERGE %s\n", zName); | |
| 377 | 383 | } |
| 378 | 384 | undo_save(zName); |
| 379 | 385 | content_get(ridt, &t); |
| 380 | 386 | content_get(ridv, &v); |
| 381 | 387 | rc = merge_3way(&v, zFullPath, &t, &r); |
| @@ -383,51 +389,51 @@ | ||
| 383 | 389 | if( !nochangeFlag ){ |
| 384 | 390 | blob_write_to_file(&r, zFullNewPath); |
| 385 | 391 | file_setexe(zFullNewPath, isexe); |
| 386 | 392 | } |
| 387 | 393 | if( rc>0 ){ |
| 388 | - printf("***** %d merge conflicts in %s\n", rc, zNewName); | |
| 394 | + fossil_print("***** %d merge conflicts in %s\n", rc, zNewName); | |
| 389 | 395 | nConflict++; |
| 390 | 396 | } |
| 391 | 397 | }else{ |
| 392 | 398 | if( !nochangeFlag ){ |
| 393 | 399 | blob_write_to_file(&t, zFullNewPath); |
| 394 | 400 | file_setexe(zFullNewPath, isexe); |
| 395 | 401 | } |
| 396 | - printf("***** Cannot merge binary file %s\n", zNewName); | |
| 402 | + fossil_print("***** Cannot merge binary file %s\n", zNewName); | |
| 397 | 403 | nConflict++; |
| 398 | 404 | } |
| 399 | - if( nameChng && !nochangeFlag ) unlink(zFullPath); | |
| 405 | + if( nameChng && !nochangeFlag ) file_delete(zFullPath); | |
| 400 | 406 | blob_reset(&v); |
| 401 | 407 | blob_reset(&t); |
| 402 | 408 | blob_reset(&r); |
| 403 | 409 | }else{ |
| 404 | 410 | if( chnged ){ |
| 405 | - if( verboseFlag ) printf("EDITED %s\n", zName); | |
| 411 | + if( verboseFlag ) fossil_print("EDITED %s\n", zName); | |
| 406 | 412 | }else{ |
| 407 | 413 | db_bind_int(&mtimeXfer, ":idv", idv); |
| 408 | 414 | db_bind_int(&mtimeXfer, ":idt", idt); |
| 409 | 415 | db_step(&mtimeXfer); |
| 410 | 416 | db_reset(&mtimeXfer); |
| 411 | - if( verboseFlag ) printf("UNCHANGED %s\n", zName); | |
| 417 | + if( verboseFlag ) fossil_print("UNCHANGED %s\n", zName); | |
| 412 | 418 | } |
| 413 | 419 | } |
| 414 | 420 | free(zFullPath); |
| 415 | 421 | free(zFullNewPath); |
| 416 | 422 | } |
| 417 | 423 | db_finalize(&q); |
| 418 | 424 | db_finalize(&mtimeXfer); |
| 419 | - printf("--------------\n"); | |
| 425 | + fossil_print("--------------\n"); | |
| 420 | 426 | show_common_info(tid, "updated-to:", 1, 0); |
| 421 | 427 | |
| 422 | 428 | /* Report on conflicts |
| 423 | 429 | */ |
| 424 | 430 | if( nConflict && !nochangeFlag ){ |
| 425 | 431 | if( internalUpdate ){ |
| 426 | 432 | internalConflictCnt = nConflict; |
| 427 | 433 | }else{ |
| 428 | - printf("WARNING: %d merge conflicts - see messages above for details.\n", | |
| 434 | + fossil_print("WARNING: %d merge conflicts - see messages above for details.\n", | |
| 429 | 435 | nConflict); |
| 430 | 436 | } |
| 431 | 437 | } |
| 432 | 438 | |
| 433 | 439 | /* |
| @@ -570,23 +576,23 @@ | ||
| 570 | 576 | zFile = db_column_text(&q, 0); |
| 571 | 577 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 572 | 578 | errCode = historical_version_of_file(zRevision, zFile, &record, &isExe,2); |
| 573 | 579 | if( errCode==2 ){ |
| 574 | 580 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){ |
| 575 | - printf("UNMANAGE: %s\n", zFile); | |
| 581 | + fossil_print("UNMANAGE: %s\n", zFile); | |
| 576 | 582 | }else{ |
| 577 | 583 | undo_save(zFile); |
| 578 | - unlink(zFull); | |
| 579 | - printf("DELETE: %s\n", zFile); | |
| 584 | + file_delete(zFull); | |
| 585 | + fossil_print("DELETE: %s\n", zFile); | |
| 580 | 586 | } |
| 581 | 587 | db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile); |
| 582 | 588 | }else{ |
| 583 | 589 | sqlite3_int64 mtime; |
| 584 | 590 | undo_save(zFile); |
| 585 | 591 | blob_write_to_file(&record, zFull); |
| 586 | 592 | file_setexe(zFull, isExe); |
| 587 | - printf("REVERTED: %s\n", zFile); | |
| 593 | + fossil_print("REVERTED: %s\n", zFile); | |
| 588 | 594 | mtime = file_mtime(zFull); |
| 589 | 595 | db_multi_exec( |
| 590 | 596 | "UPDATE vfile" |
| 591 | 597 | " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, mrid=rid," |
| 592 | 598 | " pathname=coalesce(origname,pathname), origname=NULL" |
| 593 | 599 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -175,13 +175,18 @@ | |
| 175 | } |
| 176 | } |
| 177 | tid = db_int(0, "SELECT rid FROM leaves, event" |
| 178 | " WHERE event.objid=leaves.rid" |
| 179 | " ORDER BY event.mtime DESC"); |
| 180 | } |
| 181 | |
| 182 | if( !verboseFlag && (tid==vid)) return; /* Nothing to update */ |
| 183 | db_begin_transaction(); |
| 184 | vfile_check_signature(vid, 1, 0); |
| 185 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 186 | load_vfile_from_rid(tid); |
| 187 | |
| @@ -253,18 +258,18 @@ | |
| 253 | if( debugFlag ){ |
| 254 | db_prepare(&q, |
| 255 | "SELECT rowid, fn, fnt, chnged, ridv, ridt, isexe FROM fv" |
| 256 | ); |
| 257 | while( db_step(&q)==SQLITE_ROW ){ |
| 258 | printf("%3d: ridv=%-4d ridt=%-4d chnged=%d isexe=%d\n", |
| 259 | db_column_int(&q, 0), |
| 260 | db_column_int(&q, 4), |
| 261 | db_column_int(&q, 5), |
| 262 | db_column_int(&q, 3), |
| 263 | db_column_int(&q, 6)); |
| 264 | printf(" fnv = [%s]\n", db_column_text(&q, 1)); |
| 265 | printf(" fnt = [%s]\n", db_column_text(&q, 2)); |
| 266 | } |
| 267 | db_finalize(&q); |
| 268 | } |
| 269 | |
| 270 | /* If FILES appear on the command-line, remove from the "fv" table |
| @@ -331,26 +336,26 @@ | |
| 331 | nameChng = fossil_strcmp(zName, zNewName); |
| 332 | if( idv>0 && ridv==0 && idt>0 && ridt>0 ){ |
| 333 | /* Conflict. This file has been added to the current checkout |
| 334 | ** but also exists in the target checkout. Use the current version. |
| 335 | */ |
| 336 | printf("CONFLICT %s\n", zName); |
| 337 | nConflict++; |
| 338 | }else if( idt>0 && idv==0 ){ |
| 339 | /* File added in the target. */ |
| 340 | printf("ADD %s\n", zName); |
| 341 | undo_save(zName); |
| 342 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 343 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){ |
| 344 | /* The file is unedited. Change it to the target version */ |
| 345 | undo_save(zName); |
| 346 | printf("UPDATE %s\n", zName); |
| 347 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 348 | }else if( idt>0 && idv>0 && file_size(zFullPath)<0 ){ |
| 349 | /* The file missing from the local check-out. Restore it to the |
| 350 | ** version that appears in the target. */ |
| 351 | printf("UPDATE %s\n", zName); |
| 352 | undo_save(zName); |
| 353 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 354 | }else if( idt==0 && idv>0 ){ |
| 355 | if( ridv==0 ){ |
| 356 | /* Added in current checkout. Continue to hold the file as |
| @@ -357,25 +362,26 @@ | |
| 357 | ** as an addition */ |
| 358 | db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv); |
| 359 | }else if( chnged ){ |
| 360 | /* Edited locally but deleted from the target. Do not track the |
| 361 | ** file but keep the edited version around. */ |
| 362 | printf("CONFLICT %s - edited locally but deleted by update\n", zName); |
| 363 | nConflict++; |
| 364 | }else{ |
| 365 | printf("REMOVE %s\n", zName); |
| 366 | undo_save(zName); |
| 367 | if( !nochangeFlag ) unlink(zFullPath); |
| 368 | } |
| 369 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){ |
| 370 | /* Merge the changes in the current tree into the target version */ |
| 371 | Blob r, t, v; |
| 372 | int rc; |
| 373 | if( nameChng ){ |
| 374 | printf("MERGE %s -> %s\n", zName, zNewName); |
| 375 | }else{ |
| 376 | printf("MERGE %s\n", zName); |
| 377 | } |
| 378 | undo_save(zName); |
| 379 | content_get(ridt, &t); |
| 380 | content_get(ridv, &v); |
| 381 | rc = merge_3way(&v, zFullPath, &t, &r); |
| @@ -383,51 +389,51 @@ | |
| 383 | if( !nochangeFlag ){ |
| 384 | blob_write_to_file(&r, zFullNewPath); |
| 385 | file_setexe(zFullNewPath, isexe); |
| 386 | } |
| 387 | if( rc>0 ){ |
| 388 | printf("***** %d merge conflicts in %s\n", rc, zNewName); |
| 389 | nConflict++; |
| 390 | } |
| 391 | }else{ |
| 392 | if( !nochangeFlag ){ |
| 393 | blob_write_to_file(&t, zFullNewPath); |
| 394 | file_setexe(zFullNewPath, isexe); |
| 395 | } |
| 396 | printf("***** Cannot merge binary file %s\n", zNewName); |
| 397 | nConflict++; |
| 398 | } |
| 399 | if( nameChng && !nochangeFlag ) unlink(zFullPath); |
| 400 | blob_reset(&v); |
| 401 | blob_reset(&t); |
| 402 | blob_reset(&r); |
| 403 | }else{ |
| 404 | if( chnged ){ |
| 405 | if( verboseFlag ) printf("EDITED %s\n", zName); |
| 406 | }else{ |
| 407 | db_bind_int(&mtimeXfer, ":idv", idv); |
| 408 | db_bind_int(&mtimeXfer, ":idt", idt); |
| 409 | db_step(&mtimeXfer); |
| 410 | db_reset(&mtimeXfer); |
| 411 | if( verboseFlag ) printf("UNCHANGED %s\n", zName); |
| 412 | } |
| 413 | } |
| 414 | free(zFullPath); |
| 415 | free(zFullNewPath); |
| 416 | } |
| 417 | db_finalize(&q); |
| 418 | db_finalize(&mtimeXfer); |
| 419 | printf("--------------\n"); |
| 420 | show_common_info(tid, "updated-to:", 1, 0); |
| 421 | |
| 422 | /* Report on conflicts |
| 423 | */ |
| 424 | if( nConflict && !nochangeFlag ){ |
| 425 | if( internalUpdate ){ |
| 426 | internalConflictCnt = nConflict; |
| 427 | }else{ |
| 428 | printf("WARNING: %d merge conflicts - see messages above for details.\n", |
| 429 | nConflict); |
| 430 | } |
| 431 | } |
| 432 | |
| 433 | /* |
| @@ -570,23 +576,23 @@ | |
| 570 | zFile = db_column_text(&q, 0); |
| 571 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 572 | errCode = historical_version_of_file(zRevision, zFile, &record, &isExe,2); |
| 573 | if( errCode==2 ){ |
| 574 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){ |
| 575 | printf("UNMANAGE: %s\n", zFile); |
| 576 | }else{ |
| 577 | undo_save(zFile); |
| 578 | unlink(zFull); |
| 579 | printf("DELETE: %s\n", zFile); |
| 580 | } |
| 581 | db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile); |
| 582 | }else{ |
| 583 | sqlite3_int64 mtime; |
| 584 | undo_save(zFile); |
| 585 | blob_write_to_file(&record, zFull); |
| 586 | file_setexe(zFull, isExe); |
| 587 | printf("REVERTED: %s\n", zFile); |
| 588 | mtime = file_mtime(zFull); |
| 589 | db_multi_exec( |
| 590 | "UPDATE vfile" |
| 591 | " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, mrid=rid," |
| 592 | " pathname=coalesce(origname,pathname), origname=NULL" |
| 593 |
| --- src/update.c | |
| +++ src/update.c | |
| @@ -175,13 +175,18 @@ | |
| 175 | } |
| 176 | } |
| 177 | tid = db_int(0, "SELECT rid FROM leaves, event" |
| 178 | " WHERE event.objid=leaves.rid" |
| 179 | " ORDER BY event.mtime DESC"); |
| 180 | if( tid==0 ) tid = vid; |
| 181 | } |
| 182 | |
| 183 | if( tid==0 ){ |
| 184 | fossil_panic("Internal Error: unable to find a version to update to."); |
| 185 | } |
| 186 | |
| 187 | if( tid==vid && !verboseFlag ) return; /* Nothing to update */ |
| 188 | db_begin_transaction(); |
| 189 | vfile_check_signature(vid, 1, 0); |
| 190 | if( !nochangeFlag && !internalUpdate ) undo_begin(); |
| 191 | load_vfile_from_rid(tid); |
| 192 | |
| @@ -253,18 +258,18 @@ | |
| 258 | if( debugFlag ){ |
| 259 | db_prepare(&q, |
| 260 | "SELECT rowid, fn, fnt, chnged, ridv, ridt, isexe FROM fv" |
| 261 | ); |
| 262 | while( db_step(&q)==SQLITE_ROW ){ |
| 263 | fossil_print("%3d: ridv=%-4d ridt=%-4d chnged=%d isexe=%d\n", |
| 264 | db_column_int(&q, 0), |
| 265 | db_column_int(&q, 4), |
| 266 | db_column_int(&q, 5), |
| 267 | db_column_int(&q, 3), |
| 268 | db_column_int(&q, 6)); |
| 269 | fossil_print(" fnv = [%s]\n", db_column_text(&q, 1)); |
| 270 | fossil_print(" fnt = [%s]\n", db_column_text(&q, 2)); |
| 271 | } |
| 272 | db_finalize(&q); |
| 273 | } |
| 274 | |
| 275 | /* If FILES appear on the command-line, remove from the "fv" table |
| @@ -331,26 +336,26 @@ | |
| 336 | nameChng = fossil_strcmp(zName, zNewName); |
| 337 | if( idv>0 && ridv==0 && idt>0 && ridt>0 ){ |
| 338 | /* Conflict. This file has been added to the current checkout |
| 339 | ** but also exists in the target checkout. Use the current version. |
| 340 | */ |
| 341 | fossil_print("CONFLICT %s\n", zName); |
| 342 | nConflict++; |
| 343 | }else if( idt>0 && idv==0 ){ |
| 344 | /* File added in the target. */ |
| 345 | fossil_print("ADD %s\n", zName); |
| 346 | undo_save(zName); |
| 347 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 348 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){ |
| 349 | /* The file is unedited. Change it to the target version */ |
| 350 | undo_save(zName); |
| 351 | fossil_print("UPDATE %s\n", zName); |
| 352 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 353 | }else if( idt>0 && idv>0 && file_size(zFullPath)<0 ){ |
| 354 | /* The file missing from the local check-out. Restore it to the |
| 355 | ** version that appears in the target. */ |
| 356 | fossil_print("UPDATE %s\n", zName); |
| 357 | undo_save(zName); |
| 358 | if( !nochangeFlag ) vfile_to_disk(0, idt, 0, 0); |
| 359 | }else if( idt==0 && idv>0 ){ |
| 360 | if( ridv==0 ){ |
| 361 | /* Added in current checkout. Continue to hold the file as |
| @@ -357,25 +362,26 @@ | |
| 362 | ** as an addition */ |
| 363 | db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv); |
| 364 | }else if( chnged ){ |
| 365 | /* Edited locally but deleted from the target. Do not track the |
| 366 | ** file but keep the edited version around. */ |
| 367 | fossil_print("CONFLICT %s - edited locally but deleted by update\n", |
| 368 | zName); |
| 369 | nConflict++; |
| 370 | }else{ |
| 371 | fossil_print("REMOVE %s\n", zName); |
| 372 | undo_save(zName); |
| 373 | if( !nochangeFlag ) file_delete(zFullPath); |
| 374 | } |
| 375 | }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){ |
| 376 | /* Merge the changes in the current tree into the target version */ |
| 377 | Blob r, t, v; |
| 378 | int rc; |
| 379 | if( nameChng ){ |
| 380 | fossil_print("MERGE %s -> %s\n", zName, zNewName); |
| 381 | }else{ |
| 382 | fossil_print("MERGE %s\n", zName); |
| 383 | } |
| 384 | undo_save(zName); |
| 385 | content_get(ridt, &t); |
| 386 | content_get(ridv, &v); |
| 387 | rc = merge_3way(&v, zFullPath, &t, &r); |
| @@ -383,51 +389,51 @@ | |
| 389 | if( !nochangeFlag ){ |
| 390 | blob_write_to_file(&r, zFullNewPath); |
| 391 | file_setexe(zFullNewPath, isexe); |
| 392 | } |
| 393 | if( rc>0 ){ |
| 394 | fossil_print("***** %d merge conflicts in %s\n", rc, zNewName); |
| 395 | nConflict++; |
| 396 | } |
| 397 | }else{ |
| 398 | if( !nochangeFlag ){ |
| 399 | blob_write_to_file(&t, zFullNewPath); |
| 400 | file_setexe(zFullNewPath, isexe); |
| 401 | } |
| 402 | fossil_print("***** Cannot merge binary file %s\n", zNewName); |
| 403 | nConflict++; |
| 404 | } |
| 405 | if( nameChng && !nochangeFlag ) file_delete(zFullPath); |
| 406 | blob_reset(&v); |
| 407 | blob_reset(&t); |
| 408 | blob_reset(&r); |
| 409 | }else{ |
| 410 | if( chnged ){ |
| 411 | if( verboseFlag ) fossil_print("EDITED %s\n", zName); |
| 412 | }else{ |
| 413 | db_bind_int(&mtimeXfer, ":idv", idv); |
| 414 | db_bind_int(&mtimeXfer, ":idt", idt); |
| 415 | db_step(&mtimeXfer); |
| 416 | db_reset(&mtimeXfer); |
| 417 | if( verboseFlag ) fossil_print("UNCHANGED %s\n", zName); |
| 418 | } |
| 419 | } |
| 420 | free(zFullPath); |
| 421 | free(zFullNewPath); |
| 422 | } |
| 423 | db_finalize(&q); |
| 424 | db_finalize(&mtimeXfer); |
| 425 | fossil_print("--------------\n"); |
| 426 | show_common_info(tid, "updated-to:", 1, 0); |
| 427 | |
| 428 | /* Report on conflicts |
| 429 | */ |
| 430 | if( nConflict && !nochangeFlag ){ |
| 431 | if( internalUpdate ){ |
| 432 | internalConflictCnt = nConflict; |
| 433 | }else{ |
| 434 | fossil_print("WARNING: %d merge conflicts - see messages above for details.\n", |
| 435 | nConflict); |
| 436 | } |
| 437 | } |
| 438 | |
| 439 | /* |
| @@ -570,23 +576,23 @@ | |
| 576 | zFile = db_column_text(&q, 0); |
| 577 | zFull = mprintf("%/%/", g.zLocalRoot, zFile); |
| 578 | errCode = historical_version_of_file(zRevision, zFile, &record, &isExe,2); |
| 579 | if( errCode==2 ){ |
| 580 | if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q", zFile)==0 ){ |
| 581 | fossil_print("UNMANAGE: %s\n", zFile); |
| 582 | }else{ |
| 583 | undo_save(zFile); |
| 584 | file_delete(zFull); |
| 585 | fossil_print("DELETE: %s\n", zFile); |
| 586 | } |
| 587 | db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile); |
| 588 | }else{ |
| 589 | sqlite3_int64 mtime; |
| 590 | undo_save(zFile); |
| 591 | blob_write_to_file(&record, zFull); |
| 592 | file_setexe(zFull, isExe); |
| 593 | fossil_print("REVERTED: %s\n", zFile); |
| 594 | mtime = file_mtime(zFull); |
| 595 | db_multi_exec( |
| 596 | "UPDATE vfile" |
| 597 | " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, mrid=rid," |
| 598 | " pathname=coalesce(origname,pathname), origname=NULL" |
| 599 |
+15
-15
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -208,26 +208,26 @@ | ||
| 208 | 208 | if( g.argc!=3 && g.argc!=4 ){ |
| 209 | 209 | usage("URL"); |
| 210 | 210 | } |
| 211 | 211 | url_parse(g.argv[2]); |
| 212 | 212 | for(i=0; i<2; i++){ |
| 213 | - printf("g.urlIsFile = %d\n", g.urlIsFile); | |
| 214 | - printf("g.urlIsHttps = %d\n", g.urlIsHttps); | |
| 215 | - printf("g.urlIsSsh = %d\n", g.urlIsSsh); | |
| 216 | - printf("g.urlProtocol = %s\n", g.urlProtocol); | |
| 217 | - printf("g.urlName = %s\n", g.urlName); | |
| 218 | - printf("g.urlPort = %d\n", g.urlPort); | |
| 219 | - printf("g.urlDfltPort = %d\n", g.urlDfltPort); | |
| 220 | - printf("g.urlHostname = %s\n", g.urlHostname); | |
| 221 | - printf("g.urlPath = %s\n", g.urlPath); | |
| 222 | - printf("g.urlUser = %s\n", g.urlUser); | |
| 223 | - printf("g.urlPasswd = %s\n", g.urlPasswd); | |
| 224 | - printf("g.urlCanonical = %s\n", g.urlCanonical); | |
| 225 | - printf("g.urlFossil = %s\n", g.urlFossil); | |
| 213 | + fossil_print("g.urlIsFile = %d\n", g.urlIsFile); | |
| 214 | + fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps); | |
| 215 | + fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh); | |
| 216 | + fossil_print("g.urlProtocol = %s\n", g.urlProtocol); | |
| 217 | + fossil_print("g.urlName = %s\n", g.urlName); | |
| 218 | + fossil_print("g.urlPort = %d\n", g.urlPort); | |
| 219 | + fossil_print("g.urlDfltPort = %d\n", g.urlDfltPort); | |
| 220 | + fossil_print("g.urlHostname = %s\n", g.urlHostname); | |
| 221 | + fossil_print("g.urlPath = %s\n", g.urlPath); | |
| 222 | + fossil_print("g.urlUser = %s\n", g.urlUser); | |
| 223 | + fossil_print("g.urlPasswd = %s\n", g.urlPasswd); | |
| 224 | + fossil_print("g.urlCanonical = %s\n", g.urlCanonical); | |
| 225 | + fossil_print("g.urlFossil = %s\n", g.urlFossil); | |
| 226 | 226 | if( g.urlIsFile || g.urlIsSsh ) break; |
| 227 | 227 | if( i==0 ){ |
| 228 | - printf("********\n"); | |
| 228 | + fossil_print("********\n"); | |
| 229 | 229 | url_enable_proxy("Using proxy: "); |
| 230 | 230 | } |
| 231 | 231 | } |
| 232 | 232 | } |
| 233 | 233 | |
| @@ -276,11 +276,11 @@ | ||
| 276 | 276 | char *zOriginalUser = g.urlUser; |
| 277 | 277 | char *zOriginalPasswd = g.urlPasswd; |
| 278 | 278 | g.urlUser = 0; |
| 279 | 279 | g.urlPasswd = ""; |
| 280 | 280 | url_parse(zProxy); |
| 281 | - if( zMsg ) printf("%s%s\n", zMsg, g.urlCanonical); | |
| 281 | + if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical); | |
| 282 | 282 | g.urlPath = zOriginalUrl; |
| 283 | 283 | g.urlHostname = zOriginalHost; |
| 284 | 284 | if( g.urlUser ){ |
| 285 | 285 | char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd); |
| 286 | 286 | char *zCredentials2 = encode64(zCredentials1, -1); |
| 287 | 287 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -208,26 +208,26 @@ | |
| 208 | if( g.argc!=3 && g.argc!=4 ){ |
| 209 | usage("URL"); |
| 210 | } |
| 211 | url_parse(g.argv[2]); |
| 212 | for(i=0; i<2; i++){ |
| 213 | printf("g.urlIsFile = %d\n", g.urlIsFile); |
| 214 | printf("g.urlIsHttps = %d\n", g.urlIsHttps); |
| 215 | printf("g.urlIsSsh = %d\n", g.urlIsSsh); |
| 216 | printf("g.urlProtocol = %s\n", g.urlProtocol); |
| 217 | printf("g.urlName = %s\n", g.urlName); |
| 218 | printf("g.urlPort = %d\n", g.urlPort); |
| 219 | printf("g.urlDfltPort = %d\n", g.urlDfltPort); |
| 220 | printf("g.urlHostname = %s\n", g.urlHostname); |
| 221 | printf("g.urlPath = %s\n", g.urlPath); |
| 222 | printf("g.urlUser = %s\n", g.urlUser); |
| 223 | printf("g.urlPasswd = %s\n", g.urlPasswd); |
| 224 | printf("g.urlCanonical = %s\n", g.urlCanonical); |
| 225 | printf("g.urlFossil = %s\n", g.urlFossil); |
| 226 | if( g.urlIsFile || g.urlIsSsh ) break; |
| 227 | if( i==0 ){ |
| 228 | printf("********\n"); |
| 229 | url_enable_proxy("Using proxy: "); |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
| @@ -276,11 +276,11 @@ | |
| 276 | char *zOriginalUser = g.urlUser; |
| 277 | char *zOriginalPasswd = g.urlPasswd; |
| 278 | g.urlUser = 0; |
| 279 | g.urlPasswd = ""; |
| 280 | url_parse(zProxy); |
| 281 | if( zMsg ) printf("%s%s\n", zMsg, g.urlCanonical); |
| 282 | g.urlPath = zOriginalUrl; |
| 283 | g.urlHostname = zOriginalHost; |
| 284 | if( g.urlUser ){ |
| 285 | char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd); |
| 286 | char *zCredentials2 = encode64(zCredentials1, -1); |
| 287 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -208,26 +208,26 @@ | |
| 208 | if( g.argc!=3 && g.argc!=4 ){ |
| 209 | usage("URL"); |
| 210 | } |
| 211 | url_parse(g.argv[2]); |
| 212 | for(i=0; i<2; i++){ |
| 213 | fossil_print("g.urlIsFile = %d\n", g.urlIsFile); |
| 214 | fossil_print("g.urlIsHttps = %d\n", g.urlIsHttps); |
| 215 | fossil_print("g.urlIsSsh = %d\n", g.urlIsSsh); |
| 216 | fossil_print("g.urlProtocol = %s\n", g.urlProtocol); |
| 217 | fossil_print("g.urlName = %s\n", g.urlName); |
| 218 | fossil_print("g.urlPort = %d\n", g.urlPort); |
| 219 | fossil_print("g.urlDfltPort = %d\n", g.urlDfltPort); |
| 220 | fossil_print("g.urlHostname = %s\n", g.urlHostname); |
| 221 | fossil_print("g.urlPath = %s\n", g.urlPath); |
| 222 | fossil_print("g.urlUser = %s\n", g.urlUser); |
| 223 | fossil_print("g.urlPasswd = %s\n", g.urlPasswd); |
| 224 | fossil_print("g.urlCanonical = %s\n", g.urlCanonical); |
| 225 | fossil_print("g.urlFossil = %s\n", g.urlFossil); |
| 226 | if( g.urlIsFile || g.urlIsSsh ) break; |
| 227 | if( i==0 ){ |
| 228 | fossil_print("********\n"); |
| 229 | url_enable_proxy("Using proxy: "); |
| 230 | } |
| 231 | } |
| 232 | } |
| 233 | |
| @@ -276,11 +276,11 @@ | |
| 276 | char *zOriginalUser = g.urlUser; |
| 277 | char *zOriginalPasswd = g.urlPasswd; |
| 278 | g.urlUser = 0; |
| 279 | g.urlPasswd = ""; |
| 280 | url_parse(zProxy); |
| 281 | if( zMsg ) fossil_print("%s%s\n", zMsg, g.urlCanonical); |
| 282 | g.urlPath = zOriginalUrl; |
| 283 | g.urlHostname = zOriginalHost; |
| 284 | if( g.urlUser ){ |
| 285 | char *zCredentials1 = mprintf("%s:%s", g.urlUser, g.urlPasswd); |
| 286 | char *zCredentials2 = encode64(zCredentials1, -1); |
| 287 |
+15
-14
| --- src/user.c | ||
| +++ src/user.c | ||
| @@ -117,11 +117,11 @@ | ||
| 117 | 117 | prompt_for_passphrase(zPrompt, pPassphrase); |
| 118 | 118 | if( verify==0 ) break; |
| 119 | 119 | if( verify==1 && blob_size(pPassphrase)==0 ) break; |
| 120 | 120 | prompt_for_passphrase("Retype new password: ", &secondTry); |
| 121 | 121 | if( blob_compare(pPassphrase, &secondTry) ){ |
| 122 | - printf("Passphrases do not match. Try again...\n"); | |
| 122 | + fossil_print("Passphrases do not match. Try again...\n"); | |
| 123 | 123 | }else{ |
| 124 | 124 | break; |
| 125 | 125 | } |
| 126 | 126 | } |
| 127 | 127 | blob_reset(&secondTry); |
| @@ -132,11 +132,11 @@ | ||
| 132 | 132 | */ |
| 133 | 133 | void prompt_user(const char *zPrompt, Blob *pIn){ |
| 134 | 134 | char *z; |
| 135 | 135 | char zLine[1000]; |
| 136 | 136 | blob_zero(pIn); |
| 137 | - printf("%s", zPrompt); | |
| 137 | + fossil_print("%s", zPrompt); | |
| 138 | 138 | fflush(stdout); |
| 139 | 139 | z = fgets(zLine, sizeof(zLine), stdin); |
| 140 | 140 | if( z ){ |
| 141 | 141 | strip_string(pIn, z); |
| 142 | 142 | } |
| @@ -204,19 +204,19 @@ | ||
| 204 | 204 | }else{ |
| 205 | 205 | prompt_for_password("password: ", &passwd, 1); |
| 206 | 206 | } |
| 207 | 207 | zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0); |
| 208 | 208 | db_multi_exec( |
| 209 | - "INSERT INTO user(login,pw,cap,info)" | |
| 210 | - "VALUES(%B,%Q,%B,%B)", | |
| 209 | + "INSERT INTO user(login,pw,cap,info,mtime)" | |
| 210 | + "VALUES(%B,%Q,%B,%B,now())", | |
| 211 | 211 | &login, zPw, &caps, &contact |
| 212 | 212 | ); |
| 213 | 213 | free(zPw); |
| 214 | 214 | }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){ |
| 215 | 215 | user_select(); |
| 216 | 216 | if( g.argc==3 ){ |
| 217 | - printf("%s\n", g.zLogin); | |
| 217 | + fossil_print("%s\n", g.zLogin); | |
| 218 | 218 | }else{ |
| 219 | 219 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.argv[3]) ){ |
| 220 | 220 | fossil_fatal("no such user: %s", g.argv[3]); |
| 221 | 221 | } |
| 222 | 222 | if( g.localOpen ){ |
| @@ -227,11 +227,11 @@ | ||
| 227 | 227 | } |
| 228 | 228 | }else if( n>=2 && strncmp(g.argv[2],"list",n)==0 ){ |
| 229 | 229 | Stmt q; |
| 230 | 230 | db_prepare(&q, "SELECT login, info FROM user ORDER BY login"); |
| 231 | 231 | while( db_step(&q)==SQLITE_ROW ){ |
| 232 | - printf("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); | |
| 232 | + fossil_print("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); | |
| 233 | 233 | } |
| 234 | 234 | db_finalize(&q); |
| 235 | 235 | }else if( n>=2 && strncmp(g.argv[2],"password",2)==0 ){ |
| 236 | 236 | char *zPrompt; |
| 237 | 237 | int uid; |
| @@ -246,14 +246,15 @@ | ||
| 246 | 246 | }else{ |
| 247 | 247 | zPrompt = mprintf("New password for %s: ", g.argv[3]); |
| 248 | 248 | prompt_for_password(zPrompt, &pw, 1); |
| 249 | 249 | } |
| 250 | 250 | if( blob_size(&pw)==0 ){ |
| 251 | - printf("password unchanged\n"); | |
| 251 | + fossil_print("password unchanged\n"); | |
| 252 | 252 | }else{ |
| 253 | 253 | char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); |
| 254 | - db_multi_exec("UPDATE user SET pw=%Q WHERE uid=%d", zSecret, uid); | |
| 254 | + db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d", | |
| 255 | + zSecret, uid); | |
| 255 | 256 | free(zSecret); |
| 256 | 257 | } |
| 257 | 258 | }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ |
| 258 | 259 | int uid; |
| 259 | 260 | if( g.argc!=4 && g.argc!=5 ){ |
| @@ -263,15 +264,15 @@ | ||
| 263 | 264 | if( uid==0 ){ |
| 264 | 265 | fossil_fatal("no such user: %s", g.argv[3]); |
| 265 | 266 | } |
| 266 | 267 | if( g.argc==5 ){ |
| 267 | 268 | db_multi_exec( |
| 268 | - "UPDATE user SET cap=%Q WHERE uid=%d", g.argv[4], | |
| 269 | - uid | |
| 269 | + "UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d", | |
| 270 | + g.argv[4], uid | |
| 270 | 271 | ); |
| 271 | 272 | } |
| 272 | - printf("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); | |
| 273 | + fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); | |
| 273 | 274 | }else{ |
| 274 | 275 | fossil_panic("user subcommand should be one of: " |
| 275 | 276 | "capabilities default list new password"); |
| 276 | 277 | } |
| 277 | 278 | } |
| @@ -340,12 +341,12 @@ | ||
| 340 | 341 | db_finalize(&s); |
| 341 | 342 | } |
| 342 | 343 | |
| 343 | 344 | if( g.userUid==0 ){ |
| 344 | 345 | db_multi_exec( |
| 345 | - "INSERT INTO user(login, pw, cap, info)" | |
| 346 | - "VALUES('anonymous', '', 'cfghjkmnoqw', '')" | |
| 346 | + "INSERT INTO user(login, pw, cap, info, mtime)" | |
| 347 | + "VALUES('anonymous', '', 'cfghjkmnoqw', '', now())" | |
| 347 | 348 | ); |
| 348 | 349 | g.userUid = db_last_insert_rowid(); |
| 349 | 350 | g.zLogin = "anonymous"; |
| 350 | 351 | } |
| 351 | 352 | } |
| @@ -364,11 +365,11 @@ | ||
| 364 | 365 | if( g.argc!=3 ) usage("REPOSITORY"); |
| 365 | 366 | db_open_repository(g.argv[2]); |
| 366 | 367 | sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, |
| 367 | 368 | sha1_shared_secret_sql_function, 0, 0); |
| 368 | 369 | db_multi_exec( |
| 369 | - "UPDATE user SET pw=shared_secret(pw,login)" | |
| 370 | + "UPDATE user SET pw=shared_secret(pw,login), mtime=now()" | |
| 370 | 371 | " WHERE length(pw)>0 AND length(pw)!=40" |
| 371 | 372 | ); |
| 372 | 373 | } |
| 373 | 374 | |
| 374 | 375 | /* |
| 375 | 376 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -117,11 +117,11 @@ | |
| 117 | prompt_for_passphrase(zPrompt, pPassphrase); |
| 118 | if( verify==0 ) break; |
| 119 | if( verify==1 && blob_size(pPassphrase)==0 ) break; |
| 120 | prompt_for_passphrase("Retype new password: ", &secondTry); |
| 121 | if( blob_compare(pPassphrase, &secondTry) ){ |
| 122 | printf("Passphrases do not match. Try again...\n"); |
| 123 | }else{ |
| 124 | break; |
| 125 | } |
| 126 | } |
| 127 | blob_reset(&secondTry); |
| @@ -132,11 +132,11 @@ | |
| 132 | */ |
| 133 | void prompt_user(const char *zPrompt, Blob *pIn){ |
| 134 | char *z; |
| 135 | char zLine[1000]; |
| 136 | blob_zero(pIn); |
| 137 | printf("%s", zPrompt); |
| 138 | fflush(stdout); |
| 139 | z = fgets(zLine, sizeof(zLine), stdin); |
| 140 | if( z ){ |
| 141 | strip_string(pIn, z); |
| 142 | } |
| @@ -204,19 +204,19 @@ | |
| 204 | }else{ |
| 205 | prompt_for_password("password: ", &passwd, 1); |
| 206 | } |
| 207 | zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0); |
| 208 | db_multi_exec( |
| 209 | "INSERT INTO user(login,pw,cap,info)" |
| 210 | "VALUES(%B,%Q,%B,%B)", |
| 211 | &login, zPw, &caps, &contact |
| 212 | ); |
| 213 | free(zPw); |
| 214 | }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){ |
| 215 | user_select(); |
| 216 | if( g.argc==3 ){ |
| 217 | printf("%s\n", g.zLogin); |
| 218 | }else{ |
| 219 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.argv[3]) ){ |
| 220 | fossil_fatal("no such user: %s", g.argv[3]); |
| 221 | } |
| 222 | if( g.localOpen ){ |
| @@ -227,11 +227,11 @@ | |
| 227 | } |
| 228 | }else if( n>=2 && strncmp(g.argv[2],"list",n)==0 ){ |
| 229 | Stmt q; |
| 230 | db_prepare(&q, "SELECT login, info FROM user ORDER BY login"); |
| 231 | while( db_step(&q)==SQLITE_ROW ){ |
| 232 | printf("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); |
| 233 | } |
| 234 | db_finalize(&q); |
| 235 | }else if( n>=2 && strncmp(g.argv[2],"password",2)==0 ){ |
| 236 | char *zPrompt; |
| 237 | int uid; |
| @@ -246,14 +246,15 @@ | |
| 246 | }else{ |
| 247 | zPrompt = mprintf("New password for %s: ", g.argv[3]); |
| 248 | prompt_for_password(zPrompt, &pw, 1); |
| 249 | } |
| 250 | if( blob_size(&pw)==0 ){ |
| 251 | printf("password unchanged\n"); |
| 252 | }else{ |
| 253 | char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); |
| 254 | db_multi_exec("UPDATE user SET pw=%Q WHERE uid=%d", zSecret, uid); |
| 255 | free(zSecret); |
| 256 | } |
| 257 | }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ |
| 258 | int uid; |
| 259 | if( g.argc!=4 && g.argc!=5 ){ |
| @@ -263,15 +264,15 @@ | |
| 263 | if( uid==0 ){ |
| 264 | fossil_fatal("no such user: %s", g.argv[3]); |
| 265 | } |
| 266 | if( g.argc==5 ){ |
| 267 | db_multi_exec( |
| 268 | "UPDATE user SET cap=%Q WHERE uid=%d", g.argv[4], |
| 269 | uid |
| 270 | ); |
| 271 | } |
| 272 | printf("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); |
| 273 | }else{ |
| 274 | fossil_panic("user subcommand should be one of: " |
| 275 | "capabilities default list new password"); |
| 276 | } |
| 277 | } |
| @@ -340,12 +341,12 @@ | |
| 340 | db_finalize(&s); |
| 341 | } |
| 342 | |
| 343 | if( g.userUid==0 ){ |
| 344 | db_multi_exec( |
| 345 | "INSERT INTO user(login, pw, cap, info)" |
| 346 | "VALUES('anonymous', '', 'cfghjkmnoqw', '')" |
| 347 | ); |
| 348 | g.userUid = db_last_insert_rowid(); |
| 349 | g.zLogin = "anonymous"; |
| 350 | } |
| 351 | } |
| @@ -364,11 +365,11 @@ | |
| 364 | if( g.argc!=3 ) usage("REPOSITORY"); |
| 365 | db_open_repository(g.argv[2]); |
| 366 | sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, |
| 367 | sha1_shared_secret_sql_function, 0, 0); |
| 368 | db_multi_exec( |
| 369 | "UPDATE user SET pw=shared_secret(pw,login)" |
| 370 | " WHERE length(pw)>0 AND length(pw)!=40" |
| 371 | ); |
| 372 | } |
| 373 | |
| 374 | /* |
| 375 |
| --- src/user.c | |
| +++ src/user.c | |
| @@ -117,11 +117,11 @@ | |
| 117 | prompt_for_passphrase(zPrompt, pPassphrase); |
| 118 | if( verify==0 ) break; |
| 119 | if( verify==1 && blob_size(pPassphrase)==0 ) break; |
| 120 | prompt_for_passphrase("Retype new password: ", &secondTry); |
| 121 | if( blob_compare(pPassphrase, &secondTry) ){ |
| 122 | fossil_print("Passphrases do not match. Try again...\n"); |
| 123 | }else{ |
| 124 | break; |
| 125 | } |
| 126 | } |
| 127 | blob_reset(&secondTry); |
| @@ -132,11 +132,11 @@ | |
| 132 | */ |
| 133 | void prompt_user(const char *zPrompt, Blob *pIn){ |
| 134 | char *z; |
| 135 | char zLine[1000]; |
| 136 | blob_zero(pIn); |
| 137 | fossil_print("%s", zPrompt); |
| 138 | fflush(stdout); |
| 139 | z = fgets(zLine, sizeof(zLine), stdin); |
| 140 | if( z ){ |
| 141 | strip_string(pIn, z); |
| 142 | } |
| @@ -204,19 +204,19 @@ | |
| 204 | }else{ |
| 205 | prompt_for_password("password: ", &passwd, 1); |
| 206 | } |
| 207 | zPw = sha1_shared_secret(blob_str(&passwd), blob_str(&login), 0); |
| 208 | db_multi_exec( |
| 209 | "INSERT INTO user(login,pw,cap,info,mtime)" |
| 210 | "VALUES(%B,%Q,%B,%B,now())", |
| 211 | &login, zPw, &caps, &contact |
| 212 | ); |
| 213 | free(zPw); |
| 214 | }else if( n>=2 && strncmp(g.argv[2],"default",n)==0 ){ |
| 215 | user_select(); |
| 216 | if( g.argc==3 ){ |
| 217 | fossil_print("%s\n", g.zLogin); |
| 218 | }else{ |
| 219 | if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.argv[3]) ){ |
| 220 | fossil_fatal("no such user: %s", g.argv[3]); |
| 221 | } |
| 222 | if( g.localOpen ){ |
| @@ -227,11 +227,11 @@ | |
| 227 | } |
| 228 | }else if( n>=2 && strncmp(g.argv[2],"list",n)==0 ){ |
| 229 | Stmt q; |
| 230 | db_prepare(&q, "SELECT login, info FROM user ORDER BY login"); |
| 231 | while( db_step(&q)==SQLITE_ROW ){ |
| 232 | fossil_print("%-12s %s\n", db_column_text(&q, 0), db_column_text(&q, 1)); |
| 233 | } |
| 234 | db_finalize(&q); |
| 235 | }else if( n>=2 && strncmp(g.argv[2],"password",2)==0 ){ |
| 236 | char *zPrompt; |
| 237 | int uid; |
| @@ -246,14 +246,15 @@ | |
| 246 | }else{ |
| 247 | zPrompt = mprintf("New password for %s: ", g.argv[3]); |
| 248 | prompt_for_password(zPrompt, &pw, 1); |
| 249 | } |
| 250 | if( blob_size(&pw)==0 ){ |
| 251 | fossil_print("password unchanged\n"); |
| 252 | }else{ |
| 253 | char *zSecret = sha1_shared_secret(blob_str(&pw), g.argv[3], 0); |
| 254 | db_multi_exec("UPDATE user SET pw=%Q, mtime=now() WHERE uid=%d", |
| 255 | zSecret, uid); |
| 256 | free(zSecret); |
| 257 | } |
| 258 | }else if( n>=2 && strncmp(g.argv[2],"capabilities",2)==0 ){ |
| 259 | int uid; |
| 260 | if( g.argc!=4 && g.argc!=5 ){ |
| @@ -263,15 +264,15 @@ | |
| 264 | if( uid==0 ){ |
| 265 | fossil_fatal("no such user: %s", g.argv[3]); |
| 266 | } |
| 267 | if( g.argc==5 ){ |
| 268 | db_multi_exec( |
| 269 | "UPDATE user SET cap=%Q, mtime=now() WHERE uid=%d", |
| 270 | g.argv[4], uid |
| 271 | ); |
| 272 | } |
| 273 | fossil_print("%s\n", db_text(0, "SELECT cap FROM user WHERE uid=%d", uid)); |
| 274 | }else{ |
| 275 | fossil_panic("user subcommand should be one of: " |
| 276 | "capabilities default list new password"); |
| 277 | } |
| 278 | } |
| @@ -340,12 +341,12 @@ | |
| 341 | db_finalize(&s); |
| 342 | } |
| 343 | |
| 344 | if( g.userUid==0 ){ |
| 345 | db_multi_exec( |
| 346 | "INSERT INTO user(login, pw, cap, info, mtime)" |
| 347 | "VALUES('anonymous', '', 'cfghjkmnoqw', '', now())" |
| 348 | ); |
| 349 | g.userUid = db_last_insert_rowid(); |
| 350 | g.zLogin = "anonymous"; |
| 351 | } |
| 352 | } |
| @@ -364,11 +365,11 @@ | |
| 365 | if( g.argc!=3 ) usage("REPOSITORY"); |
| 366 | db_open_repository(g.argv[2]); |
| 367 | sqlite3_create_function(g.db, "shared_secret", 2, SQLITE_UTF8, 0, |
| 368 | sha1_shared_secret_sql_function, 0, 0); |
| 369 | db_multi_exec( |
| 370 | "UPDATE user SET pw=shared_secret(pw,login), mtime=now()" |
| 371 | " WHERE length(pw)>0 AND length(pw)!=40" |
| 372 | ); |
| 373 | } |
| 374 | |
| 375 | /* |
| 376 |
+70
-15
| --- src/vfile.c | ||
| +++ src/vfile.c | ||
| @@ -264,11 +264,11 @@ | ||
| 264 | 264 | if( cReply=='n' || cReply=='N' ){ |
| 265 | 265 | blob_reset(&content); |
| 266 | 266 | continue; |
| 267 | 267 | } |
| 268 | 268 | } |
| 269 | - if( verbose ) printf("%s\n", &zName[nRepos]); | |
| 269 | + if( verbose ) fossil_print("%s\n", &zName[nRepos]); | |
| 270 | 270 | blob_write_to_file(&content, zName); |
| 271 | 271 | file_setexe(zName, isExe); |
| 272 | 272 | blob_reset(&content); |
| 273 | 273 | db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", |
| 274 | 274 | file_mtime(zName), id); |
| @@ -286,33 +286,76 @@ | ||
| 286 | 286 | " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid); |
| 287 | 287 | while( db_step(&q)==SQLITE_ROW ){ |
| 288 | 288 | const char *zName; |
| 289 | 289 | |
| 290 | 290 | zName = db_column_text(&q, 0); |
| 291 | - unlink(zName); | |
| 291 | + file_delete(zName); | |
| 292 | 292 | } |
| 293 | 293 | db_finalize(&q); |
| 294 | 294 | db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid); |
| 295 | 295 | } |
| 296 | + | |
| 297 | +/* | |
| 298 | +** Check to see if the directory named in zPath is the top of a checkout. | |
| 299 | +** In other words, check to see if directory pPath contains a file named | |
| 300 | +** "_FOSSIL_" or ".fos". Return true or false. | |
| 301 | +*/ | |
| 302 | +int vfile_top_of_checkout(const char *zPath){ | |
| 303 | + char *zFile; | |
| 304 | + int fileFound = 0; | |
| 305 | + | |
| 306 | + zFile = mprintf("%s/_FOSSIL_", zPath); | |
| 307 | + fileFound = file_size(zFile)>=1024; | |
| 308 | + fossil_free(zFile); | |
| 309 | + if( !fileFound ){ | |
| 310 | + zFile = mprintf("%s/.fos", zPath); | |
| 311 | + fileFound = file_size(zFile)>=1024; | |
| 312 | + fossil_free(zFile); | |
| 313 | + } | |
| 314 | + return fileFound; | |
| 315 | +} | |
| 316 | + | |
| 296 | 317 | |
| 297 | 318 | /* |
| 298 | 319 | ** Load into table SFILE the name of every ordinary file in |
| 299 | 320 | ** the directory pPath. Omit the first nPrefix characters of |
| 300 | 321 | ** of pPath when inserting into the SFILE table. |
| 301 | 322 | ** |
| 302 | 323 | ** Subdirectories are scanned recursively. |
| 303 | -** Omit files named in VFILE.vid | |
| 324 | +** Omit files named in VFILE. | |
| 325 | +** | |
| 326 | +** Files whose names begin with "." are omitted unless allFlag is true. | |
| 327 | +** | |
| 328 | +** Any files or directories that match the glob pattern pIgnore are | |
| 329 | +** excluded from the scan. Name matching occurs after the first | |
| 330 | +** nPrefix characters are elided from the filename. | |
| 304 | 331 | */ |
| 305 | -void vfile_scan(int vid, Blob *pPath, int nPrefix, int allFlag){ | |
| 332 | +void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){ | |
| 306 | 333 | DIR *d; |
| 307 | 334 | int origSize; |
| 308 | 335 | const char *zDir; |
| 309 | 336 | struct dirent *pEntry; |
| 310 | - static const char *zSql = "SELECT 1 FROM vfile " | |
| 311 | - " WHERE pathname=%Q AND NOT deleted"; | |
| 337 | + int skipAll = 0; | |
| 338 | + static Stmt ins; | |
| 339 | + static int depth = 0; | |
| 312 | 340 | |
| 313 | 341 | origSize = blob_size(pPath); |
| 342 | + if( pIgnore ){ | |
| 343 | + blob_appendf(pPath, "/"); | |
| 344 | + if( glob_match(pIgnore, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1; | |
| 345 | + blob_resize(pPath, origSize); | |
| 346 | + } | |
| 347 | + if( skipAll ) return; | |
| 348 | + | |
| 349 | + if( depth==0 ){ | |
| 350 | + db_prepare(&ins, | |
| 351 | + "INSERT OR IGNORE INTO sfile(x) SELECT :file" | |
| 352 | + " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=:file)" | |
| 353 | + ); | |
| 354 | + } | |
| 355 | + depth++; | |
| 356 | + | |
| 314 | 357 | zDir = blob_str(pPath); |
| 315 | 358 | d = opendir(zDir); |
| 316 | 359 | if( d ){ |
| 317 | 360 | while( (pEntry=readdir(d))!=0 ){ |
| 318 | 361 | char *zPath; |
| @@ -321,19 +364,30 @@ | ||
| 321 | 364 | if( pEntry->d_name[1]==0 ) continue; |
| 322 | 365 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 323 | 366 | } |
| 324 | 367 | blob_appendf(pPath, "/%s", pEntry->d_name); |
| 325 | 368 | zPath = blob_str(pPath); |
| 326 | - if( file_isdir(zPath)==1 ){ | |
| 327 | - vfile_scan(vid, pPath, nPrefix, allFlag); | |
| 328 | - }else if( file_isfile(zPath) && !db_exists(zSql, &zPath[nPrefix+1]) ){ | |
| 329 | - db_multi_exec("INSERT INTO sfile VALUES(%Q)", &zPath[nPrefix+1]); | |
| 369 | + if( glob_match(pIgnore, &zPath[nPrefix+1]) ){ | |
| 370 | + /* do nothing */ | |
| 371 | + }else if( file_isdir(zPath)==1 ){ | |
| 372 | + if( !vfile_top_of_checkout(zPath) ){ | |
| 373 | + vfile_scan(pPath, nPrefix, allFlag, pIgnore); | |
| 374 | + } | |
| 375 | + }else if( file_isfile(zPath) ){ | |
| 376 | + db_bind_text(&ins, ":file", &zPath[nPrefix+1]); | |
| 377 | + db_step(&ins); | |
| 378 | + db_reset(&ins); | |
| 330 | 379 | } |
| 331 | 380 | blob_resize(pPath, origSize); |
| 332 | 381 | } |
| 333 | 382 | closedir(d); |
| 334 | 383 | } |
| 384 | + | |
| 385 | + depth--; | |
| 386 | + if( depth==0 ){ | |
| 387 | + db_finalize(&ins); | |
| 388 | + } | |
| 335 | 389 | } |
| 336 | 390 | |
| 337 | 391 | /* |
| 338 | 392 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 339 | 393 | ** file in vid. The file names are part of the checksum. The resulting |
| @@ -374,11 +428,11 @@ | ||
| 374 | 428 | const char *zName = db_column_text(&q, 1); |
| 375 | 429 | int isSelected = db_column_int(&q, 3); |
| 376 | 430 | |
| 377 | 431 | if( isSelected ){ |
| 378 | 432 | md5sum_step_text(zName, -1); |
| 379 | - in = fopen(zFullpath,"rb"); | |
| 433 | + in = fossil_fopen(zFullpath,"rb"); | |
| 380 | 434 | if( in==0 ){ |
| 381 | 435 | md5sum_step_text(" 0\n", -1); |
| 382 | 436 | continue; |
| 383 | 437 | } |
| 384 | 438 | fseek(in, 0L, SEEK_END); |
| @@ -437,26 +491,27 @@ | ||
| 437 | 491 | int rid = db_column_int(&q, 2); |
| 438 | 492 | |
| 439 | 493 | blob_zero(&disk); |
| 440 | 494 | rc = blob_read_from_file(&disk, zFullpath); |
| 441 | 495 | if( rc<0 ){ |
| 442 | - printf("ERROR: cannot read file [%s]\n", zFullpath); | |
| 496 | + fossil_print("ERROR: cannot read file [%s]\n", zFullpath); | |
| 443 | 497 | blob_reset(&disk); |
| 444 | 498 | continue; |
| 445 | 499 | } |
| 446 | 500 | blob_zero(&repo); |
| 447 | 501 | content_get(rid, &repo); |
| 448 | 502 | if( blob_size(&repo)!=blob_size(&disk) ){ |
| 449 | - printf("ERROR: [%s] is %d bytes on disk but %d in the repository\n", | |
| 503 | + fossil_print("ERROR: [%s] is %d bytes on disk but %d in the repository\n", | |
| 450 | 504 | zName, blob_size(&disk), blob_size(&repo)); |
| 451 | 505 | blob_reset(&disk); |
| 452 | 506 | blob_reset(&repo); |
| 453 | 507 | continue; |
| 454 | 508 | } |
| 455 | 509 | if( blob_compare(&repo, &disk) ){ |
| 456 | - printf("ERROR: [%s] is different on disk compared to the repository\n", | |
| 457 | - zName); | |
| 510 | + fossil_print( | |
| 511 | + "ERROR: [%s] is different on disk compared to the repository\n", | |
| 512 | + zName); | |
| 458 | 513 | } |
| 459 | 514 | blob_reset(&disk); |
| 460 | 515 | blob_reset(&repo); |
| 461 | 516 | } |
| 462 | 517 | db_finalize(&q); |
| 463 | 518 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -264,11 +264,11 @@ | |
| 264 | if( cReply=='n' || cReply=='N' ){ |
| 265 | blob_reset(&content); |
| 266 | continue; |
| 267 | } |
| 268 | } |
| 269 | if( verbose ) printf("%s\n", &zName[nRepos]); |
| 270 | blob_write_to_file(&content, zName); |
| 271 | file_setexe(zName, isExe); |
| 272 | blob_reset(&content); |
| 273 | db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", |
| 274 | file_mtime(zName), id); |
| @@ -286,33 +286,76 @@ | |
| 286 | " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid); |
| 287 | while( db_step(&q)==SQLITE_ROW ){ |
| 288 | const char *zName; |
| 289 | |
| 290 | zName = db_column_text(&q, 0); |
| 291 | unlink(zName); |
| 292 | } |
| 293 | db_finalize(&q); |
| 294 | db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid); |
| 295 | } |
| 296 | |
| 297 | /* |
| 298 | ** Load into table SFILE the name of every ordinary file in |
| 299 | ** the directory pPath. Omit the first nPrefix characters of |
| 300 | ** of pPath when inserting into the SFILE table. |
| 301 | ** |
| 302 | ** Subdirectories are scanned recursively. |
| 303 | ** Omit files named in VFILE.vid |
| 304 | */ |
| 305 | void vfile_scan(int vid, Blob *pPath, int nPrefix, int allFlag){ |
| 306 | DIR *d; |
| 307 | int origSize; |
| 308 | const char *zDir; |
| 309 | struct dirent *pEntry; |
| 310 | static const char *zSql = "SELECT 1 FROM vfile " |
| 311 | " WHERE pathname=%Q AND NOT deleted"; |
| 312 | |
| 313 | origSize = blob_size(pPath); |
| 314 | zDir = blob_str(pPath); |
| 315 | d = opendir(zDir); |
| 316 | if( d ){ |
| 317 | while( (pEntry=readdir(d))!=0 ){ |
| 318 | char *zPath; |
| @@ -321,19 +364,30 @@ | |
| 321 | if( pEntry->d_name[1]==0 ) continue; |
| 322 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 323 | } |
| 324 | blob_appendf(pPath, "/%s", pEntry->d_name); |
| 325 | zPath = blob_str(pPath); |
| 326 | if( file_isdir(zPath)==1 ){ |
| 327 | vfile_scan(vid, pPath, nPrefix, allFlag); |
| 328 | }else if( file_isfile(zPath) && !db_exists(zSql, &zPath[nPrefix+1]) ){ |
| 329 | db_multi_exec("INSERT INTO sfile VALUES(%Q)", &zPath[nPrefix+1]); |
| 330 | } |
| 331 | blob_resize(pPath, origSize); |
| 332 | } |
| 333 | closedir(d); |
| 334 | } |
| 335 | } |
| 336 | |
| 337 | /* |
| 338 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 339 | ** file in vid. The file names are part of the checksum. The resulting |
| @@ -374,11 +428,11 @@ | |
| 374 | const char *zName = db_column_text(&q, 1); |
| 375 | int isSelected = db_column_int(&q, 3); |
| 376 | |
| 377 | if( isSelected ){ |
| 378 | md5sum_step_text(zName, -1); |
| 379 | in = fopen(zFullpath,"rb"); |
| 380 | if( in==0 ){ |
| 381 | md5sum_step_text(" 0\n", -1); |
| 382 | continue; |
| 383 | } |
| 384 | fseek(in, 0L, SEEK_END); |
| @@ -437,26 +491,27 @@ | |
| 437 | int rid = db_column_int(&q, 2); |
| 438 | |
| 439 | blob_zero(&disk); |
| 440 | rc = blob_read_from_file(&disk, zFullpath); |
| 441 | if( rc<0 ){ |
| 442 | printf("ERROR: cannot read file [%s]\n", zFullpath); |
| 443 | blob_reset(&disk); |
| 444 | continue; |
| 445 | } |
| 446 | blob_zero(&repo); |
| 447 | content_get(rid, &repo); |
| 448 | if( blob_size(&repo)!=blob_size(&disk) ){ |
| 449 | printf("ERROR: [%s] is %d bytes on disk but %d in the repository\n", |
| 450 | zName, blob_size(&disk), blob_size(&repo)); |
| 451 | blob_reset(&disk); |
| 452 | blob_reset(&repo); |
| 453 | continue; |
| 454 | } |
| 455 | if( blob_compare(&repo, &disk) ){ |
| 456 | printf("ERROR: [%s] is different on disk compared to the repository\n", |
| 457 | zName); |
| 458 | } |
| 459 | blob_reset(&disk); |
| 460 | blob_reset(&repo); |
| 461 | } |
| 462 | db_finalize(&q); |
| 463 |
| --- src/vfile.c | |
| +++ src/vfile.c | |
| @@ -264,11 +264,11 @@ | |
| 264 | if( cReply=='n' || cReply=='N' ){ |
| 265 | blob_reset(&content); |
| 266 | continue; |
| 267 | } |
| 268 | } |
| 269 | if( verbose ) fossil_print("%s\n", &zName[nRepos]); |
| 270 | blob_write_to_file(&content, zName); |
| 271 | file_setexe(zName, isExe); |
| 272 | blob_reset(&content); |
| 273 | db_multi_exec("UPDATE vfile SET mtime=%lld WHERE id=%d", |
| 274 | file_mtime(zName), id); |
| @@ -286,33 +286,76 @@ | |
| 286 | " WHERE vid=%d AND mrid>0", g.zLocalRoot, vid); |
| 287 | while( db_step(&q)==SQLITE_ROW ){ |
| 288 | const char *zName; |
| 289 | |
| 290 | zName = db_column_text(&q, 0); |
| 291 | file_delete(zName); |
| 292 | } |
| 293 | db_finalize(&q); |
| 294 | db_multi_exec("UPDATE vfile SET mtime=NULL WHERE vid=%d AND mrid>0", vid); |
| 295 | } |
| 296 | |
| 297 | /* |
| 298 | ** Check to see if the directory named in zPath is the top of a checkout. |
| 299 | ** In other words, check to see if directory pPath contains a file named |
| 300 | ** "_FOSSIL_" or ".fos". Return true or false. |
| 301 | */ |
| 302 | int vfile_top_of_checkout(const char *zPath){ |
| 303 | char *zFile; |
| 304 | int fileFound = 0; |
| 305 | |
| 306 | zFile = mprintf("%s/_FOSSIL_", zPath); |
| 307 | fileFound = file_size(zFile)>=1024; |
| 308 | fossil_free(zFile); |
| 309 | if( !fileFound ){ |
| 310 | zFile = mprintf("%s/.fos", zPath); |
| 311 | fileFound = file_size(zFile)>=1024; |
| 312 | fossil_free(zFile); |
| 313 | } |
| 314 | return fileFound; |
| 315 | } |
| 316 | |
| 317 | |
| 318 | /* |
| 319 | ** Load into table SFILE the name of every ordinary file in |
| 320 | ** the directory pPath. Omit the first nPrefix characters of |
| 321 | ** of pPath when inserting into the SFILE table. |
| 322 | ** |
| 323 | ** Subdirectories are scanned recursively. |
| 324 | ** Omit files named in VFILE. |
| 325 | ** |
| 326 | ** Files whose names begin with "." are omitted unless allFlag is true. |
| 327 | ** |
| 328 | ** Any files or directories that match the glob pattern pIgnore are |
| 329 | ** excluded from the scan. Name matching occurs after the first |
| 330 | ** nPrefix characters are elided from the filename. |
| 331 | */ |
| 332 | void vfile_scan(Blob *pPath, int nPrefix, int allFlag, Glob *pIgnore){ |
| 333 | DIR *d; |
| 334 | int origSize; |
| 335 | const char *zDir; |
| 336 | struct dirent *pEntry; |
| 337 | int skipAll = 0; |
| 338 | static Stmt ins; |
| 339 | static int depth = 0; |
| 340 | |
| 341 | origSize = blob_size(pPath); |
| 342 | if( pIgnore ){ |
| 343 | blob_appendf(pPath, "/"); |
| 344 | if( glob_match(pIgnore, &blob_str(pPath)[nPrefix+1]) ) skipAll = 1; |
| 345 | blob_resize(pPath, origSize); |
| 346 | } |
| 347 | if( skipAll ) return; |
| 348 | |
| 349 | if( depth==0 ){ |
| 350 | db_prepare(&ins, |
| 351 | "INSERT OR IGNORE INTO sfile(x) SELECT :file" |
| 352 | " WHERE NOT EXISTS(SELECT 1 FROM vfile WHERE pathname=:file)" |
| 353 | ); |
| 354 | } |
| 355 | depth++; |
| 356 | |
| 357 | zDir = blob_str(pPath); |
| 358 | d = opendir(zDir); |
| 359 | if( d ){ |
| 360 | while( (pEntry=readdir(d))!=0 ){ |
| 361 | char *zPath; |
| @@ -321,19 +364,30 @@ | |
| 364 | if( pEntry->d_name[1]==0 ) continue; |
| 365 | if( pEntry->d_name[1]=='.' && pEntry->d_name[2]==0 ) continue; |
| 366 | } |
| 367 | blob_appendf(pPath, "/%s", pEntry->d_name); |
| 368 | zPath = blob_str(pPath); |
| 369 | if( glob_match(pIgnore, &zPath[nPrefix+1]) ){ |
| 370 | /* do nothing */ |
| 371 | }else if( file_isdir(zPath)==1 ){ |
| 372 | if( !vfile_top_of_checkout(zPath) ){ |
| 373 | vfile_scan(pPath, nPrefix, allFlag, pIgnore); |
| 374 | } |
| 375 | }else if( file_isfile(zPath) ){ |
| 376 | db_bind_text(&ins, ":file", &zPath[nPrefix+1]); |
| 377 | db_step(&ins); |
| 378 | db_reset(&ins); |
| 379 | } |
| 380 | blob_resize(pPath, origSize); |
| 381 | } |
| 382 | closedir(d); |
| 383 | } |
| 384 | |
| 385 | depth--; |
| 386 | if( depth==0 ){ |
| 387 | db_finalize(&ins); |
| 388 | } |
| 389 | } |
| 390 | |
| 391 | /* |
| 392 | ** Compute an aggregate MD5 checksum over the disk image of every |
| 393 | ** file in vid. The file names are part of the checksum. The resulting |
| @@ -374,11 +428,11 @@ | |
| 428 | const char *zName = db_column_text(&q, 1); |
| 429 | int isSelected = db_column_int(&q, 3); |
| 430 | |
| 431 | if( isSelected ){ |
| 432 | md5sum_step_text(zName, -1); |
| 433 | in = fossil_fopen(zFullpath,"rb"); |
| 434 | if( in==0 ){ |
| 435 | md5sum_step_text(" 0\n", -1); |
| 436 | continue; |
| 437 | } |
| 438 | fseek(in, 0L, SEEK_END); |
| @@ -437,26 +491,27 @@ | |
| 491 | int rid = db_column_int(&q, 2); |
| 492 | |
| 493 | blob_zero(&disk); |
| 494 | rc = blob_read_from_file(&disk, zFullpath); |
| 495 | if( rc<0 ){ |
| 496 | fossil_print("ERROR: cannot read file [%s]\n", zFullpath); |
| 497 | blob_reset(&disk); |
| 498 | continue; |
| 499 | } |
| 500 | blob_zero(&repo); |
| 501 | content_get(rid, &repo); |
| 502 | if( blob_size(&repo)!=blob_size(&disk) ){ |
| 503 | fossil_print("ERROR: [%s] is %d bytes on disk but %d in the repository\n", |
| 504 | zName, blob_size(&disk), blob_size(&repo)); |
| 505 | blob_reset(&disk); |
| 506 | blob_reset(&repo); |
| 507 | continue; |
| 508 | } |
| 509 | if( blob_compare(&repo, &disk) ){ |
| 510 | fossil_print( |
| 511 | "ERROR: [%s] is different on disk compared to the repository\n", |
| 512 | zName); |
| 513 | } |
| 514 | blob_reset(&disk); |
| 515 | blob_reset(&repo); |
| 516 | } |
| 517 | db_finalize(&q); |
| 518 |
+5
-5
| --- src/wiki.c | ||
| +++ src/wiki.c | ||
| @@ -916,20 +916,20 @@ | ||
| 916 | 916 | FILE * zF; |
| 917 | 917 | short doClose = 0; |
| 918 | 918 | if( (1 == strlen(zFile)) && ('-'==zFile[0]) ){ |
| 919 | 919 | zF = stdout; |
| 920 | 920 | }else{ |
| 921 | - zF = fopen( zFile, "w" ); | |
| 921 | + zF = fossil_fopen( zFile, "w" ); | |
| 922 | 922 | doClose = zF ? 1 : 0; |
| 923 | 923 | } |
| 924 | 924 | if( ! zF ){ |
| 925 | 925 | fossil_fatal("wiki export could not open output file for writing."); |
| 926 | 926 | } |
| 927 | 927 | fprintf(zF,"%.*s\n", i, zBody); |
| 928 | 928 | if( doClose ) fclose(zF); |
| 929 | 929 | }else{ |
| 930 | - printf("%.*s\n", i, zBody); | |
| 930 | + fossil_print("%.*s\n", i, zBody); | |
| 931 | 931 | } |
| 932 | 932 | manifest_destroy(pWiki); |
| 933 | 933 | return; |
| 934 | 934 | }else |
| 935 | 935 | if( strncmp(g.argv[2],"commit",n)==0 |
| @@ -945,14 +945,14 @@ | ||
| 945 | 945 | }else{ |
| 946 | 946 | blob_read_from_file(&content, g.argv[4]); |
| 947 | 947 | } |
| 948 | 948 | if( g.argv[2][1]=='r' ){ |
| 949 | 949 | wiki_cmd_commit(zPageName, 1, &content); |
| 950 | - printf("Created new wiki page %s.\n", zPageName); | |
| 950 | + fossil_print("Created new wiki page %s.\n", zPageName); | |
| 951 | 951 | }else{ |
| 952 | 952 | wiki_cmd_commit(zPageName, 0, &content); |
| 953 | - printf("Updated wiki page %s.\n", zPageName); | |
| 953 | + fossil_print("Updated wiki page %s.\n", zPageName); | |
| 954 | 954 | } |
| 955 | 955 | blob_reset(&content); |
| 956 | 956 | }else |
| 957 | 957 | if( strncmp(g.argv[2],"delete",n)==0 ){ |
| 958 | 958 | if( g.argc!=5 ){ |
| @@ -966,11 +966,11 @@ | ||
| 966 | 966 | "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" |
| 967 | 967 | " ORDER BY lower(tagname) /*sort*/" |
| 968 | 968 | ); |
| 969 | 969 | while( db_step(&q)==SQLITE_ROW ){ |
| 970 | 970 | const char *zName = db_column_text(&q, 0); |
| 971 | - printf( "%s\n",zName); | |
| 971 | + fossil_print( "%s\n",zName); | |
| 972 | 972 | } |
| 973 | 973 | db_finalize(&q); |
| 974 | 974 | }else |
| 975 | 975 | { |
| 976 | 976 | goto wiki_cmd_usage; |
| 977 | 977 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -916,20 +916,20 @@ | |
| 916 | FILE * zF; |
| 917 | short doClose = 0; |
| 918 | if( (1 == strlen(zFile)) && ('-'==zFile[0]) ){ |
| 919 | zF = stdout; |
| 920 | }else{ |
| 921 | zF = fopen( zFile, "w" ); |
| 922 | doClose = zF ? 1 : 0; |
| 923 | } |
| 924 | if( ! zF ){ |
| 925 | fossil_fatal("wiki export could not open output file for writing."); |
| 926 | } |
| 927 | fprintf(zF,"%.*s\n", i, zBody); |
| 928 | if( doClose ) fclose(zF); |
| 929 | }else{ |
| 930 | printf("%.*s\n", i, zBody); |
| 931 | } |
| 932 | manifest_destroy(pWiki); |
| 933 | return; |
| 934 | }else |
| 935 | if( strncmp(g.argv[2],"commit",n)==0 |
| @@ -945,14 +945,14 @@ | |
| 945 | }else{ |
| 946 | blob_read_from_file(&content, g.argv[4]); |
| 947 | } |
| 948 | if( g.argv[2][1]=='r' ){ |
| 949 | wiki_cmd_commit(zPageName, 1, &content); |
| 950 | printf("Created new wiki page %s.\n", zPageName); |
| 951 | }else{ |
| 952 | wiki_cmd_commit(zPageName, 0, &content); |
| 953 | printf("Updated wiki page %s.\n", zPageName); |
| 954 | } |
| 955 | blob_reset(&content); |
| 956 | }else |
| 957 | if( strncmp(g.argv[2],"delete",n)==0 ){ |
| 958 | if( g.argc!=5 ){ |
| @@ -966,11 +966,11 @@ | |
| 966 | "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" |
| 967 | " ORDER BY lower(tagname) /*sort*/" |
| 968 | ); |
| 969 | while( db_step(&q)==SQLITE_ROW ){ |
| 970 | const char *zName = db_column_text(&q, 0); |
| 971 | printf( "%s\n",zName); |
| 972 | } |
| 973 | db_finalize(&q); |
| 974 | }else |
| 975 | { |
| 976 | goto wiki_cmd_usage; |
| 977 |
| --- src/wiki.c | |
| +++ src/wiki.c | |
| @@ -916,20 +916,20 @@ | |
| 916 | FILE * zF; |
| 917 | short doClose = 0; |
| 918 | if( (1 == strlen(zFile)) && ('-'==zFile[0]) ){ |
| 919 | zF = stdout; |
| 920 | }else{ |
| 921 | zF = fossil_fopen( zFile, "w" ); |
| 922 | doClose = zF ? 1 : 0; |
| 923 | } |
| 924 | if( ! zF ){ |
| 925 | fossil_fatal("wiki export could not open output file for writing."); |
| 926 | } |
| 927 | fprintf(zF,"%.*s\n", i, zBody); |
| 928 | if( doClose ) fclose(zF); |
| 929 | }else{ |
| 930 | fossil_print("%.*s\n", i, zBody); |
| 931 | } |
| 932 | manifest_destroy(pWiki); |
| 933 | return; |
| 934 | }else |
| 935 | if( strncmp(g.argv[2],"commit",n)==0 |
| @@ -945,14 +945,14 @@ | |
| 945 | }else{ |
| 946 | blob_read_from_file(&content, g.argv[4]); |
| 947 | } |
| 948 | if( g.argv[2][1]=='r' ){ |
| 949 | wiki_cmd_commit(zPageName, 1, &content); |
| 950 | fossil_print("Created new wiki page %s.\n", zPageName); |
| 951 | }else{ |
| 952 | wiki_cmd_commit(zPageName, 0, &content); |
| 953 | fossil_print("Updated wiki page %s.\n", zPageName); |
| 954 | } |
| 955 | blob_reset(&content); |
| 956 | }else |
| 957 | if( strncmp(g.argv[2],"delete",n)==0 ){ |
| 958 | if( g.argc!=5 ){ |
| @@ -966,11 +966,11 @@ | |
| 966 | "SELECT substr(tagname, 6) FROM tag WHERE tagname GLOB 'wiki-*'" |
| 967 | " ORDER BY lower(tagname) /*sort*/" |
| 968 | ); |
| 969 | while( db_step(&q)==SQLITE_ROW ){ |
| 970 | const char *zName = db_column_text(&q, 0); |
| 971 | fossil_print( "%s\n",zName); |
| 972 | } |
| 973 | db_finalize(&q); |
| 974 | }else |
| 975 | { |
| 976 | goto wiki_cmd_usage; |
| 977 |
+1
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -1734,6 +1734,7 @@ | ||
| 1734 | 1734 | break; |
| 1735 | 1735 | } |
| 1736 | 1736 | } |
| 1737 | 1737 | z += n; |
| 1738 | 1738 | } |
| 1739 | + free(renderer.aStack); | |
| 1739 | 1740 | } |
| 1740 | 1741 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1734,6 +1734,7 @@ | |
| 1734 | break; |
| 1735 | } |
| 1736 | } |
| 1737 | z += n; |
| 1738 | } |
| 1739 | } |
| 1740 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1734,6 +1734,7 @@ | |
| 1734 | break; |
| 1735 | } |
| 1736 | } |
| 1737 | z += n; |
| 1738 | } |
| 1739 | free(renderer.aStack); |
| 1740 | } |
| 1741 |
+8
-8
| --- src/winhttp.c | ||
| +++ src/winhttp.c | ||
| @@ -92,11 +92,11 @@ | ||
| 92 | 92 | wanted = find_content_length(zHdr) + (&z[4]-zHdr) - amt; |
| 93 | 93 | break; |
| 94 | 94 | } |
| 95 | 95 | } |
| 96 | 96 | if( amt>=sizeof(zHdr) ) goto end_request; |
| 97 | - out = fopen(zRequestFName, "wb"); | |
| 97 | + out = fossil_fopen(zRequestFName, "wb"); | |
| 98 | 98 | if( out==0 ) goto end_request; |
| 99 | 99 | fwrite(zHdr, 1, amt, out); |
| 100 | 100 | while( wanted>0 ){ |
| 101 | 101 | got = recv(p->s, zHdr, sizeof(zHdr), 0); |
| 102 | 102 | if( got==SOCKET_ERROR ) goto end_request; |
| @@ -112,11 +112,11 @@ | ||
| 112 | 112 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 113 | 113 | fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, |
| 114 | 114 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 115 | 115 | ); |
| 116 | 116 | fossil_system(zCmd); |
| 117 | - in = fopen(zReplyFName, "rb"); | |
| 117 | + in = fossil_fopen(zReplyFName, "rb"); | |
| 118 | 118 | if( in ){ |
| 119 | 119 | while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ |
| 120 | 120 | send(p->s, zHdr, got, 0); |
| 121 | 121 | } |
| 122 | 122 | } |
| @@ -123,12 +123,12 @@ | ||
| 123 | 123 | |
| 124 | 124 | end_request: |
| 125 | 125 | if( out ) fclose(out); |
| 126 | 126 | if( in ) fclose(in); |
| 127 | 127 | closesocket(p->s); |
| 128 | - unlink(zRequestFName); | |
| 129 | - unlink(zReplyFName); | |
| 128 | + file_delete(zRequestFName); | |
| 129 | + file_delete(zReplyFName); | |
| 130 | 130 | free(p); |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | /* |
| 134 | 134 | ** Start a listening socket and process incoming HTTP requests on |
| @@ -146,11 +146,11 @@ | ||
| 146 | 146 | SOCKADDR_IN addr; |
| 147 | 147 | int idCnt = 0; |
| 148 | 148 | int iPort = mnPort; |
| 149 | 149 | Blob options; |
| 150 | 150 | |
| 151 | - if( zStopper ) unlink(zStopper); | |
| 151 | + if( zStopper ) file_delete(zStopper); | |
| 152 | 152 | blob_zero(&options); |
| 153 | 153 | if( zNotFound ){ |
| 154 | 154 | blob_appendf(&options, " --notfound %s", zNotFound); |
| 155 | 155 | } |
| 156 | 156 | if( g.useLocalauth ){ |
| @@ -190,17 +190,17 @@ | ||
| 190 | 190 | fossil_fatal("unable to open listening socket on any" |
| 191 | 191 | " port in the range %d..%d", mnPort, mxPort); |
| 192 | 192 | } |
| 193 | 193 | } |
| 194 | 194 | zTempPrefix = mprintf("fossil_server_P%d_", iPort); |
| 195 | - printf("Listening for HTTP requests on TCP port %d\n", iPort); | |
| 195 | + fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); | |
| 196 | 196 | if( zBrowser ){ |
| 197 | 197 | zBrowser = mprintf(zBrowser, iPort); |
| 198 | - printf("Launch webbrowser: %s\n", zBrowser); | |
| 198 | + fossil_print("Launch webbrowser: %s\n", zBrowser); | |
| 199 | 199 | fossil_system(zBrowser); |
| 200 | 200 | } |
| 201 | - printf("Type Ctrl-C to stop the HTTP server\n"); | |
| 201 | + fossil_print("Type Ctrl-C to stop the HTTP server\n"); | |
| 202 | 202 | for(;;){ |
| 203 | 203 | SOCKET client; |
| 204 | 204 | SOCKADDR_IN client_addr; |
| 205 | 205 | HttpRequest *p; |
| 206 | 206 | int len = sizeof(client_addr); |
| 207 | 207 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -92,11 +92,11 @@ | |
| 92 | wanted = find_content_length(zHdr) + (&z[4]-zHdr) - amt; |
| 93 | break; |
| 94 | } |
| 95 | } |
| 96 | if( amt>=sizeof(zHdr) ) goto end_request; |
| 97 | out = fopen(zRequestFName, "wb"); |
| 98 | if( out==0 ) goto end_request; |
| 99 | fwrite(zHdr, 1, amt, out); |
| 100 | while( wanted>0 ){ |
| 101 | got = recv(p->s, zHdr, sizeof(zHdr), 0); |
| 102 | if( got==SOCKET_ERROR ) goto end_request; |
| @@ -112,11 +112,11 @@ | |
| 112 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 113 | fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, |
| 114 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 115 | ); |
| 116 | fossil_system(zCmd); |
| 117 | in = fopen(zReplyFName, "rb"); |
| 118 | if( in ){ |
| 119 | while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ |
| 120 | send(p->s, zHdr, got, 0); |
| 121 | } |
| 122 | } |
| @@ -123,12 +123,12 @@ | |
| 123 | |
| 124 | end_request: |
| 125 | if( out ) fclose(out); |
| 126 | if( in ) fclose(in); |
| 127 | closesocket(p->s); |
| 128 | unlink(zRequestFName); |
| 129 | unlink(zReplyFName); |
| 130 | free(p); |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Start a listening socket and process incoming HTTP requests on |
| @@ -146,11 +146,11 @@ | |
| 146 | SOCKADDR_IN addr; |
| 147 | int idCnt = 0; |
| 148 | int iPort = mnPort; |
| 149 | Blob options; |
| 150 | |
| 151 | if( zStopper ) unlink(zStopper); |
| 152 | blob_zero(&options); |
| 153 | if( zNotFound ){ |
| 154 | blob_appendf(&options, " --notfound %s", zNotFound); |
| 155 | } |
| 156 | if( g.useLocalauth ){ |
| @@ -190,17 +190,17 @@ | |
| 190 | fossil_fatal("unable to open listening socket on any" |
| 191 | " port in the range %d..%d", mnPort, mxPort); |
| 192 | } |
| 193 | } |
| 194 | zTempPrefix = mprintf("fossil_server_P%d_", iPort); |
| 195 | printf("Listening for HTTP requests on TCP port %d\n", iPort); |
| 196 | if( zBrowser ){ |
| 197 | zBrowser = mprintf(zBrowser, iPort); |
| 198 | printf("Launch webbrowser: %s\n", zBrowser); |
| 199 | fossil_system(zBrowser); |
| 200 | } |
| 201 | printf("Type Ctrl-C to stop the HTTP server\n"); |
| 202 | for(;;){ |
| 203 | SOCKET client; |
| 204 | SOCKADDR_IN client_addr; |
| 205 | HttpRequest *p; |
| 206 | int len = sizeof(client_addr); |
| 207 |
| --- src/winhttp.c | |
| +++ src/winhttp.c | |
| @@ -92,11 +92,11 @@ | |
| 92 | wanted = find_content_length(zHdr) + (&z[4]-zHdr) - amt; |
| 93 | break; |
| 94 | } |
| 95 | } |
| 96 | if( amt>=sizeof(zHdr) ) goto end_request; |
| 97 | out = fossil_fopen(zRequestFName, "wb"); |
| 98 | if( out==0 ) goto end_request; |
| 99 | fwrite(zHdr, 1, amt, out); |
| 100 | while( wanted>0 ){ |
| 101 | got = recv(p->s, zHdr, sizeof(zHdr), 0); |
| 102 | if( got==SOCKET_ERROR ) goto end_request; |
| @@ -112,11 +112,11 @@ | |
| 112 | sqlite3_snprintf(sizeof(zCmd), zCmd, "\"%s\" http \"%s\" %s %s %s --nossl%s", |
| 113 | fossil_nameofexe(), g.zRepositoryName, zRequestFName, zReplyFName, |
| 114 | inet_ntoa(p->addr.sin_addr), p->zOptions |
| 115 | ); |
| 116 | fossil_system(zCmd); |
| 117 | in = fossil_fopen(zReplyFName, "rb"); |
| 118 | if( in ){ |
| 119 | while( (got = fread(zHdr, 1, sizeof(zHdr), in))>0 ){ |
| 120 | send(p->s, zHdr, got, 0); |
| 121 | } |
| 122 | } |
| @@ -123,12 +123,12 @@ | |
| 123 | |
| 124 | end_request: |
| 125 | if( out ) fclose(out); |
| 126 | if( in ) fclose(in); |
| 127 | closesocket(p->s); |
| 128 | file_delete(zRequestFName); |
| 129 | file_delete(zReplyFName); |
| 130 | free(p); |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Start a listening socket and process incoming HTTP requests on |
| @@ -146,11 +146,11 @@ | |
| 146 | SOCKADDR_IN addr; |
| 147 | int idCnt = 0; |
| 148 | int iPort = mnPort; |
| 149 | Blob options; |
| 150 | |
| 151 | if( zStopper ) file_delete(zStopper); |
| 152 | blob_zero(&options); |
| 153 | if( zNotFound ){ |
| 154 | blob_appendf(&options, " --notfound %s", zNotFound); |
| 155 | } |
| 156 | if( g.useLocalauth ){ |
| @@ -190,17 +190,17 @@ | |
| 190 | fossil_fatal("unable to open listening socket on any" |
| 191 | " port in the range %d..%d", mnPort, mxPort); |
| 192 | } |
| 193 | } |
| 194 | zTempPrefix = mprintf("fossil_server_P%d_", iPort); |
| 195 | fossil_print("Listening for HTTP requests on TCP port %d\n", iPort); |
| 196 | if( zBrowser ){ |
| 197 | zBrowser = mprintf(zBrowser, iPort); |
| 198 | fossil_print("Launch webbrowser: %s\n", zBrowser); |
| 199 | fossil_system(zBrowser); |
| 200 | } |
| 201 | fossil_print("Type Ctrl-C to stop the HTTP server\n"); |
| 202 | for(;;){ |
| 203 | SOCKET client; |
| 204 | SOCKADDR_IN client_addr; |
| 205 | HttpRequest *p; |
| 206 | int len = sizeof(client_addr); |
| 207 |
+53
-75
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -454,11 +454,11 @@ | ||
| 454 | 454 | " (SELECT uuid FROM delta, blob" |
| 455 | 455 | " WHERE delta.rid=:rid AND delta.srcid=blob.rid)" |
| 456 | 456 | " FROM blob" |
| 457 | 457 | " WHERE rid=:rid" |
| 458 | 458 | " AND size>=0" |
| 459 | - " AND uuid NOT IN shun" | |
| 459 | + " AND NOT EXISTS(SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)" | |
| 460 | 460 | ); |
| 461 | 461 | db_bind_int(&q1, ":rid", rid); |
| 462 | 462 | rc = db_step(&q1); |
| 463 | 463 | if( rc==SQLITE_ROW ){ |
| 464 | 464 | zUuid = db_column_text(&q1, 0); |
| @@ -552,10 +552,13 @@ | ||
| 552 | 552 | defossilize(zLogin); |
| 553 | 553 | |
| 554 | 554 | if( strcmp(zLogin, "nobody")==0 || strcmp(zLogin,"anonymous")==0 ){ |
| 555 | 555 | return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */ |
| 556 | 556 | } |
| 557 | + if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 ){ | |
| 558 | + return 0; /* Accept Basic Authorization */ | |
| 559 | + } | |
| 557 | 560 | db_prepare(&q, |
| 558 | 561 | "SELECT pw, cap, uid FROM user" |
| 559 | 562 | " WHERE login=%Q" |
| 560 | 563 | " AND login NOT IN ('anonymous','nobody','developer','reader')" |
| 561 | 564 | " AND length(pw)>0", |
| @@ -592,11 +595,11 @@ | ||
| 592 | 595 | blob_reset(&combined); |
| 593 | 596 | } |
| 594 | 597 | if( rc==0 ){ |
| 595 | 598 | const char *zCap; |
| 596 | 599 | zCap = db_column_text(&q, 1); |
| 597 | - login_set_capabilities(zCap); | |
| 600 | + login_set_capabilities(zCap, 0); | |
| 598 | 601 | g.userUid = db_column_int(&q, 2); |
| 599 | 602 | g.zLogin = mprintf("%b", pLogin); |
| 600 | 603 | g.zNonce = mprintf("%b", pNonce); |
| 601 | 604 | } |
| 602 | 605 | } |
| @@ -738,13 +741,16 @@ | ||
| 738 | 741 | } |
| 739 | 742 | db_finalize(&q); |
| 740 | 743 | } |
| 741 | 744 | |
| 742 | 745 | /* |
| 743 | -** Send a single config card for configuration item zName | |
| 746 | +** Send a single old-style config card for configuration item zName. | |
| 747 | +** | |
| 748 | +** This routine and the functionality it implements is scheduled for | |
| 749 | +** removal on 2012-05-01. | |
| 744 | 750 | */ |
| 745 | -static void send_config_card(Xfer *pXfer, const char *zName){ | |
| 751 | +static void send_legacy_config_card(Xfer *pXfer, const char *zName){ | |
| 746 | 752 | if( zName[0]!='@' ){ |
| 747 | 753 | Blob val; |
| 748 | 754 | blob_zero(&val); |
| 749 | 755 | db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName); |
| 750 | 756 | if( blob_size(&val)>0 ){ |
| @@ -760,11 +766,10 @@ | ||
| 760 | 766 | blob_appendf(pXfer->pOut, "config %s %d\n%s\n", zName, |
| 761 | 767 | blob_size(&content), blob_str(&content)); |
| 762 | 768 | blob_reset(&content); |
| 763 | 769 | } |
| 764 | 770 | } |
| 765 | - | |
| 766 | 771 | |
| 767 | 772 | /* |
| 768 | 773 | ** Called when there is an attempt to transfer private content to and |
| 769 | 774 | ** from a server without authorization. |
| 770 | 775 | */ |
| @@ -807,10 +812,11 @@ | ||
| 807 | 812 | if( strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 808 | 813 | fossil_redirect_home(); |
| 809 | 814 | } |
| 810 | 815 | g.zLogin = "anonymous"; |
| 811 | 816 | login_set_anon_nobody_capabilities(); |
| 817 | + login_check_credentials(); | |
| 812 | 818 | memset(&xfer, 0, sizeof(xfer)); |
| 813 | 819 | blobarray_zero(xfer.aToken, count(xfer.aToken)); |
| 814 | 820 | cgi_set_content_type(g.zContentType); |
| 815 | 821 | if( db_schema_is_outofdate() ){ |
| 816 | 822 | @ error database\sschema\sis\sout-of-date\son\sthe\sserver. |
| @@ -1007,11 +1013,11 @@ | ||
| 1007 | 1013 | */ |
| 1008 | 1014 | if( blob_eq(&xfer.aToken[0], "login") |
| 1009 | 1015 | && xfer.nToken==4 |
| 1010 | 1016 | ){ |
| 1011 | 1017 | if( disableLogin ){ |
| 1012 | - g.okRead = g.okWrite = g.okPrivate = 1; | |
| 1018 | + g.okRead = g.okWrite = g.okPrivate = g.okAdmin = 1; | |
| 1013 | 1019 | }else{ |
| 1014 | 1020 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) |
| 1015 | 1021 | || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) |
| 1016 | 1022 | ){ |
| 1017 | 1023 | cgi_reset_content(); |
| @@ -1029,12 +1035,19 @@ | ||
| 1029 | 1035 | if( blob_eq(&xfer.aToken[0], "reqconfig") |
| 1030 | 1036 | && xfer.nToken==2 |
| 1031 | 1037 | ){ |
| 1032 | 1038 | if( g.okRead ){ |
| 1033 | 1039 | char *zName = blob_str(&xfer.aToken[1]); |
| 1034 | - if( configure_is_exportable(zName) ){ | |
| 1035 | - send_config_card(&xfer, zName); | |
| 1040 | + if( zName[0]=='/' ){ | |
| 1041 | + /* New style configuration transfer */ | |
| 1042 | + int groupMask = configure_name_to_mask(&zName[1], 0); | |
| 1043 | + if( !g.okAdmin ) groupMask &= ~CONFIGSET_USER; | |
| 1044 | + if( !g.okRdAddr ) groupMask &= ~CONFIGSET_ADDR; | |
| 1045 | + configure_send_group(xfer.pOut, groupMask, 0); | |
| 1046 | + }else if( configure_is_exportable(zName) ){ | |
| 1047 | + /* Old style configuration transfer */ | |
| 1048 | + send_legacy_config_card(&xfer, zName); | |
| 1036 | 1049 | } |
| 1037 | 1050 | } |
| 1038 | 1051 | }else |
| 1039 | 1052 | |
| 1040 | 1053 | /* config NAME SIZE \n CONTENT |
| @@ -1052,38 +1065,15 @@ | ||
| 1052 | 1065 | cgi_reset_content(); |
| 1053 | 1066 | @ error not\sauthorized\sto\spush\sconfiguration |
| 1054 | 1067 | nErr++; |
| 1055 | 1068 | break; |
| 1056 | 1069 | } |
| 1057 | - if( zName[0]!='@' ){ | |
| 1058 | - if( strcmp(zName, "logo-image")==0 ){ | |
| 1059 | - Stmt ins; | |
| 1060 | - db_prepare(&ins, | |
| 1061 | - "REPLACE INTO config(name, value) VALUES(:name, :value)" | |
| 1062 | - ); | |
| 1063 | - db_bind_text(&ins, ":name", zName); | |
| 1064 | - db_bind_blob(&ins, ":value", &content); | |
| 1065 | - db_step(&ins); | |
| 1066 | - db_finalize(&ins); | |
| 1067 | - }else{ | |
| 1068 | - db_multi_exec( | |
| 1069 | - "REPLACE INTO config(name,value) VALUES(%Q,%Q)", | |
| 1070 | - zName, blob_str(&content) | |
| 1071 | - ); | |
| 1072 | - } | |
| 1073 | - }else{ | |
| 1074 | - /* Notice that we are evaluating arbitrary SQL received from the | |
| 1075 | - ** client. But this can only happen if the client has authenticated | |
| 1076 | - ** as an administrator, so presumably we trust the client at this | |
| 1077 | - ** point. | |
| 1078 | - */ | |
| 1079 | - if( !recvConfig ){ | |
| 1080 | - configure_prepare_to_receive(0); | |
| 1081 | - recvConfig = 1; | |
| 1082 | - } | |
| 1083 | - db_multi_exec("%s", blob_str(&content)); | |
| 1084 | - } | |
| 1070 | + if( !recvConfig && zName[0]=='@' ){ | |
| 1071 | + configure_prepare_to_receive(0); | |
| 1072 | + recvConfig = 1; | |
| 1073 | + } | |
| 1074 | + configure_receive(zName, &content, CONFIGSET_ALL); | |
| 1085 | 1075 | blob_reset(&content); |
| 1086 | 1076 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1087 | 1077 | }else |
| 1088 | 1078 | |
| 1089 | 1079 | |
| @@ -1208,19 +1198,19 @@ | ||
| 1208 | 1198 | ** gdb fossil |
| 1209 | 1199 | ** r test-xfer out.txt |
| 1210 | 1200 | */ |
| 1211 | 1201 | void cmd_test_xfer(void){ |
| 1212 | 1202 | int notUsed; |
| 1203 | + db_find_and_open_repository(0,0); | |
| 1213 | 1204 | if( g.argc!=2 && g.argc!=3 ){ |
| 1214 | 1205 | usage("?MESSAGEFILE?"); |
| 1215 | 1206 | } |
| 1216 | - db_must_be_within_tree(); | |
| 1217 | 1207 | blob_zero(&g.cgiIn); |
| 1218 | 1208 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1219 | 1209 | disableLogin = 1; |
| 1220 | 1210 | page_xfer(); |
| 1221 | - printf("%s\n", cgi_extract_content(¬Used)); | |
| 1211 | + fossil_print("%s\n", cgi_extract_content(¬Used)); | |
| 1222 | 1212 | } |
| 1223 | 1213 | |
| 1224 | 1214 | /* |
| 1225 | 1215 | ** Format strings for progress reporting. |
| 1226 | 1216 | */ |
| @@ -1354,25 +1344,32 @@ | ||
| 1354 | 1344 | while( zName ){ |
| 1355 | 1345 | blob_appendf(&send, "reqconfig %s\n", zName); |
| 1356 | 1346 | zName = configure_next_name(configRcvMask); |
| 1357 | 1347 | nCardSent++; |
| 1358 | 1348 | } |
| 1359 | - if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){ | |
| 1360 | - configure_prepare_to_receive(0); | |
| 1349 | + if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0 | |
| 1350 | + && (configRcvMask & CONFIGSET_OLDFORMAT)!=0 | |
| 1351 | + ){ | |
| 1352 | + int overwrite = (configRcvMask & CONFIGSET_OVERWRITE)!=0; | |
| 1353 | + configure_prepare_to_receive(overwrite); | |
| 1361 | 1354 | } |
| 1362 | 1355 | origConfigRcvMask = configRcvMask; |
| 1363 | 1356 | configRcvMask = 0; |
| 1364 | 1357 | } |
| 1365 | 1358 | |
| 1366 | 1359 | /* Send configuration parameters being pushed */ |
| 1367 | 1360 | if( configSendMask ){ |
| 1368 | - const char *zName; | |
| 1369 | - zName = configure_first_name(configSendMask); | |
| 1370 | - while( zName ){ | |
| 1371 | - send_config_card(&xfer, zName); | |
| 1372 | - zName = configure_next_name(configSendMask); | |
| 1373 | - nCardSent++; | |
| 1361 | + if( configSendMask & CONFIGSET_OLDFORMAT ){ | |
| 1362 | + const char *zName; | |
| 1363 | + zName = configure_first_name(configSendMask); | |
| 1364 | + while( zName ){ | |
| 1365 | + send_legacy_config_card(&xfer, zName); | |
| 1366 | + zName = configure_next_name(configSendMask); | |
| 1367 | + nCardSent++; | |
| 1368 | + } | |
| 1369 | + }else{ | |
| 1370 | + nCardSent += configure_send_group(xfer.pOut, configSendMask, 0); | |
| 1374 | 1371 | } |
| 1375 | 1372 | configSendMask = 0; |
| 1376 | 1373 | } |
| 1377 | 1374 | |
| 1378 | 1375 | /* Append randomness to the end of the message. This makes all |
| @@ -1393,11 +1390,11 @@ | ||
| 1393 | 1390 | xfer.nFileSent = 0; |
| 1394 | 1391 | xfer.nDeltaSent = 0; |
| 1395 | 1392 | xfer.nGimmeSent = 0; |
| 1396 | 1393 | xfer.nIGotSent = 0; |
| 1397 | 1394 | if( !g.cgiOutput && !g.fQuiet ){ |
| 1398 | - printf("waiting for server..."); | |
| 1395 | + fossil_print("waiting for server..."); | |
| 1399 | 1396 | } |
| 1400 | 1397 | fflush(stdout); |
| 1401 | 1398 | if( http_exchange(&send, &recv, cloneFlag==0 || nCycle>0) ){ |
| 1402 | 1399 | nErr++; |
| 1403 | 1400 | break; |
| @@ -1441,18 +1438,19 @@ | ||
| 1441 | 1438 | fossil_warning("*** time skew *** server is slow by %s", |
| 1442 | 1439 | db_timespan_name(-rDiff)); |
| 1443 | 1440 | g.clockSkewSeen = 1; |
| 1444 | 1441 | } |
| 1445 | 1442 | } |
| 1443 | + nCardRcvd++; | |
| 1446 | 1444 | continue; |
| 1447 | 1445 | } |
| 1448 | 1446 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 1449 | 1447 | nCardRcvd++; |
| 1450 | 1448 | if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){ |
| 1451 | 1449 | pctDone = (recv.iCursor*100)/recv.nUsed; |
| 1452 | 1450 | if( pctDone!=lastPctDone ){ |
| 1453 | - printf("\rprocessed: %d%% ", pctDone); | |
| 1451 | + fossil_print("\rprocessed: %d%% ", pctDone); | |
| 1454 | 1452 | lastPctDone = pctDone; |
| 1455 | 1453 | fflush(stdout); |
| 1456 | 1454 | } |
| 1457 | 1455 | } |
| 1458 | 1456 | |
| @@ -1544,44 +1542,22 @@ | ||
| 1544 | 1542 | }else |
| 1545 | 1543 | |
| 1546 | 1544 | /* config NAME SIZE \n CONTENT |
| 1547 | 1545 | ** |
| 1548 | 1546 | ** Receive a configuration value from the server. |
| 1547 | + ** | |
| 1548 | + ** The received configuration setting is silently ignored if it was | |
| 1549 | + ** not requested by a prior "reqconfig" sent from client to server. | |
| 1549 | 1550 | */ |
| 1550 | 1551 | if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 |
| 1551 | 1552 | && blob_is_int(&xfer.aToken[2], &size) ){ |
| 1552 | 1553 | const char *zName = blob_str(&xfer.aToken[1]); |
| 1553 | 1554 | Blob content; |
| 1554 | 1555 | blob_zero(&content); |
| 1555 | 1556 | blob_extract(xfer.pIn, size, &content); |
| 1556 | 1557 | g.okAdmin = g.okRdAddr = 1; |
| 1557 | - if( configure_is_exportable(zName) & origConfigRcvMask ){ | |
| 1558 | - if( zName[0]!='@' ){ | |
| 1559 | - if( strcmp(zName, "logo-image")==0 ){ | |
| 1560 | - Stmt ins; | |
| 1561 | - db_prepare(&ins, | |
| 1562 | - "REPLACE INTO config(name, value) VALUES(:name, :value)" | |
| 1563 | - ); | |
| 1564 | - db_bind_text(&ins, ":name", zName); | |
| 1565 | - db_bind_blob(&ins, ":value", &content); | |
| 1566 | - db_step(&ins); | |
| 1567 | - db_finalize(&ins); | |
| 1568 | - }else{ | |
| 1569 | - db_multi_exec( | |
| 1570 | - "REPLACE INTO config(name,value) VALUES(%Q,%Q)", | |
| 1571 | - zName, blob_str(&content) | |
| 1572 | - ); | |
| 1573 | - } | |
| 1574 | - }else{ | |
| 1575 | - /* Notice that we are evaluating arbitrary SQL received from the | |
| 1576 | - ** server. But this can only happen if we have specifically | |
| 1577 | - ** requested configuration information from the server, so | |
| 1578 | - ** presumably the operator trusts the server. | |
| 1579 | - */ | |
| 1580 | - db_multi_exec("%s", blob_str(&content)); | |
| 1581 | - } | |
| 1582 | - } | |
| 1558 | + configure_receive(zName, &content, origConfigRcvMask); | |
| 1583 | 1559 | nCardSent++; |
| 1584 | 1560 | blob_reset(&content); |
| 1585 | 1561 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1586 | 1562 | }else |
| 1587 | 1563 | |
| @@ -1691,11 +1667,13 @@ | ||
| 1691 | 1667 | break; |
| 1692 | 1668 | } |
| 1693 | 1669 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1694 | 1670 | blob_reset(&xfer.line); |
| 1695 | 1671 | } |
| 1696 | - if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){ | |
| 1672 | + if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0 | |
| 1673 | + && (configRcvMask & CONFIGSET_OLDFORMAT)!=0 | |
| 1674 | + ){ | |
| 1697 | 1675 | configure_finalize_receive(); |
| 1698 | 1676 | } |
| 1699 | 1677 | origConfigRcvMask = 0; |
| 1700 | 1678 | if( nCardRcvd>0 ){ |
| 1701 | 1679 | fossil_print(zValueFormat, "Received:", |
| 1702 | 1680 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -454,11 +454,11 @@ | |
| 454 | " (SELECT uuid FROM delta, blob" |
| 455 | " WHERE delta.rid=:rid AND delta.srcid=blob.rid)" |
| 456 | " FROM blob" |
| 457 | " WHERE rid=:rid" |
| 458 | " AND size>=0" |
| 459 | " AND uuid NOT IN shun" |
| 460 | ); |
| 461 | db_bind_int(&q1, ":rid", rid); |
| 462 | rc = db_step(&q1); |
| 463 | if( rc==SQLITE_ROW ){ |
| 464 | zUuid = db_column_text(&q1, 0); |
| @@ -552,10 +552,13 @@ | |
| 552 | defossilize(zLogin); |
| 553 | |
| 554 | if( strcmp(zLogin, "nobody")==0 || strcmp(zLogin,"anonymous")==0 ){ |
| 555 | return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */ |
| 556 | } |
| 557 | db_prepare(&q, |
| 558 | "SELECT pw, cap, uid FROM user" |
| 559 | " WHERE login=%Q" |
| 560 | " AND login NOT IN ('anonymous','nobody','developer','reader')" |
| 561 | " AND length(pw)>0", |
| @@ -592,11 +595,11 @@ | |
| 592 | blob_reset(&combined); |
| 593 | } |
| 594 | if( rc==0 ){ |
| 595 | const char *zCap; |
| 596 | zCap = db_column_text(&q, 1); |
| 597 | login_set_capabilities(zCap); |
| 598 | g.userUid = db_column_int(&q, 2); |
| 599 | g.zLogin = mprintf("%b", pLogin); |
| 600 | g.zNonce = mprintf("%b", pNonce); |
| 601 | } |
| 602 | } |
| @@ -738,13 +741,16 @@ | |
| 738 | } |
| 739 | db_finalize(&q); |
| 740 | } |
| 741 | |
| 742 | /* |
| 743 | ** Send a single config card for configuration item zName |
| 744 | */ |
| 745 | static void send_config_card(Xfer *pXfer, const char *zName){ |
| 746 | if( zName[0]!='@' ){ |
| 747 | Blob val; |
| 748 | blob_zero(&val); |
| 749 | db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName); |
| 750 | if( blob_size(&val)>0 ){ |
| @@ -760,11 +766,10 @@ | |
| 760 | blob_appendf(pXfer->pOut, "config %s %d\n%s\n", zName, |
| 761 | blob_size(&content), blob_str(&content)); |
| 762 | blob_reset(&content); |
| 763 | } |
| 764 | } |
| 765 | |
| 766 | |
| 767 | /* |
| 768 | ** Called when there is an attempt to transfer private content to and |
| 769 | ** from a server without authorization. |
| 770 | */ |
| @@ -807,10 +812,11 @@ | |
| 807 | if( strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 808 | fossil_redirect_home(); |
| 809 | } |
| 810 | g.zLogin = "anonymous"; |
| 811 | login_set_anon_nobody_capabilities(); |
| 812 | memset(&xfer, 0, sizeof(xfer)); |
| 813 | blobarray_zero(xfer.aToken, count(xfer.aToken)); |
| 814 | cgi_set_content_type(g.zContentType); |
| 815 | if( db_schema_is_outofdate() ){ |
| 816 | @ error database\sschema\sis\sout-of-date\son\sthe\sserver. |
| @@ -1007,11 +1013,11 @@ | |
| 1007 | */ |
| 1008 | if( blob_eq(&xfer.aToken[0], "login") |
| 1009 | && xfer.nToken==4 |
| 1010 | ){ |
| 1011 | if( disableLogin ){ |
| 1012 | g.okRead = g.okWrite = g.okPrivate = 1; |
| 1013 | }else{ |
| 1014 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) |
| 1015 | || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) |
| 1016 | ){ |
| 1017 | cgi_reset_content(); |
| @@ -1029,12 +1035,19 @@ | |
| 1029 | if( blob_eq(&xfer.aToken[0], "reqconfig") |
| 1030 | && xfer.nToken==2 |
| 1031 | ){ |
| 1032 | if( g.okRead ){ |
| 1033 | char *zName = blob_str(&xfer.aToken[1]); |
| 1034 | if( configure_is_exportable(zName) ){ |
| 1035 | send_config_card(&xfer, zName); |
| 1036 | } |
| 1037 | } |
| 1038 | }else |
| 1039 | |
| 1040 | /* config NAME SIZE \n CONTENT |
| @@ -1052,38 +1065,15 @@ | |
| 1052 | cgi_reset_content(); |
| 1053 | @ error not\sauthorized\sto\spush\sconfiguration |
| 1054 | nErr++; |
| 1055 | break; |
| 1056 | } |
| 1057 | if( zName[0]!='@' ){ |
| 1058 | if( strcmp(zName, "logo-image")==0 ){ |
| 1059 | Stmt ins; |
| 1060 | db_prepare(&ins, |
| 1061 | "REPLACE INTO config(name, value) VALUES(:name, :value)" |
| 1062 | ); |
| 1063 | db_bind_text(&ins, ":name", zName); |
| 1064 | db_bind_blob(&ins, ":value", &content); |
| 1065 | db_step(&ins); |
| 1066 | db_finalize(&ins); |
| 1067 | }else{ |
| 1068 | db_multi_exec( |
| 1069 | "REPLACE INTO config(name,value) VALUES(%Q,%Q)", |
| 1070 | zName, blob_str(&content) |
| 1071 | ); |
| 1072 | } |
| 1073 | }else{ |
| 1074 | /* Notice that we are evaluating arbitrary SQL received from the |
| 1075 | ** client. But this can only happen if the client has authenticated |
| 1076 | ** as an administrator, so presumably we trust the client at this |
| 1077 | ** point. |
| 1078 | */ |
| 1079 | if( !recvConfig ){ |
| 1080 | configure_prepare_to_receive(0); |
| 1081 | recvConfig = 1; |
| 1082 | } |
| 1083 | db_multi_exec("%s", blob_str(&content)); |
| 1084 | } |
| 1085 | blob_reset(&content); |
| 1086 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1087 | }else |
| 1088 | |
| 1089 | |
| @@ -1208,19 +1198,19 @@ | |
| 1208 | ** gdb fossil |
| 1209 | ** r test-xfer out.txt |
| 1210 | */ |
| 1211 | void cmd_test_xfer(void){ |
| 1212 | int notUsed; |
| 1213 | if( g.argc!=2 && g.argc!=3 ){ |
| 1214 | usage("?MESSAGEFILE?"); |
| 1215 | } |
| 1216 | db_must_be_within_tree(); |
| 1217 | blob_zero(&g.cgiIn); |
| 1218 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1219 | disableLogin = 1; |
| 1220 | page_xfer(); |
| 1221 | printf("%s\n", cgi_extract_content(¬Used)); |
| 1222 | } |
| 1223 | |
| 1224 | /* |
| 1225 | ** Format strings for progress reporting. |
| 1226 | */ |
| @@ -1354,25 +1344,32 @@ | |
| 1354 | while( zName ){ |
| 1355 | blob_appendf(&send, "reqconfig %s\n", zName); |
| 1356 | zName = configure_next_name(configRcvMask); |
| 1357 | nCardSent++; |
| 1358 | } |
| 1359 | if( configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT) ){ |
| 1360 | configure_prepare_to_receive(0); |
| 1361 | } |
| 1362 | origConfigRcvMask = configRcvMask; |
| 1363 | configRcvMask = 0; |
| 1364 | } |
| 1365 | |
| 1366 | /* Send configuration parameters being pushed */ |
| 1367 | if( configSendMask ){ |
| 1368 | const char *zName; |
| 1369 | zName = configure_first_name(configSendMask); |
| 1370 | while( zName ){ |
| 1371 | send_config_card(&xfer, zName); |
| 1372 | zName = configure_next_name(configSendMask); |
| 1373 | nCardSent++; |
| 1374 | } |
| 1375 | configSendMask = 0; |
| 1376 | } |
| 1377 | |
| 1378 | /* Append randomness to the end of the message. This makes all |
| @@ -1393,11 +1390,11 @@ | |
| 1393 | xfer.nFileSent = 0; |
| 1394 | xfer.nDeltaSent = 0; |
| 1395 | xfer.nGimmeSent = 0; |
| 1396 | xfer.nIGotSent = 0; |
| 1397 | if( !g.cgiOutput && !g.fQuiet ){ |
| 1398 | printf("waiting for server..."); |
| 1399 | } |
| 1400 | fflush(stdout); |
| 1401 | if( http_exchange(&send, &recv, cloneFlag==0 || nCycle>0) ){ |
| 1402 | nErr++; |
| 1403 | break; |
| @@ -1441,18 +1438,19 @@ | |
| 1441 | fossil_warning("*** time skew *** server is slow by %s", |
| 1442 | db_timespan_name(-rDiff)); |
| 1443 | g.clockSkewSeen = 1; |
| 1444 | } |
| 1445 | } |
| 1446 | continue; |
| 1447 | } |
| 1448 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 1449 | nCardRcvd++; |
| 1450 | if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){ |
| 1451 | pctDone = (recv.iCursor*100)/recv.nUsed; |
| 1452 | if( pctDone!=lastPctDone ){ |
| 1453 | printf("\rprocessed: %d%% ", pctDone); |
| 1454 | lastPctDone = pctDone; |
| 1455 | fflush(stdout); |
| 1456 | } |
| 1457 | } |
| 1458 | |
| @@ -1544,44 +1542,22 @@ | |
| 1544 | }else |
| 1545 | |
| 1546 | /* config NAME SIZE \n CONTENT |
| 1547 | ** |
| 1548 | ** Receive a configuration value from the server. |
| 1549 | */ |
| 1550 | if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 |
| 1551 | && blob_is_int(&xfer.aToken[2], &size) ){ |
| 1552 | const char *zName = blob_str(&xfer.aToken[1]); |
| 1553 | Blob content; |
| 1554 | blob_zero(&content); |
| 1555 | blob_extract(xfer.pIn, size, &content); |
| 1556 | g.okAdmin = g.okRdAddr = 1; |
| 1557 | if( configure_is_exportable(zName) & origConfigRcvMask ){ |
| 1558 | if( zName[0]!='@' ){ |
| 1559 | if( strcmp(zName, "logo-image")==0 ){ |
| 1560 | Stmt ins; |
| 1561 | db_prepare(&ins, |
| 1562 | "REPLACE INTO config(name, value) VALUES(:name, :value)" |
| 1563 | ); |
| 1564 | db_bind_text(&ins, ":name", zName); |
| 1565 | db_bind_blob(&ins, ":value", &content); |
| 1566 | db_step(&ins); |
| 1567 | db_finalize(&ins); |
| 1568 | }else{ |
| 1569 | db_multi_exec( |
| 1570 | "REPLACE INTO config(name,value) VALUES(%Q,%Q)", |
| 1571 | zName, blob_str(&content) |
| 1572 | ); |
| 1573 | } |
| 1574 | }else{ |
| 1575 | /* Notice that we are evaluating arbitrary SQL received from the |
| 1576 | ** server. But this can only happen if we have specifically |
| 1577 | ** requested configuration information from the server, so |
| 1578 | ** presumably the operator trusts the server. |
| 1579 | */ |
| 1580 | db_multi_exec("%s", blob_str(&content)); |
| 1581 | } |
| 1582 | } |
| 1583 | nCardSent++; |
| 1584 | blob_reset(&content); |
| 1585 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1586 | }else |
| 1587 | |
| @@ -1691,11 +1667,13 @@ | |
| 1691 | break; |
| 1692 | } |
| 1693 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1694 | blob_reset(&xfer.line); |
| 1695 | } |
| 1696 | if( origConfigRcvMask & (CONFIGSET_TKT|CONFIGSET_USER) ){ |
| 1697 | configure_finalize_receive(); |
| 1698 | } |
| 1699 | origConfigRcvMask = 0; |
| 1700 | if( nCardRcvd>0 ){ |
| 1701 | fossil_print(zValueFormat, "Received:", |
| 1702 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -454,11 +454,11 @@ | |
| 454 | " (SELECT uuid FROM delta, blob" |
| 455 | " WHERE delta.rid=:rid AND delta.srcid=blob.rid)" |
| 456 | " FROM blob" |
| 457 | " WHERE rid=:rid" |
| 458 | " AND size>=0" |
| 459 | " AND NOT EXISTS(SELECT 1 FROM shun WHERE shun.uuid=blob.uuid)" |
| 460 | ); |
| 461 | db_bind_int(&q1, ":rid", rid); |
| 462 | rc = db_step(&q1); |
| 463 | if( rc==SQLITE_ROW ){ |
| 464 | zUuid = db_column_text(&q1, 0); |
| @@ -552,10 +552,13 @@ | |
| 552 | defossilize(zLogin); |
| 553 | |
| 554 | if( strcmp(zLogin, "nobody")==0 || strcmp(zLogin,"anonymous")==0 ){ |
| 555 | return 0; /* Anybody is allowed to sync as "nobody" or "anonymous" */ |
| 556 | } |
| 557 | if( fossil_strcmp(P("REMOTE_USER"), zLogin)==0 ){ |
| 558 | return 0; /* Accept Basic Authorization */ |
| 559 | } |
| 560 | db_prepare(&q, |
| 561 | "SELECT pw, cap, uid FROM user" |
| 562 | " WHERE login=%Q" |
| 563 | " AND login NOT IN ('anonymous','nobody','developer','reader')" |
| 564 | " AND length(pw)>0", |
| @@ -592,11 +595,11 @@ | |
| 595 | blob_reset(&combined); |
| 596 | } |
| 597 | if( rc==0 ){ |
| 598 | const char *zCap; |
| 599 | zCap = db_column_text(&q, 1); |
| 600 | login_set_capabilities(zCap, 0); |
| 601 | g.userUid = db_column_int(&q, 2); |
| 602 | g.zLogin = mprintf("%b", pLogin); |
| 603 | g.zNonce = mprintf("%b", pNonce); |
| 604 | } |
| 605 | } |
| @@ -738,13 +741,16 @@ | |
| 741 | } |
| 742 | db_finalize(&q); |
| 743 | } |
| 744 | |
| 745 | /* |
| 746 | ** Send a single old-style config card for configuration item zName. |
| 747 | ** |
| 748 | ** This routine and the functionality it implements is scheduled for |
| 749 | ** removal on 2012-05-01. |
| 750 | */ |
| 751 | static void send_legacy_config_card(Xfer *pXfer, const char *zName){ |
| 752 | if( zName[0]!='@' ){ |
| 753 | Blob val; |
| 754 | blob_zero(&val); |
| 755 | db_blob(&val, "SELECT value FROM config WHERE name=%Q", zName); |
| 756 | if( blob_size(&val)>0 ){ |
| @@ -760,11 +766,10 @@ | |
| 766 | blob_appendf(pXfer->pOut, "config %s %d\n%s\n", zName, |
| 767 | blob_size(&content), blob_str(&content)); |
| 768 | blob_reset(&content); |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | /* |
| 773 | ** Called when there is an attempt to transfer private content to and |
| 774 | ** from a server without authorization. |
| 775 | */ |
| @@ -807,10 +812,11 @@ | |
| 812 | if( strcmp(PD("REQUEST_METHOD","POST"),"POST") ){ |
| 813 | fossil_redirect_home(); |
| 814 | } |
| 815 | g.zLogin = "anonymous"; |
| 816 | login_set_anon_nobody_capabilities(); |
| 817 | login_check_credentials(); |
| 818 | memset(&xfer, 0, sizeof(xfer)); |
| 819 | blobarray_zero(xfer.aToken, count(xfer.aToken)); |
| 820 | cgi_set_content_type(g.zContentType); |
| 821 | if( db_schema_is_outofdate() ){ |
| 822 | @ error database\sschema\sis\sout-of-date\son\sthe\sserver. |
| @@ -1007,11 +1013,11 @@ | |
| 1013 | */ |
| 1014 | if( blob_eq(&xfer.aToken[0], "login") |
| 1015 | && xfer.nToken==4 |
| 1016 | ){ |
| 1017 | if( disableLogin ){ |
| 1018 | g.okRead = g.okWrite = g.okPrivate = g.okAdmin = 1; |
| 1019 | }else{ |
| 1020 | if( check_tail_hash(&xfer.aToken[2], xfer.pIn) |
| 1021 | || check_login(&xfer.aToken[1], &xfer.aToken[2], &xfer.aToken[3]) |
| 1022 | ){ |
| 1023 | cgi_reset_content(); |
| @@ -1029,12 +1035,19 @@ | |
| 1035 | if( blob_eq(&xfer.aToken[0], "reqconfig") |
| 1036 | && xfer.nToken==2 |
| 1037 | ){ |
| 1038 | if( g.okRead ){ |
| 1039 | char *zName = blob_str(&xfer.aToken[1]); |
| 1040 | if( zName[0]=='/' ){ |
| 1041 | /* New style configuration transfer */ |
| 1042 | int groupMask = configure_name_to_mask(&zName[1], 0); |
| 1043 | if( !g.okAdmin ) groupMask &= ~CONFIGSET_USER; |
| 1044 | if( !g.okRdAddr ) groupMask &= ~CONFIGSET_ADDR; |
| 1045 | configure_send_group(xfer.pOut, groupMask, 0); |
| 1046 | }else if( configure_is_exportable(zName) ){ |
| 1047 | /* Old style configuration transfer */ |
| 1048 | send_legacy_config_card(&xfer, zName); |
| 1049 | } |
| 1050 | } |
| 1051 | }else |
| 1052 | |
| 1053 | /* config NAME SIZE \n CONTENT |
| @@ -1052,38 +1065,15 @@ | |
| 1065 | cgi_reset_content(); |
| 1066 | @ error not\sauthorized\sto\spush\sconfiguration |
| 1067 | nErr++; |
| 1068 | break; |
| 1069 | } |
| 1070 | if( !recvConfig && zName[0]=='@' ){ |
| 1071 | configure_prepare_to_receive(0); |
| 1072 | recvConfig = 1; |
| 1073 | } |
| 1074 | configure_receive(zName, &content, CONFIGSET_ALL); |
| 1075 | blob_reset(&content); |
| 1076 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1077 | }else |
| 1078 | |
| 1079 | |
| @@ -1208,19 +1198,19 @@ | |
| 1198 | ** gdb fossil |
| 1199 | ** r test-xfer out.txt |
| 1200 | */ |
| 1201 | void cmd_test_xfer(void){ |
| 1202 | int notUsed; |
| 1203 | db_find_and_open_repository(0,0); |
| 1204 | if( g.argc!=2 && g.argc!=3 ){ |
| 1205 | usage("?MESSAGEFILE?"); |
| 1206 | } |
| 1207 | blob_zero(&g.cgiIn); |
| 1208 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1209 | disableLogin = 1; |
| 1210 | page_xfer(); |
| 1211 | fossil_print("%s\n", cgi_extract_content(¬Used)); |
| 1212 | } |
| 1213 | |
| 1214 | /* |
| 1215 | ** Format strings for progress reporting. |
| 1216 | */ |
| @@ -1354,25 +1344,32 @@ | |
| 1344 | while( zName ){ |
| 1345 | blob_appendf(&send, "reqconfig %s\n", zName); |
| 1346 | zName = configure_next_name(configRcvMask); |
| 1347 | nCardSent++; |
| 1348 | } |
| 1349 | if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0 |
| 1350 | && (configRcvMask & CONFIGSET_OLDFORMAT)!=0 |
| 1351 | ){ |
| 1352 | int overwrite = (configRcvMask & CONFIGSET_OVERWRITE)!=0; |
| 1353 | configure_prepare_to_receive(overwrite); |
| 1354 | } |
| 1355 | origConfigRcvMask = configRcvMask; |
| 1356 | configRcvMask = 0; |
| 1357 | } |
| 1358 | |
| 1359 | /* Send configuration parameters being pushed */ |
| 1360 | if( configSendMask ){ |
| 1361 | if( configSendMask & CONFIGSET_OLDFORMAT ){ |
| 1362 | const char *zName; |
| 1363 | zName = configure_first_name(configSendMask); |
| 1364 | while( zName ){ |
| 1365 | send_legacy_config_card(&xfer, zName); |
| 1366 | zName = configure_next_name(configSendMask); |
| 1367 | nCardSent++; |
| 1368 | } |
| 1369 | }else{ |
| 1370 | nCardSent += configure_send_group(xfer.pOut, configSendMask, 0); |
| 1371 | } |
| 1372 | configSendMask = 0; |
| 1373 | } |
| 1374 | |
| 1375 | /* Append randomness to the end of the message. This makes all |
| @@ -1393,11 +1390,11 @@ | |
| 1390 | xfer.nFileSent = 0; |
| 1391 | xfer.nDeltaSent = 0; |
| 1392 | xfer.nGimmeSent = 0; |
| 1393 | xfer.nIGotSent = 0; |
| 1394 | if( !g.cgiOutput && !g.fQuiet ){ |
| 1395 | fossil_print("waiting for server..."); |
| 1396 | } |
| 1397 | fflush(stdout); |
| 1398 | if( http_exchange(&send, &recv, cloneFlag==0 || nCycle>0) ){ |
| 1399 | nErr++; |
| 1400 | break; |
| @@ -1441,18 +1438,19 @@ | |
| 1438 | fossil_warning("*** time skew *** server is slow by %s", |
| 1439 | db_timespan_name(-rDiff)); |
| 1440 | g.clockSkewSeen = 1; |
| 1441 | } |
| 1442 | } |
| 1443 | nCardRcvd++; |
| 1444 | continue; |
| 1445 | } |
| 1446 | xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken)); |
| 1447 | nCardRcvd++; |
| 1448 | if( !g.cgiOutput && !g.fQuiet && recv.nUsed>0 ){ |
| 1449 | pctDone = (recv.iCursor*100)/recv.nUsed; |
| 1450 | if( pctDone!=lastPctDone ){ |
| 1451 | fossil_print("\rprocessed: %d%% ", pctDone); |
| 1452 | lastPctDone = pctDone; |
| 1453 | fflush(stdout); |
| 1454 | } |
| 1455 | } |
| 1456 | |
| @@ -1544,44 +1542,22 @@ | |
| 1542 | }else |
| 1543 | |
| 1544 | /* config NAME SIZE \n CONTENT |
| 1545 | ** |
| 1546 | ** Receive a configuration value from the server. |
| 1547 | ** |
| 1548 | ** The received configuration setting is silently ignored if it was |
| 1549 | ** not requested by a prior "reqconfig" sent from client to server. |
| 1550 | */ |
| 1551 | if( blob_eq(&xfer.aToken[0],"config") && xfer.nToken==3 |
| 1552 | && blob_is_int(&xfer.aToken[2], &size) ){ |
| 1553 | const char *zName = blob_str(&xfer.aToken[1]); |
| 1554 | Blob content; |
| 1555 | blob_zero(&content); |
| 1556 | blob_extract(xfer.pIn, size, &content); |
| 1557 | g.okAdmin = g.okRdAddr = 1; |
| 1558 | configure_receive(zName, &content, origConfigRcvMask); |
| 1559 | nCardSent++; |
| 1560 | blob_reset(&content); |
| 1561 | blob_seek(xfer.pIn, 1, BLOB_SEEK_CUR); |
| 1562 | }else |
| 1563 | |
| @@ -1691,11 +1667,13 @@ | |
| 1667 | break; |
| 1668 | } |
| 1669 | blobarray_reset(xfer.aToken, xfer.nToken); |
| 1670 | blob_reset(&xfer.line); |
| 1671 | } |
| 1672 | if( (configRcvMask & (CONFIGSET_USER|CONFIGSET_TKT))!=0 |
| 1673 | && (configRcvMask & CONFIGSET_OLDFORMAT)!=0 |
| 1674 | ){ |
| 1675 | configure_finalize_receive(); |
| 1676 | } |
| 1677 | origConfigRcvMask = 0; |
| 1678 | if( nCardRcvd>0 ){ |
| 1679 | fossil_print(zValueFormat, "Received:", |
| 1680 |
+3
-3
| --- test/file1.test | ||
| +++ test/file1.test | ||
| @@ -26,12 +26,12 @@ | ||
| 26 | 26 | incr i |
| 27 | 27 | } |
| 28 | 28 | } |
| 29 | 29 | |
| 30 | 30 | simplify-name 100 . . .// . .. .. ..///// .. |
| 31 | -simplify-name 101 {} . / / ///////// / ././././ . | |
| 32 | -simplify-name 102 x x /x /x ///x /x | |
| 33 | -simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// /a/b | |
| 31 | +simplify-name 101 {} {} / / ///////// / ././././ . | |
| 32 | +simplify-name 102 x x /x /x ///x //x | |
| 33 | +simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b | |
| 34 | 34 | simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c |
| 35 | 35 | simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y |
| 36 | 36 | simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y |
| 37 | 37 | simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y |
| 38 | 38 |
| --- test/file1.test | |
| +++ test/file1.test | |
| @@ -26,12 +26,12 @@ | |
| 26 | incr i |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | simplify-name 100 . . .// . .. .. ..///// .. |
| 31 | simplify-name 101 {} . / / ///////// / ././././ . |
| 32 | simplify-name 102 x x /x /x ///x /x |
| 33 | simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// /a/b |
| 34 | simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c |
| 35 | simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y |
| 36 | simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y |
| 37 | simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y |
| 38 |
| --- test/file1.test | |
| +++ test/file1.test | |
| @@ -26,12 +26,12 @@ | |
| 26 | incr i |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | simplify-name 100 . . .// . .. .. ..///// .. |
| 31 | simplify-name 101 {} {} / / ///////// / ././././ . |
| 32 | simplify-name 102 x x /x /x ///x //x |
| 33 | simplify-name 103 a/b a/b /a/b /a/b a///b a/b ///a///b///// //a/b |
| 34 | simplify-name 104 a/b/../c/ a/c /a/b/../c /a/c /a/b//../c /a/c /a/b/..///c /a/c |
| 35 | simplify-name 105 a/b/../../x/y x/y /a/b/../../x/y /x/y |
| 36 | simplify-name 106 a/b/../../../x/y ../x/y /a/b/../../../x/y /../x/y |
| 37 | simplify-name 107 a/./b/.././../x/y x/y a//.//b//..//.//..//x//y/// x/y |
| 38 |
+63
-22
| --- test/graph-test-1.wiki | ||
| +++ test/graph-test-1.wiki | ||
| @@ -2,30 +2,71 @@ | ||
| 2 | 2 | |
| 3 | 3 | This page contains examples a list of URLs of timelines with |
| 4 | 4 | interesting graphs. Click on all URLs, one by one, to verify |
| 5 | 5 | the correct operation of the graph drawing logic. |
| 6 | 6 | |
| 7 | - * [/timeline?n=20&y=ci&b=2010-11-08] | |
| 8 | - * [/timeline?n=40&y=ci&b=2010-11-08] | |
| 9 | - * [/timeline?n=1000&y=ci&b=2010-11-08] | |
| 10 | - * [/timeline?f=3ea66260b5555d2e] | |
| 11 | - * [/timeline?d=e5fe4164f74a7576&p=e5fe4164f74a7576&n=3] - | |
| 12 | - multiple merge descenders from the penultimate node. | |
| 13 | - * [/timeline?y=ci&a=2010-12-20] - multiple branch risers. | |
| 14 | - * [/timeline?y=ci&a=2010-12-20&n=18] | |
| 15 | - * [/timeline?y=ci&a=2010-12-20&n=9] | |
| 16 | - * [/timeline?r=experimental] | |
| 17 | - * [/timeline?r=experimental&n=1000] | |
| 18 | - * [/timeline?r=creole] | |
| 19 | - * [/timeline?t=creole] | |
| 20 | - * [/timeline?t=release] | |
| 21 | - * [/timeline?r=release] | |
| 22 | - * [/finfo?name=Makefile] | |
| 23 | - * [/timeline?a=1970-01-01] | |
| 24 | - * [/timeline?y=ci&n=1000000] - All checkins - a huge graph | |
| 25 | - * [/timeline?f=8dfed953f7530442] - This malformed commit has a | |
| 26 | - merge parent which is not a valid checkin. | |
| 7 | + * <a href="../../../timeline?n=20&y=ci&b=2010-11-08" target="testwindow"> | |
| 8 | + 20-element timeline, check-ins only, before 2010-11-08</a> | |
| 9 | + * <a href="../../../timeline?n=20&y=ci&b=2010-11-08&ng" target="testwindow"> | |
| 10 | + 20-element timeline, check-ins only, no graph, before 2010-11-08</a> | |
| 11 | + * <a href="../../../timeline?n=20&y=ci&b=2010-11-08&fc" target="testwindow"> | |
| 12 | + 20-element timeline, check-ins only, file changes, before 2010-11-08</a> | |
| 13 | + * <a href="../../../timeline?n=40&y=ci&b=2010-11-08" target="testwindow"> | |
| 14 | + 40-element timeline, check-ins only, before 2010-11-08</a> | |
| 15 | + * <a href="../../../timeline?n=1000&y=ci&b=2010-11-08" target="testwindow"> | |
| 16 | + 1000-element timeline, check-ins only, before 2010-11-08</a> | |
| 17 | + * <a href="../../../timeline?n=10&c=2010-11-07+10:23:00" target="testwindow"> | |
| 18 | + 10-elements circa 2010-11-07 10:23:00, with dividers</a> | |
| 19 | + * <a href="../../../timeline?n=10&c=2010-11-07+10:23:00&nd" | |
| 20 | + target="testwindow"> | |
| 21 | + 10-elements circa 2010-11-07 10:23:00, without dividers</a> | |
| 22 | + * <a href="../../../timeline?f=3ea66260b5555" target="testwindow"> | |
| 23 | + Parents and children of check-in 3ea66260b5555</a> | |
| 24 | + * <a href="../../../timeline?d=e5fe4164f74a7576&p=e5fe4164f74a7576&n=3" | |
| 25 | + target="testwindow">multiple merge descenders from the penultimate node. | |
| 26 | + </a> | |
| 27 | + * <a href="../../../timeline?y=ci&a=2010-12-20" target="testwindow"> | |
| 28 | + multiple branch risers.</a> | |
| 29 | + * <a href="../../../timeline?y=ci&a=2010-12-20&n=18" target="testwindow"> | |
| 30 | + multiple branch risers, n=18.</a> | |
| 31 | + * <a href="../../../timeline?y=ci&a=2010-12-20&n=9" target="testwindow"> | |
| 32 | + multiple branch risers, n=9.</a> | |
| 33 | + * <a href="../../../timeline?r=experimental" target="testwindow"> | |
| 34 | + Experimental branch using and related check-ins.</a> | |
| 35 | + * <a href="../../../timeline?r=experimental&mionly" target="testwindow"> | |
| 36 | + Experimental branch using and merge-ins only.</a> | |
| 37 | + * <a href="../../../timeline?t=experimental" target="testwindow"> | |
| 38 | + Experimental branch check-ins only.</a> | |
| 39 | + * <a href="../../../timeline?r=experimental&n=1000" target="testwindow"> | |
| 40 | + Experimental branch using and related check-ins - 1000 elements.</a> | |
| 41 | + * <a href="../../../timeline?r=release" target="testwindow"> | |
| 42 | + Check-ins tagged "release" and related check-ins</a> | |
| 43 | + * <a href="../../../timeline?r=release&mionly" target="testwindow"> | |
| 44 | + Check-ins tagged "release" and merge-ins</a> | |
| 45 | + * <a href="../../../timeline?t=release" target="testwindow"> | |
| 46 | + Only check-ins tagged "release"</a> | |
| 47 | + * <a href="../../../finfo?name=Makefile" target="testwindow"> | |
| 48 | + History of source file "Makefile".</a> | |
| 49 | + * <a href="../../../timeline?a=1970-01-01" target="testwindow"> | |
| 50 | + 20 elements after 1970-01-01.</a> | |
| 51 | + * <a href="../../../timeline?n=100000000&y=ci" target="testwindow"> | |
| 52 | + All check-ins - a huge graph.</a> | |
| 53 | + * <a href="../../../timeline?f=8dfed953f7530442" target="testwindow"> | |
| 54 | + This malformed commit has a | |
| 55 | + merge parent which is not a valid checkin.</a> | |
| 56 | + * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9" | |
| 57 | + target="testwindow"> | |
| 58 | + From e663bac6f7 to a298a0e2f9 by shortest path.</a> | |
| 59 | + * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&nomerge" | |
| 60 | + target="testwindow"> | |
| 61 | + From e663bac6f7 to a298a0e2f9 without merge links.</a> | |
| 62 | + * <a href="../../../timeline?me=e663bac6f7&you=a298a0e2f9" | |
| 63 | + target="testwindow"> | |
| 64 | + Common ancestor path of e663bac6f7 to a298a0e2f9.</a> | |
| 65 | + * <a href="../../../timeline?f=65dd90fb95a2af55"> | |
| 66 | + Merge on the same branch does not result in a leaf. | |
| 67 | + </a> | |
| 27 | 68 | |
| 28 | 69 | External: |
| 29 | 70 | |
| 30 | - * [http://www.sqlite.org/src/timeline?c=2010-09-29&nd] - timewarp due to | |
| 31 | - a mis-configured system clock. | |
| 71 | + * <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd" | |
| 72 | + target="testwindow">Timewarp due to a mis-configured system clock.</a> | |
| 32 | 73 |
| --- test/graph-test-1.wiki | |
| +++ test/graph-test-1.wiki | |
| @@ -2,30 +2,71 @@ | |
| 2 | |
| 3 | This page contains examples a list of URLs of timelines with |
| 4 | interesting graphs. Click on all URLs, one by one, to verify |
| 5 | the correct operation of the graph drawing logic. |
| 6 | |
| 7 | * [/timeline?n=20&y=ci&b=2010-11-08] |
| 8 | * [/timeline?n=40&y=ci&b=2010-11-08] |
| 9 | * [/timeline?n=1000&y=ci&b=2010-11-08] |
| 10 | * [/timeline?f=3ea66260b5555d2e] |
| 11 | * [/timeline?d=e5fe4164f74a7576&p=e5fe4164f74a7576&n=3] - |
| 12 | multiple merge descenders from the penultimate node. |
| 13 | * [/timeline?y=ci&a=2010-12-20] - multiple branch risers. |
| 14 | * [/timeline?y=ci&a=2010-12-20&n=18] |
| 15 | * [/timeline?y=ci&a=2010-12-20&n=9] |
| 16 | * [/timeline?r=experimental] |
| 17 | * [/timeline?r=experimental&n=1000] |
| 18 | * [/timeline?r=creole] |
| 19 | * [/timeline?t=creole] |
| 20 | * [/timeline?t=release] |
| 21 | * [/timeline?r=release] |
| 22 | * [/finfo?name=Makefile] |
| 23 | * [/timeline?a=1970-01-01] |
| 24 | * [/timeline?y=ci&n=1000000] - All checkins - a huge graph |
| 25 | * [/timeline?f=8dfed953f7530442] - This malformed commit has a |
| 26 | merge parent which is not a valid checkin. |
| 27 | |
| 28 | External: |
| 29 | |
| 30 | * [http://www.sqlite.org/src/timeline?c=2010-09-29&nd] - timewarp due to |
| 31 | a mis-configured system clock. |
| 32 |
| --- test/graph-test-1.wiki | |
| +++ test/graph-test-1.wiki | |
| @@ -2,30 +2,71 @@ | |
| 2 | |
| 3 | This page contains examples a list of URLs of timelines with |
| 4 | interesting graphs. Click on all URLs, one by one, to verify |
| 5 | the correct operation of the graph drawing logic. |
| 6 | |
| 7 | * <a href="../../../timeline?n=20&y=ci&b=2010-11-08" target="testwindow"> |
| 8 | 20-element timeline, check-ins only, before 2010-11-08</a> |
| 9 | * <a href="../../../timeline?n=20&y=ci&b=2010-11-08&ng" target="testwindow"> |
| 10 | 20-element timeline, check-ins only, no graph, before 2010-11-08</a> |
| 11 | * <a href="../../../timeline?n=20&y=ci&b=2010-11-08&fc" target="testwindow"> |
| 12 | 20-element timeline, check-ins only, file changes, before 2010-11-08</a> |
| 13 | * <a href="../../../timeline?n=40&y=ci&b=2010-11-08" target="testwindow"> |
| 14 | 40-element timeline, check-ins only, before 2010-11-08</a> |
| 15 | * <a href="../../../timeline?n=1000&y=ci&b=2010-11-08" target="testwindow"> |
| 16 | 1000-element timeline, check-ins only, before 2010-11-08</a> |
| 17 | * <a href="../../../timeline?n=10&c=2010-11-07+10:23:00" target="testwindow"> |
| 18 | 10-elements circa 2010-11-07 10:23:00, with dividers</a> |
| 19 | * <a href="../../../timeline?n=10&c=2010-11-07+10:23:00&nd" |
| 20 | target="testwindow"> |
| 21 | 10-elements circa 2010-11-07 10:23:00, without dividers</a> |
| 22 | * <a href="../../../timeline?f=3ea66260b5555" target="testwindow"> |
| 23 | Parents and children of check-in 3ea66260b5555</a> |
| 24 | * <a href="../../../timeline?d=e5fe4164f74a7576&p=e5fe4164f74a7576&n=3" |
| 25 | target="testwindow">multiple merge descenders from the penultimate node. |
| 26 | </a> |
| 27 | * <a href="../../../timeline?y=ci&a=2010-12-20" target="testwindow"> |
| 28 | multiple branch risers.</a> |
| 29 | * <a href="../../../timeline?y=ci&a=2010-12-20&n=18" target="testwindow"> |
| 30 | multiple branch risers, n=18.</a> |
| 31 | * <a href="../../../timeline?y=ci&a=2010-12-20&n=9" target="testwindow"> |
| 32 | multiple branch risers, n=9.</a> |
| 33 | * <a href="../../../timeline?r=experimental" target="testwindow"> |
| 34 | Experimental branch using and related check-ins.</a> |
| 35 | * <a href="../../../timeline?r=experimental&mionly" target="testwindow"> |
| 36 | Experimental branch using and merge-ins only.</a> |
| 37 | * <a href="../../../timeline?t=experimental" target="testwindow"> |
| 38 | Experimental branch check-ins only.</a> |
| 39 | * <a href="../../../timeline?r=experimental&n=1000" target="testwindow"> |
| 40 | Experimental branch using and related check-ins - 1000 elements.</a> |
| 41 | * <a href="../../../timeline?r=release" target="testwindow"> |
| 42 | Check-ins tagged "release" and related check-ins</a> |
| 43 | * <a href="../../../timeline?r=release&mionly" target="testwindow"> |
| 44 | Check-ins tagged "release" and merge-ins</a> |
| 45 | * <a href="../../../timeline?t=release" target="testwindow"> |
| 46 | Only check-ins tagged "release"</a> |
| 47 | * <a href="../../../finfo?name=Makefile" target="testwindow"> |
| 48 | History of source file "Makefile".</a> |
| 49 | * <a href="../../../timeline?a=1970-01-01" target="testwindow"> |
| 50 | 20 elements after 1970-01-01.</a> |
| 51 | * <a href="../../../timeline?n=100000000&y=ci" target="testwindow"> |
| 52 | All check-ins - a huge graph.</a> |
| 53 | * <a href="../../../timeline?f=8dfed953f7530442" target="testwindow"> |
| 54 | This malformed commit has a |
| 55 | merge parent which is not a valid checkin.</a> |
| 56 | * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9" |
| 57 | target="testwindow"> |
| 58 | From e663bac6f7 to a298a0e2f9 by shortest path.</a> |
| 59 | * <a href="../../../timeline?from=e663bac6f7&to=a298a0e2f9&nomerge" |
| 60 | target="testwindow"> |
| 61 | From e663bac6f7 to a298a0e2f9 without merge links.</a> |
| 62 | * <a href="../../../timeline?me=e663bac6f7&you=a298a0e2f9" |
| 63 | target="testwindow"> |
| 64 | Common ancestor path of e663bac6f7 to a298a0e2f9.</a> |
| 65 | * <a href="../../../timeline?f=65dd90fb95a2af55"> |
| 66 | Merge on the same branch does not result in a leaf. |
| 67 | </a> |
| 68 | |
| 69 | External: |
| 70 | |
| 71 | * <a href="http://www.sqlite.org/src/timeline?c=2010-09-29&nd" |
| 72 | target="testwindow">Timewarp due to a mis-configured system clock.</a> |
| 73 |
+44
-18
| --- test/merge1.test | ||
| +++ test/merge1.test | ||
| @@ -71,26 +71,30 @@ | ||
| 71 | 71 | 333 - This is a test of the merging algohm - 3333 |
| 72 | 72 | 444 - If all goes well, we will be pleased - 4444 |
| 73 | 73 | 555 - we think it well and other stuff too - 5555 |
| 74 | 74 | } |
| 75 | 75 | write_file_indented t23 { |
| 76 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 76 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 77 | 77 | 111 - This is line ONE of the demo program - 1111 |
| 78 | - ======= original content above; conflict below ============= | |
| 78 | + ======= COMMON ANCESTOR content follows ============================ | |
| 79 | + 111 - This is line one of the demo program - 1111 | |
| 80 | + ======= MERGED IN content follows ================================== | |
| 79 | 81 | 111 - This is line one OF the demo program - 1111 |
| 80 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 82 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 81 | 83 | 222 - The second line program line in code - 2222 |
| 82 | 84 | 333 - This is a test of the merging algohm - 3333 |
| 83 | 85 | 444 - If all goes well, we will be pleased - 4444 |
| 84 | 86 | 555 - we think it well and other stuff too - 5555 |
| 85 | 87 | } |
| 86 | 88 | write_file_indented t32 { |
| 87 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 89 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 88 | 90 | 111 - This is line one OF the demo program - 1111 |
| 89 | - ======= original content above; conflict below ============= | |
| 91 | + ======= COMMON ANCESTOR content follows ============================ | |
| 92 | + 111 - This is line one of the demo program - 1111 | |
| 93 | + ======= MERGED IN content follows ================================== | |
| 90 | 94 | 111 - This is line ONE of the demo program - 1111 |
| 91 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 95 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 92 | 96 | 222 - The second line program line in code - 2222 |
| 93 | 97 | 333 - This is a test of the merging algohm - 3333 |
| 94 | 98 | 444 - If all goes well, we will be pleased - 4444 |
| 95 | 99 | 555 - we think it well and other stuff too - 5555 |
| 96 | 100 | } |
| @@ -152,26 +156,30 @@ | ||
| 152 | 156 | 333 - This is a test of the merging algohm - 3333 |
| 153 | 157 | 444 - If all goes well, we will be pleased - 4444 |
| 154 | 158 | 555 - we think it well and other stuff too - 5555 |
| 155 | 159 | } |
| 156 | 160 | write_file_indented t32 { |
| 157 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 158 | - ======= original content above; conflict below ============= | |
| 161 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 162 | + ======= COMMON ANCESTOR content follows ============================ | |
| 163 | + 111 - This is line one of the demo program - 1111 | |
| 164 | + ======= MERGED IN content follows ================================== | |
| 159 | 165 | 000 - Zero lines added to the beginning of - 0000 |
| 160 | 166 | 111 - This is line one of the demo program - 1111 |
| 161 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 167 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 162 | 168 | 222 - The second line program line in code - 2222 |
| 163 | 169 | 333 - This is a test of the merging algohm - 3333 |
| 164 | 170 | 444 - If all goes well, we will be pleased - 4444 |
| 165 | 171 | 555 - we think it well and other stuff too - 5555 |
| 166 | 172 | } |
| 167 | 173 | write_file_indented t23 { |
| 168 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 174 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 169 | 175 | 000 - Zero lines added to the beginning of - 0000 |
| 170 | 176 | 111 - This is line one of the demo program - 1111 |
| 171 | - ======= original content above; conflict below ============= | |
| 172 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 177 | + ======= COMMON ANCESTOR content follows ============================ | |
| 178 | + 111 - This is line one of the demo program - 1111 | |
| 179 | + ======= MERGED IN content follows ================================== | |
| 180 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 173 | 181 | 222 - The second line program line in code - 2222 |
| 174 | 182 | 333 - This is a test of the merging algohm - 3333 |
| 175 | 183 | 444 - If all goes well, we will be pleased - 4444 |
| 176 | 184 | 555 - we think it well and other stuff too - 5555 |
| 177 | 185 | } |
| @@ -287,29 +295,38 @@ | ||
| 287 | 295 | STUV |
| 288 | 296 | XYZ. |
| 289 | 297 | } |
| 290 | 298 | write_file_indented t23 { |
| 291 | 299 | abcd |
| 292 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 300 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 293 | 301 | efgh 2 |
| 294 | 302 | ijkl 2 |
| 295 | 303 | mnop 2 |
| 296 | 304 | qrst |
| 297 | 305 | uvwx |
| 298 | 306 | yzAB 2 |
| 299 | 307 | CDEF 2 |
| 300 | 308 | GHIJ 2 |
| 301 | - ======= original content above; conflict below ============= | |
| 309 | + ======= COMMON ANCESTOR content follows ============================ | |
| 310 | + efgh | |
| 311 | + ijkl | |
| 312 | + mnop | |
| 313 | + qrst | |
| 314 | + uvwx | |
| 315 | + yzAB | |
| 316 | + CDEF | |
| 317 | + GHIJ | |
| 318 | + ======= MERGED IN content follows ================================== | |
| 302 | 319 | efgh |
| 303 | 320 | ijkl |
| 304 | 321 | mnop 3 |
| 305 | 322 | qrst 3 |
| 306 | 323 | uvwx 3 |
| 307 | 324 | yzAB 3 |
| 308 | 325 | CDEF |
| 309 | 326 | GHIJ |
| 310 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 327 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 311 | 328 | KLMN |
| 312 | 329 | OPQR |
| 313 | 330 | STUV |
| 314 | 331 | XYZ. |
| 315 | 332 | } |
| @@ -346,31 +363,40 @@ | ||
| 346 | 363 | STUV |
| 347 | 364 | XYZ. |
| 348 | 365 | } |
| 349 | 366 | write_file_indented t23 { |
| 350 | 367 | abcd |
| 351 | - <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< | |
| 368 | + <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< | |
| 352 | 369 | efgh 2 |
| 353 | 370 | ijkl 2 |
| 354 | 371 | mnop |
| 355 | 372 | qrst |
| 356 | 373 | uvwx |
| 357 | 374 | yzAB 2 |
| 358 | 375 | CDEF 2 |
| 359 | 376 | GHIJ 2 |
| 360 | - ======= original content above; conflict below ============= | |
| 377 | + ======= COMMON ANCESTOR content follows ============================ | |
| 378 | + efgh | |
| 379 | + ijkl | |
| 380 | + mnop | |
| 381 | + qrst | |
| 382 | + uvwx | |
| 383 | + yzAB | |
| 384 | + CDEF | |
| 385 | + GHIJ | |
| 386 | + ======= MERGED IN content follows ================================== | |
| 361 | 387 | efgh |
| 362 | 388 | ijkl |
| 363 | 389 | mnop 3 |
| 364 | 390 | qrst 3 |
| 365 | 391 | uvwx 3 |
| 366 | 392 | yzAB 3 |
| 367 | 393 | CDEF |
| 368 | 394 | GHIJ |
| 369 | - >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> | |
| 395 | + >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> | |
| 370 | 396 | KLMN |
| 371 | 397 | OPQR |
| 372 | 398 | STUV |
| 373 | 399 | XYZ. |
| 374 | 400 | } |
| 375 | 401 | fossil test-3 t1 t2 t3 a23 |
| 376 | 402 | test merge1-7.2 {[same_file t23 a23]} |
| 377 | 403 |
| --- test/merge1.test | |
| +++ test/merge1.test | |
| @@ -71,26 +71,30 @@ | |
| 71 | 333 - This is a test of the merging algohm - 3333 |
| 72 | 444 - If all goes well, we will be pleased - 4444 |
| 73 | 555 - we think it well and other stuff too - 5555 |
| 74 | } |
| 75 | write_file_indented t23 { |
| 76 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 77 | 111 - This is line ONE of the demo program - 1111 |
| 78 | ======= original content above; conflict below ============= |
| 79 | 111 - This is line one OF the demo program - 1111 |
| 80 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 81 | 222 - The second line program line in code - 2222 |
| 82 | 333 - This is a test of the merging algohm - 3333 |
| 83 | 444 - If all goes well, we will be pleased - 4444 |
| 84 | 555 - we think it well and other stuff too - 5555 |
| 85 | } |
| 86 | write_file_indented t32 { |
| 87 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 88 | 111 - This is line one OF the demo program - 1111 |
| 89 | ======= original content above; conflict below ============= |
| 90 | 111 - This is line ONE of the demo program - 1111 |
| 91 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 92 | 222 - The second line program line in code - 2222 |
| 93 | 333 - This is a test of the merging algohm - 3333 |
| 94 | 444 - If all goes well, we will be pleased - 4444 |
| 95 | 555 - we think it well and other stuff too - 5555 |
| 96 | } |
| @@ -152,26 +156,30 @@ | |
| 152 | 333 - This is a test of the merging algohm - 3333 |
| 153 | 444 - If all goes well, we will be pleased - 4444 |
| 154 | 555 - we think it well and other stuff too - 5555 |
| 155 | } |
| 156 | write_file_indented t32 { |
| 157 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 158 | ======= original content above; conflict below ============= |
| 159 | 000 - Zero lines added to the beginning of - 0000 |
| 160 | 111 - This is line one of the demo program - 1111 |
| 161 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 162 | 222 - The second line program line in code - 2222 |
| 163 | 333 - This is a test of the merging algohm - 3333 |
| 164 | 444 - If all goes well, we will be pleased - 4444 |
| 165 | 555 - we think it well and other stuff too - 5555 |
| 166 | } |
| 167 | write_file_indented t23 { |
| 168 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 169 | 000 - Zero lines added to the beginning of - 0000 |
| 170 | 111 - This is line one of the demo program - 1111 |
| 171 | ======= original content above; conflict below ============= |
| 172 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 173 | 222 - The second line program line in code - 2222 |
| 174 | 333 - This is a test of the merging algohm - 3333 |
| 175 | 444 - If all goes well, we will be pleased - 4444 |
| 176 | 555 - we think it well and other stuff too - 5555 |
| 177 | } |
| @@ -287,29 +295,38 @@ | |
| 287 | STUV |
| 288 | XYZ. |
| 289 | } |
| 290 | write_file_indented t23 { |
| 291 | abcd |
| 292 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 293 | efgh 2 |
| 294 | ijkl 2 |
| 295 | mnop 2 |
| 296 | qrst |
| 297 | uvwx |
| 298 | yzAB 2 |
| 299 | CDEF 2 |
| 300 | GHIJ 2 |
| 301 | ======= original content above; conflict below ============= |
| 302 | efgh |
| 303 | ijkl |
| 304 | mnop 3 |
| 305 | qrst 3 |
| 306 | uvwx 3 |
| 307 | yzAB 3 |
| 308 | CDEF |
| 309 | GHIJ |
| 310 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 311 | KLMN |
| 312 | OPQR |
| 313 | STUV |
| 314 | XYZ. |
| 315 | } |
| @@ -346,31 +363,40 @@ | |
| 346 | STUV |
| 347 | XYZ. |
| 348 | } |
| 349 | write_file_indented t23 { |
| 350 | abcd |
| 351 | <<<<<<< BEGIN MERGE CONFLICT: original content first <<<<<<< |
| 352 | efgh 2 |
| 353 | ijkl 2 |
| 354 | mnop |
| 355 | qrst |
| 356 | uvwx |
| 357 | yzAB 2 |
| 358 | CDEF 2 |
| 359 | GHIJ 2 |
| 360 | ======= original content above; conflict below ============= |
| 361 | efgh |
| 362 | ijkl |
| 363 | mnop 3 |
| 364 | qrst 3 |
| 365 | uvwx 3 |
| 366 | yzAB 3 |
| 367 | CDEF |
| 368 | GHIJ |
| 369 | >>>>>>> END MERGE CONFLICT: conflict last >>>>>>>>>>>>>>>>>> |
| 370 | KLMN |
| 371 | OPQR |
| 372 | STUV |
| 373 | XYZ. |
| 374 | } |
| 375 | fossil test-3 t1 t2 t3 a23 |
| 376 | test merge1-7.2 {[same_file t23 a23]} |
| 377 |
| --- test/merge1.test | |
| +++ test/merge1.test | |
| @@ -71,26 +71,30 @@ | |
| 71 | 333 - This is a test of the merging algohm - 3333 |
| 72 | 444 - If all goes well, we will be pleased - 4444 |
| 73 | 555 - we think it well and other stuff too - 5555 |
| 74 | } |
| 75 | write_file_indented t23 { |
| 76 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 77 | 111 - This is line ONE of the demo program - 1111 |
| 78 | ======= COMMON ANCESTOR content follows ============================ |
| 79 | 111 - This is line one of the demo program - 1111 |
| 80 | ======= MERGED IN content follows ================================== |
| 81 | 111 - This is line one OF the demo program - 1111 |
| 82 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 83 | 222 - The second line program line in code - 2222 |
| 84 | 333 - This is a test of the merging algohm - 3333 |
| 85 | 444 - If all goes well, we will be pleased - 4444 |
| 86 | 555 - we think it well and other stuff too - 5555 |
| 87 | } |
| 88 | write_file_indented t32 { |
| 89 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 90 | 111 - This is line one OF the demo program - 1111 |
| 91 | ======= COMMON ANCESTOR content follows ============================ |
| 92 | 111 - This is line one of the demo program - 1111 |
| 93 | ======= MERGED IN content follows ================================== |
| 94 | 111 - This is line ONE of the demo program - 1111 |
| 95 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 96 | 222 - The second line program line in code - 2222 |
| 97 | 333 - This is a test of the merging algohm - 3333 |
| 98 | 444 - If all goes well, we will be pleased - 4444 |
| 99 | 555 - we think it well and other stuff too - 5555 |
| 100 | } |
| @@ -152,26 +156,30 @@ | |
| 156 | 333 - This is a test of the merging algohm - 3333 |
| 157 | 444 - If all goes well, we will be pleased - 4444 |
| 158 | 555 - we think it well and other stuff too - 5555 |
| 159 | } |
| 160 | write_file_indented t32 { |
| 161 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 162 | ======= COMMON ANCESTOR content follows ============================ |
| 163 | 111 - This is line one of the demo program - 1111 |
| 164 | ======= MERGED IN content follows ================================== |
| 165 | 000 - Zero lines added to the beginning of - 0000 |
| 166 | 111 - This is line one of the demo program - 1111 |
| 167 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 168 | 222 - The second line program line in code - 2222 |
| 169 | 333 - This is a test of the merging algohm - 3333 |
| 170 | 444 - If all goes well, we will be pleased - 4444 |
| 171 | 555 - we think it well and other stuff too - 5555 |
| 172 | } |
| 173 | write_file_indented t23 { |
| 174 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 175 | 000 - Zero lines added to the beginning of - 0000 |
| 176 | 111 - This is line one of the demo program - 1111 |
| 177 | ======= COMMON ANCESTOR content follows ============================ |
| 178 | 111 - This is line one of the demo program - 1111 |
| 179 | ======= MERGED IN content follows ================================== |
| 180 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 181 | 222 - The second line program line in code - 2222 |
| 182 | 333 - This is a test of the merging algohm - 3333 |
| 183 | 444 - If all goes well, we will be pleased - 4444 |
| 184 | 555 - we think it well and other stuff too - 5555 |
| 185 | } |
| @@ -287,29 +295,38 @@ | |
| 295 | STUV |
| 296 | XYZ. |
| 297 | } |
| 298 | write_file_indented t23 { |
| 299 | abcd |
| 300 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 301 | efgh 2 |
| 302 | ijkl 2 |
| 303 | mnop 2 |
| 304 | qrst |
| 305 | uvwx |
| 306 | yzAB 2 |
| 307 | CDEF 2 |
| 308 | GHIJ 2 |
| 309 | ======= COMMON ANCESTOR content follows ============================ |
| 310 | efgh |
| 311 | ijkl |
| 312 | mnop |
| 313 | qrst |
| 314 | uvwx |
| 315 | yzAB |
| 316 | CDEF |
| 317 | GHIJ |
| 318 | ======= MERGED IN content follows ================================== |
| 319 | efgh |
| 320 | ijkl |
| 321 | mnop 3 |
| 322 | qrst 3 |
| 323 | uvwx 3 |
| 324 | yzAB 3 |
| 325 | CDEF |
| 326 | GHIJ |
| 327 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 328 | KLMN |
| 329 | OPQR |
| 330 | STUV |
| 331 | XYZ. |
| 332 | } |
| @@ -346,31 +363,40 @@ | |
| 363 | STUV |
| 364 | XYZ. |
| 365 | } |
| 366 | write_file_indented t23 { |
| 367 | abcd |
| 368 | <<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<< |
| 369 | efgh 2 |
| 370 | ijkl 2 |
| 371 | mnop |
| 372 | qrst |
| 373 | uvwx |
| 374 | yzAB 2 |
| 375 | CDEF 2 |
| 376 | GHIJ 2 |
| 377 | ======= COMMON ANCESTOR content follows ============================ |
| 378 | efgh |
| 379 | ijkl |
| 380 | mnop |
| 381 | qrst |
| 382 | uvwx |
| 383 | yzAB |
| 384 | CDEF |
| 385 | GHIJ |
| 386 | ======= MERGED IN content follows ================================== |
| 387 | efgh |
| 388 | ijkl |
| 389 | mnop 3 |
| 390 | qrst 3 |
| 391 | uvwx 3 |
| 392 | yzAB 3 |
| 393 | CDEF |
| 394 | GHIJ |
| 395 | >>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> |
| 396 | KLMN |
| 397 | OPQR |
| 398 | STUV |
| 399 | XYZ. |
| 400 | } |
| 401 | fossil test-3 t1 t2 t3 a23 |
| 402 | test merge1-7.2 {[same_file t23 a23]} |
| 403 |
+30
-28
| --- test/merge3.test | ||
| +++ test/merge3.test | ||
| @@ -22,13 +22,15 @@ | ||
| 22 | 22 | write_file t1 [join [string trim $basis] \n]\n |
| 23 | 23 | write_file t2 [join [string trim $v1] \n]\n |
| 24 | 24 | write_file t3 [join [string trim $v2] \n]\n |
| 25 | 25 | fossil test-3-way-merge t1 t2 t3 t4 |
| 26 | 26 | set x [read_file t4] |
| 27 | - regsub -all {<<<<<<< BEGIN MERGE CONFLICT:.*<} $x {>} x | |
| 28 | - regsub -all {======= original content.*======} $x {=} x | |
| 29 | - regsub -all {>>>>>>> END MERGE CONFLICT:.*>>>} $x {<} x | |
| 27 | + regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \ | |
| 28 | + {MINE:} x | |
| 29 | + regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x | |
| 30 | + regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x | |
| 31 | + regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x | |
| 30 | 32 | set x [split [string trim $x] \n] |
| 31 | 33 | set result [string trim $result] |
| 32 | 34 | if {$x!=$result} { |
| 33 | 35 | protOut " Expected \[$result\]" |
| 34 | 36 | protOut " Got \[$x\]" |
| @@ -62,56 +64,56 @@ | ||
| 62 | 64 | } { |
| 63 | 65 | 1 2 3b 4b 5b 6 7 8 9 |
| 64 | 66 | } { |
| 65 | 67 | 1 2 3 4 5c 6 7 8 9 |
| 66 | 68 | } { |
| 67 | - 1 2 > 3b 4b 5b = 3 4 5c < 6 7 8 9 | |
| 69 | + 1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 | |
| 68 | 70 | } |
| 69 | 71 | merge-test 4 { |
| 70 | 72 | 1 2 3 4 5 6 7 8 9 |
| 71 | 73 | } { |
| 72 | 74 | 1 2 3b 4b 5b 6b 7 8 9 |
| 73 | 75 | } { |
| 74 | 76 | 1 2 3 4 5c 6 7 8 9 |
| 75 | 77 | } { |
| 76 | - 1 2 > 3b 4b 5b 6b = 3 4 5c 6 < 7 8 9 | |
| 78 | + 1 2 MINE: 3b 4b 5b 6b COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9 | |
| 77 | 79 | } |
| 78 | 80 | merge-test 5 { |
| 79 | 81 | 1 2 3 4 5 6 7 8 9 |
| 80 | 82 | } { |
| 81 | 83 | 1 2 3b 4b 5b 6b 7 8 9 |
| 82 | 84 | } { |
| 83 | 85 | 1 2 3 4 5c 6c 7c 8 9 |
| 84 | 86 | } { |
| 85 | - 1 2 > 3b 4b 5b 6b 7 = 3 4 5c 6c 7c < 8 9 | |
| 87 | + 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9 | |
| 86 | 88 | } |
| 87 | 89 | merge-test 6 { |
| 88 | 90 | 1 2 3 4 5 6 7 8 9 |
| 89 | 91 | } { |
| 90 | 92 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 91 | 93 | } { |
| 92 | 94 | 1 2 3 4 5c 6c 7c 8 9 |
| 93 | 95 | } { |
| 94 | - 1 2 > 3b 4b 5b 6b 7 = 3 4 5c 6c 7c < 8b 9 | |
| 96 | + 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9 | |
| 95 | 97 | } |
| 96 | 98 | merge-test 7 { |
| 97 | 99 | 1 2 3 4 5 6 7 8 9 |
| 98 | 100 | } { |
| 99 | 101 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 100 | 102 | } { |
| 101 | 103 | 1 2 3 4 5c 6c 7c 8c 9 |
| 102 | 104 | } { |
| 103 | - 1 2 > 3b 4b 5b 6b 7 8b = 3 4 5c 6c 7c 8c < 9 | |
| 105 | + 1 2 MINE: 3b 4b 5b 6b 7 8b COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9 | |
| 104 | 106 | } |
| 105 | 107 | merge-test 8 { |
| 106 | 108 | 1 2 3 4 5 6 7 8 9 |
| 107 | 109 | } { |
| 108 | 110 | 1 2 3b 4b 5b 6b 7 8b 9b |
| 109 | 111 | } { |
| 110 | 112 | 1 2 3 4 5c 6c 7c 8c 9 |
| 111 | 113 | } { |
| 112 | - 1 2 > 3b 4b 5b 6b 7 8b 9b = 3 4 5c 6c 7c 8c 9 < | |
| 114 | + 1 2 MINE: 3b 4b 5b 6b 7 8b 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END | |
| 113 | 115 | } |
| 114 | 116 | merge-test 9 { |
| 115 | 117 | 1 2 3 4 5 6 7 8 9 |
| 116 | 118 | } { |
| 117 | 119 | 1 2 3b 4b 5 6 7 8b 9b |
| @@ -135,11 +137,11 @@ | ||
| 135 | 137 | } { |
| 136 | 138 | 1 2 3b 4b 5 6 7 8b 9b |
| 137 | 139 | } { |
| 138 | 140 | 1 2 3b 4c 5 6c 7c 8 9 |
| 139 | 141 | } { |
| 140 | - 1 2 > 3b 4b = 3b 4c < 5 6c 7c 8b 9b | |
| 142 | + 1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b | |
| 141 | 143 | } |
| 142 | 144 | merge-test 12 { |
| 143 | 145 | 1 2 3 4 5 6 7 8 9 |
| 144 | 146 | } { |
| 145 | 147 | 1 2 3b4b 5 6 7 8b 9b |
| @@ -190,20 +192,20 @@ | ||
| 190 | 192 | } { |
| 191 | 193 | 1 6 7 8 9 |
| 192 | 194 | } { |
| 193 | 195 | 1 2 3 4 9 |
| 194 | 196 | } { |
| 195 | - 1 > 6 7 8 = 2 3 4 < 9 | |
| 197 | + 1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 | |
| 196 | 198 | } |
| 197 | 199 | merge-test 25 { |
| 198 | 200 | 1 2 3 4 5 6 7 8 9 |
| 199 | 201 | } { |
| 200 | 202 | 1 7 8 9 |
| 201 | 203 | } { |
| 202 | 204 | 1 2 3 9 |
| 203 | 205 | } { |
| 204 | - 1 > 7 8 = 2 3 < 9 | |
| 206 | + 1 MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 | |
| 205 | 207 | } |
| 206 | 208 | |
| 207 | 209 | merge-test 30 { |
| 208 | 210 | 1 2 3 4 5 6 7 8 9 |
| 209 | 211 | } { |
| @@ -245,20 +247,20 @@ | ||
| 245 | 247 | } { |
| 246 | 248 | 1 2 3 4 9 |
| 247 | 249 | } { |
| 248 | 250 | 1 6 7 8 9 |
| 249 | 251 | } { |
| 250 | - 1 > 2 3 4 = 6 7 8 < 9 | |
| 252 | + 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 | |
| 251 | 253 | } |
| 252 | 254 | merge-test 35 { |
| 253 | 255 | 1 2 3 4 5 6 7 8 9 |
| 254 | 256 | } { |
| 255 | 257 | 1 2 3 9 |
| 256 | 258 | } { |
| 257 | 259 | 1 7 8 9 |
| 258 | 260 | } { |
| 259 | - 1 > 2 3 = 7 8 < 9 | |
| 261 | + 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9 | |
| 260 | 262 | } |
| 261 | 263 | |
| 262 | 264 | merge-test 40 { |
| 263 | 265 | 2 3 4 5 6 7 8 |
| 264 | 266 | } { |
| @@ -300,20 +302,20 @@ | ||
| 300 | 302 | } { |
| 301 | 303 | 6 7 8 |
| 302 | 304 | } { |
| 303 | 305 | 2 3 4 |
| 304 | 306 | } { |
| 305 | - > 6 7 8 = 2 3 4 < | |
| 307 | + MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END | |
| 306 | 308 | } |
| 307 | 309 | merge-test 45 { |
| 308 | 310 | 2 3 4 5 6 7 8 |
| 309 | 311 | } { |
| 310 | 312 | 7 8 |
| 311 | 313 | } { |
| 312 | 314 | 2 3 |
| 313 | 315 | } { |
| 314 | - > 7 8 = 2 3 < | |
| 316 | + MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END | |
| 315 | 317 | } |
| 316 | 318 | |
| 317 | 319 | merge-test 50 { |
| 318 | 320 | 2 3 4 5 6 7 8 |
| 319 | 321 | } { |
| @@ -354,20 +356,20 @@ | ||
| 354 | 356 | } { |
| 355 | 357 | 2 3 4 |
| 356 | 358 | } { |
| 357 | 359 | 6 7 8 |
| 358 | 360 | } { |
| 359 | - > 2 3 4 = 6 7 8 < | |
| 361 | + MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END | |
| 360 | 362 | } |
| 361 | 363 | merge-test 55 { |
| 362 | 364 | 2 3 4 5 6 7 8 |
| 363 | 365 | } { |
| 364 | 366 | 2 3 |
| 365 | 367 | } { |
| 366 | 368 | 7 8 |
| 367 | 369 | } { |
| 368 | - > 2 3 = 7 8 < | |
| 370 | + MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END | |
| 369 | 371 | } |
| 370 | 372 | |
| 371 | 373 | merge-test 60 { |
| 372 | 374 | 1 2 3 4 5 6 7 8 9 |
| 373 | 375 | } { |
| @@ -409,20 +411,20 @@ | ||
| 409 | 411 | } { |
| 410 | 412 | 1 2b 3b 4b 5b 6 7 8 9 |
| 411 | 413 | } { |
| 412 | 414 | 1 2 3 4 9 |
| 413 | 415 | } { |
| 414 | - 1 > 2b 3b 4b 5b 6 7 8 = 2 3 4 < 9 | |
| 416 | + 1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 | |
| 415 | 417 | } |
| 416 | 418 | merge-test 65 { |
| 417 | 419 | 1 2 3 4 5 6 7 8 9 |
| 418 | 420 | } { |
| 419 | 421 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 420 | 422 | } { |
| 421 | 423 | 1 2 3 9 |
| 422 | 424 | } { |
| 423 | - 1 > 2b 3b 4b 5b 6b 7 8 = 2 3 < 9 | |
| 425 | + 1 MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 | |
| 424 | 426 | } |
| 425 | 427 | |
| 426 | 428 | merge-test 70 { |
| 427 | 429 | 1 2 3 4 5 6 7 8 9 |
| 428 | 430 | } { |
| @@ -464,20 +466,20 @@ | ||
| 464 | 466 | } { |
| 465 | 467 | 1 2 3 4 9 |
| 466 | 468 | } { |
| 467 | 469 | 1 2b 3b 4b 5b 6 7 8 9 |
| 468 | 470 | } { |
| 469 | - 1 > 2 3 4 = 2b 3b 4b 5b 6 7 8 < 9 | |
| 471 | + 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 | |
| 470 | 472 | } |
| 471 | 473 | merge-test 75 { |
| 472 | 474 | 1 2 3 4 5 6 7 8 9 |
| 473 | 475 | } { |
| 474 | 476 | 1 2 3 9 |
| 475 | 477 | } { |
| 476 | 478 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 477 | 479 | } { |
| 478 | - 1 > 2 3 = 2b 3b 4b 5b 6b 7 8 < 9 | |
| 480 | + 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9 | |
| 479 | 481 | } |
| 480 | 482 | |
| 481 | 483 | merge-test 80 { |
| 482 | 484 | 2 3 4 5 6 7 8 |
| 483 | 485 | } { |
| @@ -519,20 +521,20 @@ | ||
| 519 | 521 | } { |
| 520 | 522 | 2b 3b 4b 5b 6 7 8 |
| 521 | 523 | } { |
| 522 | 524 | 2 3 4 |
| 523 | 525 | } { |
| 524 | - > 2b 3b 4b 5b 6 7 8 = 2 3 4 < | |
| 526 | + MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END | |
| 525 | 527 | } |
| 526 | 528 | merge-test 85 { |
| 527 | 529 | 2 3 4 5 6 7 8 |
| 528 | 530 | } { |
| 529 | 531 | 2b 3b 4b 5b 6b 7 8 |
| 530 | 532 | } { |
| 531 | 533 | 2 3 |
| 532 | 534 | } { |
| 533 | - > 2b 3b 4b 5b 6b 7 8 = 2 3 < | |
| 535 | + MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END | |
| 534 | 536 | } |
| 535 | 537 | |
| 536 | 538 | merge-test 90 { |
| 537 | 539 | 2 3 4 5 6 7 8 |
| 538 | 540 | } { |
| @@ -574,20 +576,20 @@ | ||
| 574 | 576 | } { |
| 575 | 577 | 2 3 4 |
| 576 | 578 | } { |
| 577 | 579 | 2b 3b 4b 5b 6 7 8 |
| 578 | 580 | } { |
| 579 | - > 2 3 4 = 2b 3b 4b 5b 6 7 8 < | |
| 581 | + MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END | |
| 580 | 582 | } |
| 581 | 583 | merge-test 95 { |
| 582 | 584 | 2 3 4 5 6 7 8 |
| 583 | 585 | } { |
| 584 | 586 | 2 3 |
| 585 | 587 | } { |
| 586 | 588 | 2b 3b 4b 5b 6b 7 8 |
| 587 | 589 | } { |
| 588 | - > 2 3 = 2b 3b 4b 5b 6b 7 8 < | |
| 590 | + MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END | |
| 589 | 591 | } |
| 590 | 592 | |
| 591 | 593 | merge-test 100 { |
| 592 | 594 | 1 2 3 4 5 6 7 8 9 |
| 593 | 595 | } { |
| @@ -620,16 +622,16 @@ | ||
| 620 | 622 | } { |
| 621 | 623 | 1 2 3 4 5 7 8 9b |
| 622 | 624 | } { |
| 623 | 625 | 1 2 3 4 5 7 8 9b a b c d e |
| 624 | 626 | } { |
| 625 | - 1 2 3 4 5 7 8 > 9b = 9b a b c d e < | |
| 627 | + 1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END | |
| 626 | 628 | } |
| 627 | 629 | merge-test 104 { |
| 628 | 630 | 1 2 3 4 5 6 7 8 9 |
| 629 | 631 | } { |
| 630 | 632 | 1 2 3 4 5 7 8 9b a b c d e |
| 631 | 633 | } { |
| 632 | 634 | 1 2 3 4 5 7 8 9b |
| 633 | 635 | } { |
| 634 | - 1 2 3 4 5 7 8 > 9b a b c d e = 9b < | |
| 636 | + 1 2 3 4 5 7 8 MINE: 9b a b c d e COM: 9 YOURS: 9b END | |
| 635 | 637 | } |
| 636 | 638 |
| --- test/merge3.test | |
| +++ test/merge3.test | |
| @@ -22,13 +22,15 @@ | |
| 22 | write_file t1 [join [string trim $basis] \n]\n |
| 23 | write_file t2 [join [string trim $v1] \n]\n |
| 24 | write_file t3 [join [string trim $v2] \n]\n |
| 25 | fossil test-3-way-merge t1 t2 t3 t4 |
| 26 | set x [read_file t4] |
| 27 | regsub -all {<<<<<<< BEGIN MERGE CONFLICT:.*<} $x {>} x |
| 28 | regsub -all {======= original content.*======} $x {=} x |
| 29 | regsub -all {>>>>>>> END MERGE CONFLICT:.*>>>} $x {<} x |
| 30 | set x [split [string trim $x] \n] |
| 31 | set result [string trim $result] |
| 32 | if {$x!=$result} { |
| 33 | protOut " Expected \[$result\]" |
| 34 | protOut " Got \[$x\]" |
| @@ -62,56 +64,56 @@ | |
| 62 | } { |
| 63 | 1 2 3b 4b 5b 6 7 8 9 |
| 64 | } { |
| 65 | 1 2 3 4 5c 6 7 8 9 |
| 66 | } { |
| 67 | 1 2 > 3b 4b 5b = 3 4 5c < 6 7 8 9 |
| 68 | } |
| 69 | merge-test 4 { |
| 70 | 1 2 3 4 5 6 7 8 9 |
| 71 | } { |
| 72 | 1 2 3b 4b 5b 6b 7 8 9 |
| 73 | } { |
| 74 | 1 2 3 4 5c 6 7 8 9 |
| 75 | } { |
| 76 | 1 2 > 3b 4b 5b 6b = 3 4 5c 6 < 7 8 9 |
| 77 | } |
| 78 | merge-test 5 { |
| 79 | 1 2 3 4 5 6 7 8 9 |
| 80 | } { |
| 81 | 1 2 3b 4b 5b 6b 7 8 9 |
| 82 | } { |
| 83 | 1 2 3 4 5c 6c 7c 8 9 |
| 84 | } { |
| 85 | 1 2 > 3b 4b 5b 6b 7 = 3 4 5c 6c 7c < 8 9 |
| 86 | } |
| 87 | merge-test 6 { |
| 88 | 1 2 3 4 5 6 7 8 9 |
| 89 | } { |
| 90 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 91 | } { |
| 92 | 1 2 3 4 5c 6c 7c 8 9 |
| 93 | } { |
| 94 | 1 2 > 3b 4b 5b 6b 7 = 3 4 5c 6c 7c < 8b 9 |
| 95 | } |
| 96 | merge-test 7 { |
| 97 | 1 2 3 4 5 6 7 8 9 |
| 98 | } { |
| 99 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 100 | } { |
| 101 | 1 2 3 4 5c 6c 7c 8c 9 |
| 102 | } { |
| 103 | 1 2 > 3b 4b 5b 6b 7 8b = 3 4 5c 6c 7c 8c < 9 |
| 104 | } |
| 105 | merge-test 8 { |
| 106 | 1 2 3 4 5 6 7 8 9 |
| 107 | } { |
| 108 | 1 2 3b 4b 5b 6b 7 8b 9b |
| 109 | } { |
| 110 | 1 2 3 4 5c 6c 7c 8c 9 |
| 111 | } { |
| 112 | 1 2 > 3b 4b 5b 6b 7 8b 9b = 3 4 5c 6c 7c 8c 9 < |
| 113 | } |
| 114 | merge-test 9 { |
| 115 | 1 2 3 4 5 6 7 8 9 |
| 116 | } { |
| 117 | 1 2 3b 4b 5 6 7 8b 9b |
| @@ -135,11 +137,11 @@ | |
| 135 | } { |
| 136 | 1 2 3b 4b 5 6 7 8b 9b |
| 137 | } { |
| 138 | 1 2 3b 4c 5 6c 7c 8 9 |
| 139 | } { |
| 140 | 1 2 > 3b 4b = 3b 4c < 5 6c 7c 8b 9b |
| 141 | } |
| 142 | merge-test 12 { |
| 143 | 1 2 3 4 5 6 7 8 9 |
| 144 | } { |
| 145 | 1 2 3b4b 5 6 7 8b 9b |
| @@ -190,20 +192,20 @@ | |
| 190 | } { |
| 191 | 1 6 7 8 9 |
| 192 | } { |
| 193 | 1 2 3 4 9 |
| 194 | } { |
| 195 | 1 > 6 7 8 = 2 3 4 < 9 |
| 196 | } |
| 197 | merge-test 25 { |
| 198 | 1 2 3 4 5 6 7 8 9 |
| 199 | } { |
| 200 | 1 7 8 9 |
| 201 | } { |
| 202 | 1 2 3 9 |
| 203 | } { |
| 204 | 1 > 7 8 = 2 3 < 9 |
| 205 | } |
| 206 | |
| 207 | merge-test 30 { |
| 208 | 1 2 3 4 5 6 7 8 9 |
| 209 | } { |
| @@ -245,20 +247,20 @@ | |
| 245 | } { |
| 246 | 1 2 3 4 9 |
| 247 | } { |
| 248 | 1 6 7 8 9 |
| 249 | } { |
| 250 | 1 > 2 3 4 = 6 7 8 < 9 |
| 251 | } |
| 252 | merge-test 35 { |
| 253 | 1 2 3 4 5 6 7 8 9 |
| 254 | } { |
| 255 | 1 2 3 9 |
| 256 | } { |
| 257 | 1 7 8 9 |
| 258 | } { |
| 259 | 1 > 2 3 = 7 8 < 9 |
| 260 | } |
| 261 | |
| 262 | merge-test 40 { |
| 263 | 2 3 4 5 6 7 8 |
| 264 | } { |
| @@ -300,20 +302,20 @@ | |
| 300 | } { |
| 301 | 6 7 8 |
| 302 | } { |
| 303 | 2 3 4 |
| 304 | } { |
| 305 | > 6 7 8 = 2 3 4 < |
| 306 | } |
| 307 | merge-test 45 { |
| 308 | 2 3 4 5 6 7 8 |
| 309 | } { |
| 310 | 7 8 |
| 311 | } { |
| 312 | 2 3 |
| 313 | } { |
| 314 | > 7 8 = 2 3 < |
| 315 | } |
| 316 | |
| 317 | merge-test 50 { |
| 318 | 2 3 4 5 6 7 8 |
| 319 | } { |
| @@ -354,20 +356,20 @@ | |
| 354 | } { |
| 355 | 2 3 4 |
| 356 | } { |
| 357 | 6 7 8 |
| 358 | } { |
| 359 | > 2 3 4 = 6 7 8 < |
| 360 | } |
| 361 | merge-test 55 { |
| 362 | 2 3 4 5 6 7 8 |
| 363 | } { |
| 364 | 2 3 |
| 365 | } { |
| 366 | 7 8 |
| 367 | } { |
| 368 | > 2 3 = 7 8 < |
| 369 | } |
| 370 | |
| 371 | merge-test 60 { |
| 372 | 1 2 3 4 5 6 7 8 9 |
| 373 | } { |
| @@ -409,20 +411,20 @@ | |
| 409 | } { |
| 410 | 1 2b 3b 4b 5b 6 7 8 9 |
| 411 | } { |
| 412 | 1 2 3 4 9 |
| 413 | } { |
| 414 | 1 > 2b 3b 4b 5b 6 7 8 = 2 3 4 < 9 |
| 415 | } |
| 416 | merge-test 65 { |
| 417 | 1 2 3 4 5 6 7 8 9 |
| 418 | } { |
| 419 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 420 | } { |
| 421 | 1 2 3 9 |
| 422 | } { |
| 423 | 1 > 2b 3b 4b 5b 6b 7 8 = 2 3 < 9 |
| 424 | } |
| 425 | |
| 426 | merge-test 70 { |
| 427 | 1 2 3 4 5 6 7 8 9 |
| 428 | } { |
| @@ -464,20 +466,20 @@ | |
| 464 | } { |
| 465 | 1 2 3 4 9 |
| 466 | } { |
| 467 | 1 2b 3b 4b 5b 6 7 8 9 |
| 468 | } { |
| 469 | 1 > 2 3 4 = 2b 3b 4b 5b 6 7 8 < 9 |
| 470 | } |
| 471 | merge-test 75 { |
| 472 | 1 2 3 4 5 6 7 8 9 |
| 473 | } { |
| 474 | 1 2 3 9 |
| 475 | } { |
| 476 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 477 | } { |
| 478 | 1 > 2 3 = 2b 3b 4b 5b 6b 7 8 < 9 |
| 479 | } |
| 480 | |
| 481 | merge-test 80 { |
| 482 | 2 3 4 5 6 7 8 |
| 483 | } { |
| @@ -519,20 +521,20 @@ | |
| 519 | } { |
| 520 | 2b 3b 4b 5b 6 7 8 |
| 521 | } { |
| 522 | 2 3 4 |
| 523 | } { |
| 524 | > 2b 3b 4b 5b 6 7 8 = 2 3 4 < |
| 525 | } |
| 526 | merge-test 85 { |
| 527 | 2 3 4 5 6 7 8 |
| 528 | } { |
| 529 | 2b 3b 4b 5b 6b 7 8 |
| 530 | } { |
| 531 | 2 3 |
| 532 | } { |
| 533 | > 2b 3b 4b 5b 6b 7 8 = 2 3 < |
| 534 | } |
| 535 | |
| 536 | merge-test 90 { |
| 537 | 2 3 4 5 6 7 8 |
| 538 | } { |
| @@ -574,20 +576,20 @@ | |
| 574 | } { |
| 575 | 2 3 4 |
| 576 | } { |
| 577 | 2b 3b 4b 5b 6 7 8 |
| 578 | } { |
| 579 | > 2 3 4 = 2b 3b 4b 5b 6 7 8 < |
| 580 | } |
| 581 | merge-test 95 { |
| 582 | 2 3 4 5 6 7 8 |
| 583 | } { |
| 584 | 2 3 |
| 585 | } { |
| 586 | 2b 3b 4b 5b 6b 7 8 |
| 587 | } { |
| 588 | > 2 3 = 2b 3b 4b 5b 6b 7 8 < |
| 589 | } |
| 590 | |
| 591 | merge-test 100 { |
| 592 | 1 2 3 4 5 6 7 8 9 |
| 593 | } { |
| @@ -620,16 +622,16 @@ | |
| 620 | } { |
| 621 | 1 2 3 4 5 7 8 9b |
| 622 | } { |
| 623 | 1 2 3 4 5 7 8 9b a b c d e |
| 624 | } { |
| 625 | 1 2 3 4 5 7 8 > 9b = 9b a b c d e < |
| 626 | } |
| 627 | merge-test 104 { |
| 628 | 1 2 3 4 5 6 7 8 9 |
| 629 | } { |
| 630 | 1 2 3 4 5 7 8 9b a b c d e |
| 631 | } { |
| 632 | 1 2 3 4 5 7 8 9b |
| 633 | } { |
| 634 | 1 2 3 4 5 7 8 > 9b a b c d e = 9b < |
| 635 | } |
| 636 |
| --- test/merge3.test | |
| +++ test/merge3.test | |
| @@ -22,13 +22,15 @@ | |
| 22 | write_file t1 [join [string trim $basis] \n]\n |
| 23 | write_file t2 [join [string trim $v1] \n]\n |
| 24 | write_file t3 [join [string trim $v2] \n]\n |
| 25 | fossil test-3-way-merge t1 t2 t3 t4 |
| 26 | set x [read_file t4] |
| 27 | regsub -all {<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <+} $x \ |
| 28 | {MINE:} x |
| 29 | regsub -all {======= COMMON ANCESTOR content follows =+} $x {COM:} x |
| 30 | regsub -all {======= MERGED IN content follows =+} $x {YOURS:} x |
| 31 | regsub -all {>>>>>>> END MERGE CONFLICT >+} $x {END} x |
| 32 | set x [split [string trim $x] \n] |
| 33 | set result [string trim $result] |
| 34 | if {$x!=$result} { |
| 35 | protOut " Expected \[$result\]" |
| 36 | protOut " Got \[$x\]" |
| @@ -62,56 +64,56 @@ | |
| 64 | } { |
| 65 | 1 2 3b 4b 5b 6 7 8 9 |
| 66 | } { |
| 67 | 1 2 3 4 5c 6 7 8 9 |
| 68 | } { |
| 69 | 1 2 MINE: 3b 4b 5b COM: 3 4 5 YOURS: 3 4 5c END 6 7 8 9 |
| 70 | } |
| 71 | merge-test 4 { |
| 72 | 1 2 3 4 5 6 7 8 9 |
| 73 | } { |
| 74 | 1 2 3b 4b 5b 6b 7 8 9 |
| 75 | } { |
| 76 | 1 2 3 4 5c 6 7 8 9 |
| 77 | } { |
| 78 | 1 2 MINE: 3b 4b 5b 6b COM: 3 4 5 6 YOURS: 3 4 5c 6 END 7 8 9 |
| 79 | } |
| 80 | merge-test 5 { |
| 81 | 1 2 3 4 5 6 7 8 9 |
| 82 | } { |
| 83 | 1 2 3b 4b 5b 6b 7 8 9 |
| 84 | } { |
| 85 | 1 2 3 4 5c 6c 7c 8 9 |
| 86 | } { |
| 87 | 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8 9 |
| 88 | } |
| 89 | merge-test 6 { |
| 90 | 1 2 3 4 5 6 7 8 9 |
| 91 | } { |
| 92 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 93 | } { |
| 94 | 1 2 3 4 5c 6c 7c 8 9 |
| 95 | } { |
| 96 | 1 2 MINE: 3b 4b 5b 6b 7 COM: 3 4 5 6 7 YOURS: 3 4 5c 6c 7c END 8b 9 |
| 97 | } |
| 98 | merge-test 7 { |
| 99 | 1 2 3 4 5 6 7 8 9 |
| 100 | } { |
| 101 | 1 2 3b 4b 5b 6b 7 8b 9 |
| 102 | } { |
| 103 | 1 2 3 4 5c 6c 7c 8c 9 |
| 104 | } { |
| 105 | 1 2 MINE: 3b 4b 5b 6b 7 8b COM: 3 4 5 6 7 8 YOURS: 3 4 5c 6c 7c 8c END 9 |
| 106 | } |
| 107 | merge-test 8 { |
| 108 | 1 2 3 4 5 6 7 8 9 |
| 109 | } { |
| 110 | 1 2 3b 4b 5b 6b 7 8b 9b |
| 111 | } { |
| 112 | 1 2 3 4 5c 6c 7c 8c 9 |
| 113 | } { |
| 114 | 1 2 MINE: 3b 4b 5b 6b 7 8b 9b COM: 3 4 5 6 7 8 9 YOURS: 3 4 5c 6c 7c 8c 9 END |
| 115 | } |
| 116 | merge-test 9 { |
| 117 | 1 2 3 4 5 6 7 8 9 |
| 118 | } { |
| 119 | 1 2 3b 4b 5 6 7 8b 9b |
| @@ -135,11 +137,11 @@ | |
| 137 | } { |
| 138 | 1 2 3b 4b 5 6 7 8b 9b |
| 139 | } { |
| 140 | 1 2 3b 4c 5 6c 7c 8 9 |
| 141 | } { |
| 142 | 1 2 MINE: 3b 4b COM: 3 4 YOURS: 3b 4c END 5 6c 7c 8b 9b |
| 143 | } |
| 144 | merge-test 12 { |
| 145 | 1 2 3 4 5 6 7 8 9 |
| 146 | } { |
| 147 | 1 2 3b4b 5 6 7 8b 9b |
| @@ -190,20 +192,20 @@ | |
| 192 | } { |
| 193 | 1 6 7 8 9 |
| 194 | } { |
| 195 | 1 2 3 4 9 |
| 196 | } { |
| 197 | 1 MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 |
| 198 | } |
| 199 | merge-test 25 { |
| 200 | 1 2 3 4 5 6 7 8 9 |
| 201 | } { |
| 202 | 1 7 8 9 |
| 203 | } { |
| 204 | 1 2 3 9 |
| 205 | } { |
| 206 | 1 MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 |
| 207 | } |
| 208 | |
| 209 | merge-test 30 { |
| 210 | 1 2 3 4 5 6 7 8 9 |
| 211 | } { |
| @@ -245,20 +247,20 @@ | |
| 247 | } { |
| 248 | 1 2 3 4 9 |
| 249 | } { |
| 250 | 1 6 7 8 9 |
| 251 | } { |
| 252 | 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END 9 |
| 253 | } |
| 254 | merge-test 35 { |
| 255 | 1 2 3 4 5 6 7 8 9 |
| 256 | } { |
| 257 | 1 2 3 9 |
| 258 | } { |
| 259 | 1 7 8 9 |
| 260 | } { |
| 261 | 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END 9 |
| 262 | } |
| 263 | |
| 264 | merge-test 40 { |
| 265 | 2 3 4 5 6 7 8 |
| 266 | } { |
| @@ -300,20 +302,20 @@ | |
| 302 | } { |
| 303 | 6 7 8 |
| 304 | } { |
| 305 | 2 3 4 |
| 306 | } { |
| 307 | MINE: 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END |
| 308 | } |
| 309 | merge-test 45 { |
| 310 | 2 3 4 5 6 7 8 |
| 311 | } { |
| 312 | 7 8 |
| 313 | } { |
| 314 | 2 3 |
| 315 | } { |
| 316 | MINE: 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END |
| 317 | } |
| 318 | |
| 319 | merge-test 50 { |
| 320 | 2 3 4 5 6 7 8 |
| 321 | } { |
| @@ -354,20 +356,20 @@ | |
| 356 | } { |
| 357 | 2 3 4 |
| 358 | } { |
| 359 | 6 7 8 |
| 360 | } { |
| 361 | MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 6 7 8 END |
| 362 | } |
| 363 | merge-test 55 { |
| 364 | 2 3 4 5 6 7 8 |
| 365 | } { |
| 366 | 2 3 |
| 367 | } { |
| 368 | 7 8 |
| 369 | } { |
| 370 | MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 7 8 END |
| 371 | } |
| 372 | |
| 373 | merge-test 60 { |
| 374 | 1 2 3 4 5 6 7 8 9 |
| 375 | } { |
| @@ -409,20 +411,20 @@ | |
| 411 | } { |
| 412 | 1 2b 3b 4b 5b 6 7 8 9 |
| 413 | } { |
| 414 | 1 2 3 4 9 |
| 415 | } { |
| 416 | 1 MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END 9 |
| 417 | } |
| 418 | merge-test 65 { |
| 419 | 1 2 3 4 5 6 7 8 9 |
| 420 | } { |
| 421 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 422 | } { |
| 423 | 1 2 3 9 |
| 424 | } { |
| 425 | 1 MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END 9 |
| 426 | } |
| 427 | |
| 428 | merge-test 70 { |
| 429 | 1 2 3 4 5 6 7 8 9 |
| 430 | } { |
| @@ -464,20 +466,20 @@ | |
| 466 | } { |
| 467 | 1 2 3 4 9 |
| 468 | } { |
| 469 | 1 2b 3b 4b 5b 6 7 8 9 |
| 470 | } { |
| 471 | 1 MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END 9 |
| 472 | } |
| 473 | merge-test 75 { |
| 474 | 1 2 3 4 5 6 7 8 9 |
| 475 | } { |
| 476 | 1 2 3 9 |
| 477 | } { |
| 478 | 1 2b 3b 4b 5b 6b 7 8 9 |
| 479 | } { |
| 480 | 1 MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END 9 |
| 481 | } |
| 482 | |
| 483 | merge-test 80 { |
| 484 | 2 3 4 5 6 7 8 |
| 485 | } { |
| @@ -519,20 +521,20 @@ | |
| 521 | } { |
| 522 | 2b 3b 4b 5b 6 7 8 |
| 523 | } { |
| 524 | 2 3 4 |
| 525 | } { |
| 526 | MINE: 2b 3b 4b 5b 6 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 4 END |
| 527 | } |
| 528 | merge-test 85 { |
| 529 | 2 3 4 5 6 7 8 |
| 530 | } { |
| 531 | 2b 3b 4b 5b 6b 7 8 |
| 532 | } { |
| 533 | 2 3 |
| 534 | } { |
| 535 | MINE: 2b 3b 4b 5b 6b 7 8 COM: 2 3 4 5 6 7 8 YOURS: 2 3 END |
| 536 | } |
| 537 | |
| 538 | merge-test 90 { |
| 539 | 2 3 4 5 6 7 8 |
| 540 | } { |
| @@ -574,20 +576,20 @@ | |
| 576 | } { |
| 577 | 2 3 4 |
| 578 | } { |
| 579 | 2b 3b 4b 5b 6 7 8 |
| 580 | } { |
| 581 | MINE: 2 3 4 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6 7 8 END |
| 582 | } |
| 583 | merge-test 95 { |
| 584 | 2 3 4 5 6 7 8 |
| 585 | } { |
| 586 | 2 3 |
| 587 | } { |
| 588 | 2b 3b 4b 5b 6b 7 8 |
| 589 | } { |
| 590 | MINE: 2 3 COM: 2 3 4 5 6 7 8 YOURS: 2b 3b 4b 5b 6b 7 8 END |
| 591 | } |
| 592 | |
| 593 | merge-test 100 { |
| 594 | 1 2 3 4 5 6 7 8 9 |
| 595 | } { |
| @@ -620,16 +622,16 @@ | |
| 622 | } { |
| 623 | 1 2 3 4 5 7 8 9b |
| 624 | } { |
| 625 | 1 2 3 4 5 7 8 9b a b c d e |
| 626 | } { |
| 627 | 1 2 3 4 5 7 8 MINE: 9b COM: 9 YOURS: 9b a b c d e END |
| 628 | } |
| 629 | merge-test 104 { |
| 630 | 1 2 3 4 5 6 7 8 9 |
| 631 | } { |
| 632 | 1 2 3 4 5 7 8 9b a b c d e |
| 633 | } { |
| 634 | 1 2 3 4 5 7 8 9b |
| 635 | } { |
| 636 | 1 2 3 4 5 7 8 MINE: 9b a b c d e COM: 9 YOURS: 9b END |
| 637 | } |
| 638 |
+1
-1
| --- win/Makefile.PellesCGMake | ||
| +++ win/Makefile.PellesCGMake | ||
| @@ -61,11 +61,11 @@ | ||
| 61 | 61 | |
| 62 | 62 | # define standard C-compiler and flags, used to compile |
| 63 | 63 | # the fossil binary. Some special definitions follow for |
| 64 | 64 | # special files follow |
| 65 | 65 | CC=$(PellesCDir)\bin\pocc.exe |
| 66 | -DEFINES=-DFOSSIL_I18N=0 -D_pgmptr=g.argv[0] | |
| 66 | +DEFINES=-D_pgmptr=g.argv[0] | |
| 67 | 67 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 68 | 68 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 69 | 69 | |
| 70 | 70 | # define commands for building the windows resource files |
| 71 | 71 | RESOURCE=fossil.res |
| 72 | 72 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -61,11 +61,11 @@ | |
| 61 | |
| 62 | # define standard C-compiler and flags, used to compile |
| 63 | # the fossil binary. Some special definitions follow for |
| 64 | # special files follow |
| 65 | CC=$(PellesCDir)\bin\pocc.exe |
| 66 | DEFINES=-DFOSSIL_I18N=0 -D_pgmptr=g.argv[0] |
| 67 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 68 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 69 | |
| 70 | # define commands for building the windows resource files |
| 71 | RESOURCE=fossil.res |
| 72 |
| --- win/Makefile.PellesCGMake | |
| +++ win/Makefile.PellesCGMake | |
| @@ -61,11 +61,11 @@ | |
| 61 | |
| 62 | # define standard C-compiler and flags, used to compile |
| 63 | # the fossil binary. Some special definitions follow for |
| 64 | # special files follow |
| 65 | CC=$(PellesCDir)\bin\pocc.exe |
| 66 | DEFINES=-D_pgmptr=g.argv[0] |
| 67 | CCFLAGS=-T$(TARGETMACHINE_CC)-coff -Ot -W2 -Gd -Go -Ze -MT $(DEFINES) |
| 68 | INCLUDE=/I $(PellesCDir)\Include\Win /I $(PellesCDir)\Include /I $(ZLIBSRCDIR) /I $(SRCDIR) |
| 69 | |
| 70 | # define commands for building the windows resource files |
| 71 | RESOURCE=fossil.res |
| 72 |
+11
-7
| --- win/Makefile.dmc | ||
| +++ win/Makefile.dmc | ||
| @@ -15,22 +15,20 @@ | ||
| 15 | 15 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 16 | 16 | |
| 17 | 17 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 18 | 18 | SSL = |
| 19 | 19 | |
| 20 | -I18N = -DFOSSIL_I18N=0 | |
| 21 | - | |
| 22 | 20 | CFLAGS = -o |
| 23 | 21 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 24 | -TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) | |
| 22 | +TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) | |
| 25 | 23 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 26 | 24 | |
| 27 | 25 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 28 | 26 | |
| 29 | -SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 27 | +SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 30 | 28 | |
| 31 | -OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$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)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 29 | +OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$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)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O | |
| 32 | 30 | |
| 33 | 31 | |
| 34 | 32 | RC=$(DMDIR)\bin\rcc |
| 35 | 33 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 36 | 34 | |
| @@ -44,11 +42,11 @@ | ||
| 44 | 42 | |
| 45 | 43 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 46 | 44 | $(RC) $(RCFLAGS) -o$@ $** |
| 47 | 45 | |
| 48 | 46 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 49 | - +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@ | |
| 47 | + +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@ | |
| 50 | 48 | +echo fossil >> $@ |
| 51 | 49 | +echo fossil >> $@ |
| 52 | 50 | +echo $(LIBS) >> $@ |
| 53 | 51 | +echo. >> $@ |
| 54 | 52 | +echo fossil >> $@ |
| @@ -262,10 +260,16 @@ | ||
| 262 | 260 | $(OBJDIR)\finfo$O : finfo_.c finfo.h |
| 263 | 261 | $(TCC) -o$@ -c finfo_.c |
| 264 | 262 | |
| 265 | 263 | finfo_.c : $(SRCDIR)\finfo.c |
| 266 | 264 | +translate$E $** > $@ |
| 265 | + | |
| 266 | +$(OBJDIR)\glob$O : glob_.c glob.h | |
| 267 | + $(TCC) -o$@ -c glob_.c | |
| 268 | + | |
| 269 | +glob_.c : $(SRCDIR)\glob.c | |
| 270 | + +translate$E $** > $@ | |
| 267 | 271 | |
| 268 | 272 | $(OBJDIR)\graph$O : graph_.c graph.h |
| 269 | 273 | $(TCC) -o$@ -c graph_.c |
| 270 | 274 | |
| 271 | 275 | graph_.c : $(SRCDIR)\graph.c |
| @@ -576,7 +580,7 @@ | ||
| 576 | 580 | |
| 577 | 581 | zip_.c : $(SRCDIR)\zip.c |
| 578 | 582 | +translate$E $** > $@ |
| 579 | 583 | |
| 580 | 584 | headers: makeheaders$E page_index.h VERSION.h |
| 581 | - +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h | |
| 585 | + +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h | |
| 582 | 586 | @copy /Y nul: headers |
| 583 | 587 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -15,22 +15,20 @@ | |
| 15 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 16 | |
| 17 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 18 | SSL = |
| 19 | |
| 20 | I18N = -DFOSSIL_I18N=0 |
| 21 | |
| 22 | CFLAGS = -o |
| 23 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 24 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(I18N) $(SSL) $(INCL) |
| 25 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 26 | |
| 27 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 28 | |
| 29 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 30 | |
| 31 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$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)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 32 | |
| 33 | |
| 34 | RC=$(DMDIR)\bin\rcc |
| 35 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 36 | |
| @@ -44,11 +42,11 @@ | |
| 44 | |
| 45 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 46 | $(RC) $(RCFLAGS) -o$@ $** |
| 47 | |
| 48 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 49 | +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@ |
| 50 | +echo fossil >> $@ |
| 51 | +echo fossil >> $@ |
| 52 | +echo $(LIBS) >> $@ |
| 53 | +echo. >> $@ |
| 54 | +echo fossil >> $@ |
| @@ -262,10 +260,16 @@ | |
| 262 | $(OBJDIR)\finfo$O : finfo_.c finfo.h |
| 263 | $(TCC) -o$@ -c finfo_.c |
| 264 | |
| 265 | finfo_.c : $(SRCDIR)\finfo.c |
| 266 | +translate$E $** > $@ |
| 267 | |
| 268 | $(OBJDIR)\graph$O : graph_.c graph.h |
| 269 | $(TCC) -o$@ -c graph_.c |
| 270 | |
| 271 | graph_.c : $(SRCDIR)\graph.c |
| @@ -576,7 +580,7 @@ | |
| 576 | |
| 577 | zip_.c : $(SRCDIR)\zip.c |
| 578 | +translate$E $** > $@ |
| 579 | |
| 580 | headers: makeheaders$E page_index.h VERSION.h |
| 581 | +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h |
| 582 | @copy /Y nul: headers |
| 583 |
| --- win/Makefile.dmc | |
| +++ win/Makefile.dmc | |
| @@ -15,22 +15,20 @@ | |
| 15 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(DMDIR)\extra\include |
| 16 | |
| 17 | #SSL = -DFOSSIL_ENABLE_SSL=1 |
| 18 | SSL = |
| 19 | |
| 20 | CFLAGS = -o |
| 21 | BCC = $(DMDIR)\bin\dmc $(CFLAGS) |
| 22 | TCC = $(DMDIR)\bin\dmc $(CFLAGS) $(DMCDEF) $(SSL) $(INCL) |
| 23 | LIBS = $(DMDIR)\extra\lib\ zlib wsock32 |
| 24 | |
| 25 | SQLITE_OPTIONS = -DSQLITE_OMIT_LOAD_EXTENSION=1 -DSQLITE_THREADSAFE=0 -DSQLITE_DEFAULT_FILE_FORMAT=4 -DSQLITE_ENABLE_STAT2 -Dlocaltime=fossil_localtime -DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 26 | |
| 27 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 28 | |
| 29 | OBJ = $(OBJDIR)\add$O $(OBJDIR)\allrepo$O $(OBJDIR)\attach$O $(OBJDIR)\bag$O $(OBJDIR)\bisect$O $(OBJDIR)\blob$O $(OBJDIR)\branch$O $(OBJDIR)\browse$O $(OBJDIR)\captcha$O $(OBJDIR)\cgi$O $(OBJDIR)\checkin$O $(OBJDIR)\checkout$O $(OBJDIR)\clearsign$O $(OBJDIR)\clone$O $(OBJDIR)\comformat$O $(OBJDIR)\configure$O $(OBJDIR)\content$O $(OBJDIR)\db$O $(OBJDIR)\delta$O $(OBJDIR)\deltacmd$O $(OBJDIR)\descendants$O $(OBJDIR)\diff$O $(OBJDIR)\diffcmd$O $(OBJDIR)\doc$O $(OBJDIR)\encode$O $(OBJDIR)\event$O $(OBJDIR)\export$O $(OBJDIR)\file$O $(OBJDIR)\finfo$O $(OBJDIR)\glob$O $(OBJDIR)\graph$O $(OBJDIR)\gzip$O $(OBJDIR)\http$O $(OBJDIR)\http_socket$O $(OBJDIR)\http_ssl$O $(OBJDIR)\http_transport$O $(OBJDIR)\import$O $(OBJDIR)\info$O $(OBJDIR)\leaf$O $(OBJDIR)\login$O $(OBJDIR)\main$O $(OBJDIR)\manifest$O $(OBJDIR)\md5$O $(OBJDIR)\merge$O $(OBJDIR)\merge3$O $(OBJDIR)\name$O $(OBJDIR)\path$O $(OBJDIR)\pivot$O $(OBJDIR)\popen$O $(OBJDIR)\pqueue$O $(OBJDIR)\printf$O $(OBJDIR)\rebuild$O $(OBJDIR)\report$O $(OBJDIR)\rss$O $(OBJDIR)\schema$O $(OBJDIR)\search$O $(OBJDIR)\setup$O $(OBJDIR)\sha1$O $(OBJDIR)\shun$O $(OBJDIR)\skins$O $(OBJDIR)\sqlcmd$O $(OBJDIR)\stash$O $(OBJDIR)\stat$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)\update$O $(OBJDIR)\url$O $(OBJDIR)\user$O $(OBJDIR)\verify$O $(OBJDIR)\vfile$O $(OBJDIR)\wiki$O $(OBJDIR)\wikiformat$O $(OBJDIR)\winhttp$O $(OBJDIR)\xfer$O $(OBJDIR)\zip$O $(OBJDIR)\shell$O $(OBJDIR)\sqlite3$O $(OBJDIR)\th$O $(OBJDIR)\th_lang$O |
| 30 | |
| 31 | |
| 32 | RC=$(DMDIR)\bin\rcc |
| 33 | RCFLAGS=-32 -w1 -I$(SRCDIR) /D__DMC__ |
| 34 | |
| @@ -44,11 +42,11 @@ | |
| 42 | |
| 43 | $(OBJDIR)\fossil.res: $B\win\fossil.rc |
| 44 | $(RC) $(RCFLAGS) -o$@ $** |
| 45 | |
| 46 | $(OBJDIR)\link: $B\win\Makefile.dmc $(OBJDIR)\fossil.res |
| 47 | +echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip shell sqlite3 th th_lang > $@ |
| 48 | +echo fossil >> $@ |
| 49 | +echo fossil >> $@ |
| 50 | +echo $(LIBS) >> $@ |
| 51 | +echo. >> $@ |
| 52 | +echo fossil >> $@ |
| @@ -262,10 +260,16 @@ | |
| 260 | $(OBJDIR)\finfo$O : finfo_.c finfo.h |
| 261 | $(TCC) -o$@ -c finfo_.c |
| 262 | |
| 263 | finfo_.c : $(SRCDIR)\finfo.c |
| 264 | +translate$E $** > $@ |
| 265 | |
| 266 | $(OBJDIR)\glob$O : glob_.c glob.h |
| 267 | $(TCC) -o$@ -c glob_.c |
| 268 | |
| 269 | glob_.c : $(SRCDIR)\glob.c |
| 270 | +translate$E $** > $@ |
| 271 | |
| 272 | $(OBJDIR)\graph$O : graph_.c graph.h |
| 273 | $(TCC) -o$@ -c graph_.c |
| 274 | |
| 275 | graph_.c : $(SRCDIR)\graph.c |
| @@ -576,7 +580,7 @@ | |
| 580 | |
| 581 | zip_.c : $(SRCDIR)\zip.c |
| 582 | +translate$E $** > $@ |
| 583 | |
| 584 | headers: makeheaders$E page_index.h VERSION.h |
| 585 | +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h |
| 586 | @copy /Y nul: headers |
| 587 |
+12
-2
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -33,11 +33,11 @@ | ||
| 33 | 33 | # will run on the target platform. This is usually the same |
| 34 | 34 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 35 | 35 | # the finished binary for fossil. The BCC compiler above is used |
| 36 | 36 | # for building intermediate code-generator tools. |
| 37 | 37 | # |
| 38 | -TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include | |
| 38 | +TCC = gcc -Os -Wall -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include | |
| 39 | 39 | |
| 40 | 40 | # With HTTPS support |
| 41 | 41 | ifdef FOSSIL_ENABLE_SSL |
| 42 | 42 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 43 | 43 | endif |
| @@ -101,10 +101,11 @@ | ||
| 101 | 101 | $(SRCDIR)/encode.c \ |
| 102 | 102 | $(SRCDIR)/event.c \ |
| 103 | 103 | $(SRCDIR)/export.c \ |
| 104 | 104 | $(SRCDIR)/file.c \ |
| 105 | 105 | $(SRCDIR)/finfo.c \ |
| 106 | + $(SRCDIR)/glob.c \ | |
| 106 | 107 | $(SRCDIR)/graph.c \ |
| 107 | 108 | $(SRCDIR)/gzip.c \ |
| 108 | 109 | $(SRCDIR)/http.c \ |
| 109 | 110 | $(SRCDIR)/http_socket.c \ |
| 110 | 111 | $(SRCDIR)/http_ssl.c \ |
| @@ -184,10 +185,11 @@ | ||
| 184 | 185 | $(OBJDIR)/encode_.c \ |
| 185 | 186 | $(OBJDIR)/event_.c \ |
| 186 | 187 | $(OBJDIR)/export_.c \ |
| 187 | 188 | $(OBJDIR)/file_.c \ |
| 188 | 189 | $(OBJDIR)/finfo_.c \ |
| 190 | + $(OBJDIR)/glob_.c \ | |
| 189 | 191 | $(OBJDIR)/graph_.c \ |
| 190 | 192 | $(OBJDIR)/gzip_.c \ |
| 191 | 193 | $(OBJDIR)/http_.c \ |
| 192 | 194 | $(OBJDIR)/http_socket_.c \ |
| 193 | 195 | $(OBJDIR)/http_ssl_.c \ |
| @@ -267,10 +269,11 @@ | ||
| 267 | 269 | $(OBJDIR)/encode.o \ |
| 268 | 270 | $(OBJDIR)/event.o \ |
| 269 | 271 | $(OBJDIR)/export.o \ |
| 270 | 272 | $(OBJDIR)/file.o \ |
| 271 | 273 | $(OBJDIR)/finfo.o \ |
| 274 | + $(OBJDIR)/glob.o \ | |
| 272 | 275 | $(OBJDIR)/graph.o \ |
| 273 | 276 | $(OBJDIR)/gzip.o \ |
| 274 | 277 | $(OBJDIR)/http.o \ |
| 275 | 278 | $(OBJDIR)/http_socket.o \ |
| 276 | 279 | $(OBJDIR)/http_ssl.o \ |
| @@ -385,11 +388,11 @@ | ||
| 385 | 388 | |
| 386 | 389 | |
| 387 | 390 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 388 | 391 | $(MKINDEX) $(TRANS_SRC) >$@ |
| 389 | 392 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 390 | - $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 393 | + $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h | |
| 391 | 394 | echo Done >$(OBJDIR)/headers |
| 392 | 395 | |
| 393 | 396 | $(OBJDIR)/headers: Makefile |
| 394 | 397 | Makefile: |
| 395 | 398 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -593,10 +596,17 @@ | ||
| 593 | 596 | |
| 594 | 597 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 595 | 598 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 596 | 599 | |
| 597 | 600 | finfo.h: $(OBJDIR)/headers |
| 601 | +$(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(OBJDIR)/translate | |
| 602 | + $(TRANSLATE) $(SRCDIR)/glob.c >$(OBJDIR)/glob_.c | |
| 603 | + | |
| 604 | +$(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h | |
| 605 | + $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c | |
| 606 | + | |
| 607 | +glob.h: $(OBJDIR)/headers | |
| 598 | 608 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 599 | 609 | $(TRANSLATE) $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 600 | 610 | |
| 601 | 611 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 602 | 612 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| 603 | 613 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -33,11 +33,11 @@ | |
| 33 | # will run on the target platform. This is usually the same |
| 34 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 35 | # the finished binary for fossil. The BCC compiler above is used |
| 36 | # for building intermediate code-generator tools. |
| 37 | # |
| 38 | TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include |
| 39 | |
| 40 | # With HTTPS support |
| 41 | ifdef FOSSIL_ENABLE_SSL |
| 42 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 43 | endif |
| @@ -101,10 +101,11 @@ | |
| 101 | $(SRCDIR)/encode.c \ |
| 102 | $(SRCDIR)/event.c \ |
| 103 | $(SRCDIR)/export.c \ |
| 104 | $(SRCDIR)/file.c \ |
| 105 | $(SRCDIR)/finfo.c \ |
| 106 | $(SRCDIR)/graph.c \ |
| 107 | $(SRCDIR)/gzip.c \ |
| 108 | $(SRCDIR)/http.c \ |
| 109 | $(SRCDIR)/http_socket.c \ |
| 110 | $(SRCDIR)/http_ssl.c \ |
| @@ -184,10 +185,11 @@ | |
| 184 | $(OBJDIR)/encode_.c \ |
| 185 | $(OBJDIR)/event_.c \ |
| 186 | $(OBJDIR)/export_.c \ |
| 187 | $(OBJDIR)/file_.c \ |
| 188 | $(OBJDIR)/finfo_.c \ |
| 189 | $(OBJDIR)/graph_.c \ |
| 190 | $(OBJDIR)/gzip_.c \ |
| 191 | $(OBJDIR)/http_.c \ |
| 192 | $(OBJDIR)/http_socket_.c \ |
| 193 | $(OBJDIR)/http_ssl_.c \ |
| @@ -267,10 +269,11 @@ | |
| 267 | $(OBJDIR)/encode.o \ |
| 268 | $(OBJDIR)/event.o \ |
| 269 | $(OBJDIR)/export.o \ |
| 270 | $(OBJDIR)/file.o \ |
| 271 | $(OBJDIR)/finfo.o \ |
| 272 | $(OBJDIR)/graph.o \ |
| 273 | $(OBJDIR)/gzip.o \ |
| 274 | $(OBJDIR)/http.o \ |
| 275 | $(OBJDIR)/http_socket.o \ |
| 276 | $(OBJDIR)/http_ssl.o \ |
| @@ -385,11 +388,11 @@ | |
| 385 | |
| 386 | |
| 387 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 388 | $(MKINDEX) $(TRANS_SRC) >$@ |
| 389 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 390 | $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 391 | echo Done >$(OBJDIR)/headers |
| 392 | |
| 393 | $(OBJDIR)/headers: Makefile |
| 394 | Makefile: |
| 395 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -593,10 +596,17 @@ | |
| 593 | |
| 594 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 595 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 596 | |
| 597 | finfo.h: $(OBJDIR)/headers |
| 598 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 599 | $(TRANSLATE) $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 600 | |
| 601 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 602 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| 603 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -33,11 +33,11 @@ | |
| 33 | # will run on the target platform. This is usually the same |
| 34 | # as BCC, unless you are cross-compiling. This C compiler builds |
| 35 | # the finished binary for fossil. The BCC compiler above is used |
| 36 | # for building intermediate code-generator tools. |
| 37 | # |
| 38 | TCC = gcc -Os -Wall -L$(ZLIBDIR)/lib -I$(ZLIBDIR)/include |
| 39 | |
| 40 | # With HTTPS support |
| 41 | ifdef FOSSIL_ENABLE_SSL |
| 42 | TCC += -static -DFOSSIL_ENABLE_SSL=1 |
| 43 | endif |
| @@ -101,10 +101,11 @@ | |
| 101 | $(SRCDIR)/encode.c \ |
| 102 | $(SRCDIR)/event.c \ |
| 103 | $(SRCDIR)/export.c \ |
| 104 | $(SRCDIR)/file.c \ |
| 105 | $(SRCDIR)/finfo.c \ |
| 106 | $(SRCDIR)/glob.c \ |
| 107 | $(SRCDIR)/graph.c \ |
| 108 | $(SRCDIR)/gzip.c \ |
| 109 | $(SRCDIR)/http.c \ |
| 110 | $(SRCDIR)/http_socket.c \ |
| 111 | $(SRCDIR)/http_ssl.c \ |
| @@ -184,10 +185,11 @@ | |
| 185 | $(OBJDIR)/encode_.c \ |
| 186 | $(OBJDIR)/event_.c \ |
| 187 | $(OBJDIR)/export_.c \ |
| 188 | $(OBJDIR)/file_.c \ |
| 189 | $(OBJDIR)/finfo_.c \ |
| 190 | $(OBJDIR)/glob_.c \ |
| 191 | $(OBJDIR)/graph_.c \ |
| 192 | $(OBJDIR)/gzip_.c \ |
| 193 | $(OBJDIR)/http_.c \ |
| 194 | $(OBJDIR)/http_socket_.c \ |
| 195 | $(OBJDIR)/http_ssl_.c \ |
| @@ -267,10 +269,11 @@ | |
| 269 | $(OBJDIR)/encode.o \ |
| 270 | $(OBJDIR)/event.o \ |
| 271 | $(OBJDIR)/export.o \ |
| 272 | $(OBJDIR)/file.o \ |
| 273 | $(OBJDIR)/finfo.o \ |
| 274 | $(OBJDIR)/glob.o \ |
| 275 | $(OBJDIR)/graph.o \ |
| 276 | $(OBJDIR)/gzip.o \ |
| 277 | $(OBJDIR)/http.o \ |
| 278 | $(OBJDIR)/http_socket.o \ |
| 279 | $(OBJDIR)/http_ssl.o \ |
| @@ -385,11 +388,11 @@ | |
| 388 | |
| 389 | |
| 390 | $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex |
| 391 | $(MKINDEX) $(TRANS_SRC) >$@ |
| 392 | $(OBJDIR)/headers: $(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h |
| 393 | $(MAKEHEADERS) $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.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)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h |
| 394 | echo Done >$(OBJDIR)/headers |
| 395 | |
| 396 | $(OBJDIR)/headers: Makefile |
| 397 | Makefile: |
| 398 | $(OBJDIR)/add_.c: $(SRCDIR)/add.c $(OBJDIR)/translate |
| @@ -593,10 +596,17 @@ | |
| 596 | |
| 597 | $(OBJDIR)/finfo.o: $(OBJDIR)/finfo_.c $(OBJDIR)/finfo.h $(SRCDIR)/config.h |
| 598 | $(XTCC) -o $(OBJDIR)/finfo.o -c $(OBJDIR)/finfo_.c |
| 599 | |
| 600 | finfo.h: $(OBJDIR)/headers |
| 601 | $(OBJDIR)/glob_.c: $(SRCDIR)/glob.c $(OBJDIR)/translate |
| 602 | $(TRANSLATE) $(SRCDIR)/glob.c >$(OBJDIR)/glob_.c |
| 603 | |
| 604 | $(OBJDIR)/glob.o: $(OBJDIR)/glob_.c $(OBJDIR)/glob.h $(SRCDIR)/config.h |
| 605 | $(XTCC) -o $(OBJDIR)/glob.o -c $(OBJDIR)/glob_.c |
| 606 | |
| 607 | glob.h: $(OBJDIR)/headers |
| 608 | $(OBJDIR)/graph_.c: $(SRCDIR)/graph.c $(OBJDIR)/translate |
| 609 | $(TRANSLATE) $(SRCDIR)/graph.c >$(OBJDIR)/graph_.c |
| 610 | |
| 611 | $(OBJDIR)/graph.o: $(OBJDIR)/graph_.c $(OBJDIR)/graph.h $(SRCDIR)/config.h |
| 612 | $(XTCC) -o $(OBJDIR)/graph.o -c $(OBJDIR)/graph_.c |
| 613 |
+11
-7
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -28,23 +28,21 @@ | ||
| 28 | 28 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 29 | 29 | ZLIB = zlib.lib |
| 30 | 30 | |
| 31 | 31 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 32 | 32 | |
| 33 | -I18N = -DFOSSIL_I18N=0 | |
| 34 | - | |
| 35 | 33 | CFLAGS = -nologo -MT -O2 |
| 36 | 34 | BCC = $(CC) $(CFLAGS) |
| 37 | -TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(I18N) $(SSL) $(INCL) | |
| 35 | +TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) | |
| 38 | 36 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 39 | 37 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 40 | 38 | |
| 41 | 39 | SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 42 | 40 | |
| 43 | -SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 41 | +SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c | |
| 44 | 42 | |
| 45 | -OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O | |
| 43 | +OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\glob$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O | |
| 46 | 44 | |
| 47 | 45 | |
| 48 | 46 | APPNAME = $(OX)\fossil$(E) |
| 49 | 47 | |
| 50 | 48 | all: $(OX) $(APPNAME) |
| @@ -52,11 +50,11 @@ | ||
| 52 | 50 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts |
| 53 | 51 | cd $(OX) |
| 54 | 52 | link -LINK -OUT:$@ $(LIBDIR) @linkopts |
| 55 | 53 | |
| 56 | 54 | $(OX)\linkopts: $B\win\Makefile.msc |
| 57 | - echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 55 | + echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ | |
| 58 | 56 | echo $(LIBS) >> $@ |
| 59 | 57 | |
| 60 | 58 | |
| 61 | 59 | |
| 62 | 60 | |
| @@ -273,10 +271,16 @@ | ||
| 273 | 271 | $(OX)\finfo$O : finfo_.c finfo.h |
| 274 | 272 | $(TCC) /Fo$@ -c finfo_.c |
| 275 | 273 | |
| 276 | 274 | finfo_.c : $(SRCDIR)\finfo.c |
| 277 | 275 | translate$E $** > $@ |
| 276 | + | |
| 277 | +$(OX)\glob$O : glob_.c glob.h | |
| 278 | + $(TCC) /Fo$@ -c glob_.c | |
| 279 | + | |
| 280 | +glob_.c : $(SRCDIR)\glob.c | |
| 281 | + translate$E $** > $@ | |
| 278 | 282 | |
| 279 | 283 | $(OX)\graph$O : graph_.c graph.h |
| 280 | 284 | $(TCC) /Fo$@ -c graph_.c |
| 281 | 285 | |
| 282 | 286 | graph_.c : $(SRCDIR)\graph.c |
| @@ -587,7 +591,7 @@ | ||
| 587 | 591 | |
| 588 | 592 | zip_.c : $(SRCDIR)\zip.c |
| 589 | 593 | translate$E $** > $@ |
| 590 | 594 | |
| 591 | 595 | headers: makeheaders$E page_index.h VERSION.h |
| 592 | - makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h | |
| 596 | + makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h | |
| 593 | 597 | @copy /Y nul: headers |
| 594 | 598 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -28,23 +28,21 @@ | |
| 28 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 29 | ZLIB = zlib.lib |
| 30 | |
| 31 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 32 | |
| 33 | I18N = -DFOSSIL_I18N=0 |
| 34 | |
| 35 | CFLAGS = -nologo -MT -O2 |
| 36 | BCC = $(CC) $(CFLAGS) |
| 37 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(I18N) $(SSL) $(INCL) |
| 38 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 39 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 40 | |
| 41 | SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 42 | |
| 43 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 44 | |
| 45 | OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O |
| 46 | |
| 47 | |
| 48 | APPNAME = $(OX)\fossil$(E) |
| 49 | |
| 50 | all: $(OX) $(APPNAME) |
| @@ -52,11 +50,11 @@ | |
| 52 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts |
| 53 | cd $(OX) |
| 54 | link -LINK -OUT:$@ $(LIBDIR) @linkopts |
| 55 | |
| 56 | $(OX)\linkopts: $B\win\Makefile.msc |
| 57 | echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 58 | echo $(LIBS) >> $@ |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| @@ -273,10 +271,16 @@ | |
| 273 | $(OX)\finfo$O : finfo_.c finfo.h |
| 274 | $(TCC) /Fo$@ -c finfo_.c |
| 275 | |
| 276 | finfo_.c : $(SRCDIR)\finfo.c |
| 277 | translate$E $** > $@ |
| 278 | |
| 279 | $(OX)\graph$O : graph_.c graph.h |
| 280 | $(TCC) /Fo$@ -c graph_.c |
| 281 | |
| 282 | graph_.c : $(SRCDIR)\graph.c |
| @@ -587,7 +591,7 @@ | |
| 587 | |
| 588 | zip_.c : $(SRCDIR)\zip.c |
| 589 | translate$E $** > $@ |
| 590 | |
| 591 | headers: makeheaders$E page_index.h VERSION.h |
| 592 | makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h |
| 593 | @copy /Y nul: headers |
| 594 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -28,23 +28,21 @@ | |
| 28 | ZLIBDIR = $(MSCDIR)\extra\lib |
| 29 | ZLIB = zlib.lib |
| 30 | |
| 31 | INCL = -I. -I$(SRCDIR) -I$B\win\include -I$(MSCDIR)\extra\include -I$(ZINCDIR) |
| 32 | |
| 33 | CFLAGS = -nologo -MT -O2 |
| 34 | BCC = $(CC) $(CFLAGS) |
| 35 | TCC = $(CC) -c $(CFLAGS) $(MSCDEF) $(SSL) $(INCL) |
| 36 | LIBS = $(ZLIB) ws2_32.lib $(SSLLIB) |
| 37 | LIBDIR = -LIBPATH:$(MSCDIR)\extra\lib -LIBPATH:$(ZLIBDIR) |
| 38 | |
| 39 | SQLITE_OPTIONS = /DSQLITE_OMIT_LOAD_EXTENSION=1 /DSQLITE_THREADSAFE=0 /DSQLITE_DEFAULT_FILE_FORMAT=4 /DSQLITE_ENABLE_STAT2 /Dlocaltime=fossil_localtime /DSQLITE_ENABLE_LOCKING_STYLE=0 |
| 40 | |
| 41 | SRC = add_.c allrepo_.c attach_.c bag_.c bisect_.c blob_.c branch_.c browse_.c captcha_.c cgi_.c checkin_.c checkout_.c clearsign_.c clone_.c comformat_.c configure_.c content_.c db_.c delta_.c deltacmd_.c descendants_.c diff_.c diffcmd_.c doc_.c encode_.c event_.c export_.c file_.c finfo_.c glob_.c graph_.c gzip_.c http_.c http_socket_.c http_ssl_.c http_transport_.c import_.c info_.c leaf_.c login_.c main_.c manifest_.c md5_.c merge_.c merge3_.c name_.c path_.c pivot_.c popen_.c pqueue_.c printf_.c rebuild_.c report_.c rss_.c schema_.c search_.c setup_.c sha1_.c shun_.c skins_.c sqlcmd_.c stash_.c stat_.c style_.c sync_.c tag_.c tar_.c th_main_.c timeline_.c tkt_.c tktsetup_.c undo_.c update_.c url_.c user_.c verify_.c vfile_.c wiki_.c wikiformat_.c winhttp_.c xfer_.c zip_.c |
| 42 | |
| 43 | OBJ = $(OX)\add$O $(OX)\allrepo$O $(OX)\attach$O $(OX)\bag$O $(OX)\bisect$O $(OX)\blob$O $(OX)\branch$O $(OX)\browse$O $(OX)\captcha$O $(OX)\cgi$O $(OX)\checkin$O $(OX)\checkout$O $(OX)\clearsign$O $(OX)\clone$O $(OX)\comformat$O $(OX)\configure$O $(OX)\content$O $(OX)\db$O $(OX)\delta$O $(OX)\deltacmd$O $(OX)\descendants$O $(OX)\diff$O $(OX)\diffcmd$O $(OX)\doc$O $(OX)\encode$O $(OX)\event$O $(OX)\export$O $(OX)\file$O $(OX)\finfo$O $(OX)\glob$O $(OX)\graph$O $(OX)\gzip$O $(OX)\http$O $(OX)\http_socket$O $(OX)\http_ssl$O $(OX)\http_transport$O $(OX)\import$O $(OX)\info$O $(OX)\leaf$O $(OX)\login$O $(OX)\main$O $(OX)\manifest$O $(OX)\md5$O $(OX)\merge$O $(OX)\merge3$O $(OX)\name$O $(OX)\path$O $(OX)\pivot$O $(OX)\popen$O $(OX)\pqueue$O $(OX)\printf$O $(OX)\rebuild$O $(OX)\report$O $(OX)\rss$O $(OX)\schema$O $(OX)\search$O $(OX)\setup$O $(OX)\sha1$O $(OX)\shun$O $(OX)\skins$O $(OX)\sqlcmd$O $(OX)\stash$O $(OX)\stat$O $(OX)\style$O $(OX)\sync$O $(OX)\tag$O $(OX)\tar$O $(OX)\th_main$O $(OX)\timeline$O $(OX)\tkt$O $(OX)\tktsetup$O $(OX)\undo$O $(OX)\update$O $(OX)\url$O $(OX)\user$O $(OX)\verify$O $(OX)\vfile$O $(OX)\wiki$O $(OX)\wikiformat$O $(OX)\winhttp$O $(OX)\xfer$O $(OX)\zip$O $(OX)\shell$O $(OX)\sqlite3$O $(OX)\th$O $(OX)\th_lang$O |
| 44 | |
| 45 | |
| 46 | APPNAME = $(OX)\fossil$(E) |
| 47 | |
| 48 | all: $(OX) $(APPNAME) |
| @@ -52,11 +50,11 @@ | |
| 50 | $(APPNAME) : translate$E mkindex$E headers $(OBJ) $(OX)\linkopts |
| 51 | cd $(OX) |
| 52 | link -LINK -OUT:$@ $(LIBDIR) @linkopts |
| 53 | |
| 54 | $(OX)\linkopts: $B\win\Makefile.msc |
| 55 | echo add allrepo attach bag bisect blob branch browse captcha cgi checkin checkout clearsign clone comformat configure content db delta deltacmd descendants diff diffcmd doc encode event export file finfo glob graph gzip http http_socket http_ssl http_transport import info leaf login main manifest md5 merge merge3 name path pivot popen pqueue printf rebuild report rss schema search setup sha1 shun skins sqlcmd stash stat style sync tag tar th_main timeline tkt tktsetup undo update url user verify vfile wiki wikiformat winhttp xfer zip sqlite3 th th_lang > $@ |
| 56 | echo $(LIBS) >> $@ |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| @@ -273,10 +271,16 @@ | |
| 271 | $(OX)\finfo$O : finfo_.c finfo.h |
| 272 | $(TCC) /Fo$@ -c finfo_.c |
| 273 | |
| 274 | finfo_.c : $(SRCDIR)\finfo.c |
| 275 | translate$E $** > $@ |
| 276 | |
| 277 | $(OX)\glob$O : glob_.c glob.h |
| 278 | $(TCC) /Fo$@ -c glob_.c |
| 279 | |
| 280 | glob_.c : $(SRCDIR)\glob.c |
| 281 | translate$E $** > $@ |
| 282 | |
| 283 | $(OX)\graph$O : graph_.c graph.h |
| 284 | $(TCC) /Fo$@ -c graph_.c |
| 285 | |
| 286 | graph_.c : $(SRCDIR)\graph.c |
| @@ -587,7 +591,7 @@ | |
| 591 | |
| 592 | zip_.c : $(SRCDIR)\zip.c |
| 593 | translate$E $** > $@ |
| 594 | |
| 595 | headers: makeheaders$E page_index.h VERSION.h |
| 596 | makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.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 leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.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 update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h |
| 597 | @copy /Y nul: headers |
| 598 |
| --- www/fossil_logo_small.gif | ||
| +++ www/fossil_logo_small.gif | ||
| cannot compute difference between binary files | ||
| 1 | 1 |
| --- www/fossil_logo_small.gif | |
| +++ www/fossil_logo_small.gif | |
| 0 | annot compute difference between binary files |
| 1 |
| --- www/fossil_logo_small.gif | |
| +++ www/fossil_logo_small.gif | |
| 0 | annot compute difference between binary files |
| 1 |
+52
-26
| --- www/mkdownload.tcl | ||
| +++ www/mkdownload.tcl | ||
| @@ -1,11 +1,13 @@ | ||
| 1 | 1 | #!/usr/bin/tclsh |
| 2 | 2 | # |
| 3 | -# Run this script to build the "download.html" page on standard output. | |
| 3 | +# Run this script to build the "download.html" page. Also generate | |
| 4 | +# the fossil_download_checksums.html page. | |
| 4 | 5 | # |
| 5 | 6 | # |
| 6 | -puts \ | |
| 7 | +set out [open download.html w] | |
| 8 | +puts $out \ | |
| 7 | 9 | {<html> |
| 8 | 10 | <head> |
| 9 | 11 | <title>Fossil: Downloads</title> |
| 10 | 12 | <link rel="stylesheet" href="/fossil/style.css" type="text/css" |
| 11 | 13 | media="screen"> |
| @@ -22,14 +24,17 @@ | ||
| 22 | 24 | <p> |
| 23 | 25 | |
| 24 | 26 | <center><font size=4> |
| 25 | 27 | <b>To install Fossil →</b> download the stand-alone executable |
| 26 | 28 | and put it on your $PATH. |
| 27 | -</font><p> | |
| 29 | +</font><p><small> | |
| 28 | 30 | RPMs available |
| 29 | 31 | <a href="http://download.opensuse.org/repositories/home:/rmax:/fossil/"> |
| 30 | -here</a> | |
| 32 | +here.</a> | |
| 33 | +Cryptographic checksums for download files are | |
| 34 | +<a href="http://www.hwaci.com/fossil_download_checksums.html">here</a>. | |
| 35 | +</small></p> | |
| 31 | 36 | </center> |
| 32 | 37 | |
| 33 | 38 | <table cellpadding="10"> |
| 34 | 39 | } |
| 35 | 40 | |
| @@ -49,13 +54,13 @@ | ||
| 49 | 54 | append dt "[string range $datetime 6 7] " |
| 50 | 55 | append dt "[string range $datetime 8 9]:[string range $datetime 10 11]:" |
| 51 | 56 | append dt "[string range $datetime 12 13]" |
| 52 | 57 | set link [string map {{ } +} $dt] |
| 53 | 58 | set hr http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci |
| 54 | - puts "<tr><td colspan=6 align=left><hr>" | |
| 55 | - puts "<center><b><a href=\"$hr\">$dt</a></b></center>" | |
| 56 | - puts "</td></tr>" | |
| 59 | + puts $out "<tr><td colspan=6 align=left><hr>" | |
| 60 | + puts $out "<center><b><a href=\"$hr\">$dt</a></b></center>" | |
| 61 | + puts $out "</td></tr>" | |
| 57 | 62 | |
| 58 | 63 | foreach {prefix suffix img desc} { |
| 59 | 64 | fossil-linux-x86 zip linux.gif {Linux x86} |
| 60 | 65 | fossil-linux-amd64 zip linux64.gif {Linux x86_64} |
| 61 | 66 | fossil-macosx-x86 zip mac.gif {Mac 10.5 x86} |
| @@ -72,27 +77,48 @@ | ||
| 72 | 77 | set units MiB |
| 73 | 78 | } elseif {$size>1024} { |
| 74 | 79 | set size [format %.2f [expr {$size/(1024.0)}]] |
| 75 | 80 | set units KiB |
| 76 | 81 | } |
| 77 | - puts "<td align=center valign=bottom><a href=\"$filename\">" | |
| 78 | - puts "<img src=\"build-icons/$img\" border=0><br>$desc</a><br>" | |
| 79 | - puts "$size $units</td>" | |
| 80 | - } else { | |
| 81 | - puts "<td> </td>" | |
| 82 | - } | |
| 83 | - } | |
| 84 | - puts "</tr>" | |
| 85 | - if {[file exists download/releasenotes-$datetime.html]} { | |
| 86 | - puts "<tr><td colspan=6 align=left>" | |
| 87 | - set rn [open download/releasenotes-$datetime.html] | |
| 88 | - puts "[read $rn]" | |
| 89 | - close $rn | |
| 90 | - puts "</td></tr>" | |
| 91 | - } | |
| 92 | -} | |
| 93 | -puts "<tr><td colspan=5><hr></td></tr>" | |
| 94 | - | |
| 95 | -puts {</table> | |
| 82 | + puts $out "<td align=center valign=bottom><a href=\"$filename\">" | |
| 83 | + puts $out "<img src=\"build-icons/$img\" border=0><br>$desc</a><br>" | |
| 84 | + puts $out "$size $units</td>" | |
| 85 | + } else { | |
| 86 | + puts $out "<td> </td>" | |
| 87 | + } | |
| 88 | + } | |
| 89 | + puts $out "</tr>" | |
| 90 | + if {[file exists download/releasenotes-$datetime.html]} { | |
| 91 | + puts $out "<tr><td colspan=6 align=left>" | |
| 92 | + set rn [open download/releasenotes-$datetime.html] | |
| 93 | + puts $out "[read $rn]" | |
| 94 | + close $rn | |
| 95 | + puts $out "</td></tr>" | |
| 96 | + } | |
| 97 | +} | |
| 98 | +puts $out "<tr><td colspan=5><hr></td></tr>" | |
| 99 | + | |
| 100 | +puts $out {</table> | |
| 96 | 101 | </body> |
| 97 | 102 | </html> |
| 98 | 103 | } |
| 104 | + | |
| 105 | +close $out | |
| 106 | + | |
| 107 | +# Generate the checksum page | |
| 108 | +# | |
| 109 | +set out [open fossil_download_checksums.html w] | |
| 110 | +puts $out {<html> | |
| 111 | +<title>Fossil Download Checksums</title> | |
| 112 | +<body> | |
| 113 | +<h1 align="center">Checksums For Fossil Downloads</h1> | |
| 114 | +<p>The following table shows the SHA1 checksums for the precompiled | |
| 115 | +binaries available on the | |
| 116 | +<a href="http://www.fossil-scm.org/download.html">Fossil website</a>.</p> | |
| 117 | +<pre>} | |
| 118 | + | |
| 119 | +foreach file [lsort [glob -nocomplain download/fossil-*.zip]] { | |
| 120 | + set sha1sum [lindex [exec sha1sum $file] 0] | |
| 121 | + puts $out "$sha1sum [file tail $file]" | |
| 122 | +} | |
| 123 | +puts $out {</pre></body></html} | |
| 124 | +close $out | |
| 99 | 125 |
| --- www/mkdownload.tcl | |
| +++ www/mkdownload.tcl | |
| @@ -1,11 +1,13 @@ | |
| 1 | #!/usr/bin/tclsh |
| 2 | # |
| 3 | # Run this script to build the "download.html" page on standard output. |
| 4 | # |
| 5 | # |
| 6 | puts \ |
| 7 | {<html> |
| 8 | <head> |
| 9 | <title>Fossil: Downloads</title> |
| 10 | <link rel="stylesheet" href="/fossil/style.css" type="text/css" |
| 11 | media="screen"> |
| @@ -22,14 +24,17 @@ | |
| 22 | <p> |
| 23 | |
| 24 | <center><font size=4> |
| 25 | <b>To install Fossil →</b> download the stand-alone executable |
| 26 | and put it on your $PATH. |
| 27 | </font><p> |
| 28 | RPMs available |
| 29 | <a href="http://download.opensuse.org/repositories/home:/rmax:/fossil/"> |
| 30 | here</a> |
| 31 | </center> |
| 32 | |
| 33 | <table cellpadding="10"> |
| 34 | } |
| 35 | |
| @@ -49,13 +54,13 @@ | |
| 49 | append dt "[string range $datetime 6 7] " |
| 50 | append dt "[string range $datetime 8 9]:[string range $datetime 10 11]:" |
| 51 | append dt "[string range $datetime 12 13]" |
| 52 | set link [string map {{ } +} $dt] |
| 53 | set hr http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci |
| 54 | puts "<tr><td colspan=6 align=left><hr>" |
| 55 | puts "<center><b><a href=\"$hr\">$dt</a></b></center>" |
| 56 | puts "</td></tr>" |
| 57 | |
| 58 | foreach {prefix suffix img desc} { |
| 59 | fossil-linux-x86 zip linux.gif {Linux x86} |
| 60 | fossil-linux-amd64 zip linux64.gif {Linux x86_64} |
| 61 | fossil-macosx-x86 zip mac.gif {Mac 10.5 x86} |
| @@ -72,27 +77,48 @@ | |
| 72 | set units MiB |
| 73 | } elseif {$size>1024} { |
| 74 | set size [format %.2f [expr {$size/(1024.0)}]] |
| 75 | set units KiB |
| 76 | } |
| 77 | puts "<td align=center valign=bottom><a href=\"$filename\">" |
| 78 | puts "<img src=\"build-icons/$img\" border=0><br>$desc</a><br>" |
| 79 | puts "$size $units</td>" |
| 80 | } else { |
| 81 | puts "<td> </td>" |
| 82 | } |
| 83 | } |
| 84 | puts "</tr>" |
| 85 | if {[file exists download/releasenotes-$datetime.html]} { |
| 86 | puts "<tr><td colspan=6 align=left>" |
| 87 | set rn [open download/releasenotes-$datetime.html] |
| 88 | puts "[read $rn]" |
| 89 | close $rn |
| 90 | puts "</td></tr>" |
| 91 | } |
| 92 | } |
| 93 | puts "<tr><td colspan=5><hr></td></tr>" |
| 94 | |
| 95 | puts {</table> |
| 96 | </body> |
| 97 | </html> |
| 98 | } |
| 99 |
| --- www/mkdownload.tcl | |
| +++ www/mkdownload.tcl | |
| @@ -1,11 +1,13 @@ | |
| 1 | #!/usr/bin/tclsh |
| 2 | # |
| 3 | # Run this script to build the "download.html" page. Also generate |
| 4 | # the fossil_download_checksums.html page. |
| 5 | # |
| 6 | # |
| 7 | set out [open download.html w] |
| 8 | puts $out \ |
| 9 | {<html> |
| 10 | <head> |
| 11 | <title>Fossil: Downloads</title> |
| 12 | <link rel="stylesheet" href="/fossil/style.css" type="text/css" |
| 13 | media="screen"> |
| @@ -22,14 +24,17 @@ | |
| 24 | <p> |
| 25 | |
| 26 | <center><font size=4> |
| 27 | <b>To install Fossil →</b> download the stand-alone executable |
| 28 | and put it on your $PATH. |
| 29 | </font><p><small> |
| 30 | RPMs available |
| 31 | <a href="http://download.opensuse.org/repositories/home:/rmax:/fossil/"> |
| 32 | here.</a> |
| 33 | Cryptographic checksums for download files are |
| 34 | <a href="http://www.hwaci.com/fossil_download_checksums.html">here</a>. |
| 35 | </small></p> |
| 36 | </center> |
| 37 | |
| 38 | <table cellpadding="10"> |
| 39 | } |
| 40 | |
| @@ -49,13 +54,13 @@ | |
| 54 | append dt "[string range $datetime 6 7] " |
| 55 | append dt "[string range $datetime 8 9]:[string range $datetime 10 11]:" |
| 56 | append dt "[string range $datetime 12 13]" |
| 57 | set link [string map {{ } +} $dt] |
| 58 | set hr http://www.fossil-scm.org/fossil/timeline?c=$link&y=ci |
| 59 | puts $out "<tr><td colspan=6 align=left><hr>" |
| 60 | puts $out "<center><b><a href=\"$hr\">$dt</a></b></center>" |
| 61 | puts $out "</td></tr>" |
| 62 | |
| 63 | foreach {prefix suffix img desc} { |
| 64 | fossil-linux-x86 zip linux.gif {Linux x86} |
| 65 | fossil-linux-amd64 zip linux64.gif {Linux x86_64} |
| 66 | fossil-macosx-x86 zip mac.gif {Mac 10.5 x86} |
| @@ -72,27 +77,48 @@ | |
| 77 | set units MiB |
| 78 | } elseif {$size>1024} { |
| 79 | set size [format %.2f [expr {$size/(1024.0)}]] |
| 80 | set units KiB |
| 81 | } |
| 82 | puts $out "<td align=center valign=bottom><a href=\"$filename\">" |
| 83 | puts $out "<img src=\"build-icons/$img\" border=0><br>$desc</a><br>" |
| 84 | puts $out "$size $units</td>" |
| 85 | } else { |
| 86 | puts $out "<td> </td>" |
| 87 | } |
| 88 | } |
| 89 | puts $out "</tr>" |
| 90 | if {[file exists download/releasenotes-$datetime.html]} { |
| 91 | puts $out "<tr><td colspan=6 align=left>" |
| 92 | set rn [open download/releasenotes-$datetime.html] |
| 93 | puts $out "[read $rn]" |
| 94 | close $rn |
| 95 | puts $out "</td></tr>" |
| 96 | } |
| 97 | } |
| 98 | puts $out "<tr><td colspan=5><hr></td></tr>" |
| 99 | |
| 100 | puts $out {</table> |
| 101 | </body> |
| 102 | </html> |
| 103 | } |
| 104 | |
| 105 | close $out |
| 106 | |
| 107 | # Generate the checksum page |
| 108 | # |
| 109 | set out [open fossil_download_checksums.html w] |
| 110 | puts $out {<html> |
| 111 | <title>Fossil Download Checksums</title> |
| 112 | <body> |
| 113 | <h1 align="center">Checksums For Fossil Downloads</h1> |
| 114 | <p>The following table shows the SHA1 checksums for the precompiled |
| 115 | binaries available on the |
| 116 | <a href="http://www.fossil-scm.org/download.html">Fossil website</a>.</p> |
| 117 | <pre>} |
| 118 | |
| 119 | foreach file [lsort [glob -nocomplain download/fossil-*.zip]] { |
| 120 | set sha1sum [lindex [exec sha1sum $file] 0] |
| 121 | puts $out "$sha1sum [file tail $file]" |
| 122 | } |
| 123 | puts $out {</pre></body></html} |
| 124 | close $out |
| 125 |
+1
-1
| --- www/selfhost.wiki | ||
| +++ www/selfhost.wiki | ||
| @@ -58,8 +58,8 @@ | ||
| 58 | 58 | <blockquote><pre> |
| 59 | 59 | /home/hwaci/bin/fossil sync -R /home/hwaci/fossil/fossil.fossil |
| 60 | 60 | </pre></blockquote> |
| 61 | 61 | |
| 62 | 62 | Server (2) is a |
| 63 | -<a href="http://www.linode.com/">Linode 512</a> located in Atlanta, GA | |
| 63 | +<a href="http://www.linode.com/">Linode 512</a> located in Newark, NJ | |
| 64 | 64 | and set up just like the canonical server (1) with the addition of a |
| 65 | 65 | cron job for synchronization as in server (3). |
| 66 | 66 |
| --- www/selfhost.wiki | |
| +++ www/selfhost.wiki | |
| @@ -58,8 +58,8 @@ | |
| 58 | <blockquote><pre> |
| 59 | /home/hwaci/bin/fossil sync -R /home/hwaci/fossil/fossil.fossil |
| 60 | </pre></blockquote> |
| 61 | |
| 62 | Server (2) is a |
| 63 | <a href="http://www.linode.com/">Linode 512</a> located in Atlanta, GA |
| 64 | and set up just like the canonical server (1) with the addition of a |
| 65 | cron job for synchronization as in server (3). |
| 66 |
| --- www/selfhost.wiki | |
| +++ www/selfhost.wiki | |
| @@ -58,8 +58,8 @@ | |
| 58 | <blockquote><pre> |
| 59 | /home/hwaci/bin/fossil sync -R /home/hwaci/fossil/fossil.fossil |
| 60 | </pre></blockquote> |
| 61 | |
| 62 | Server (2) is a |
| 63 | <a href="http://www.linode.com/">Linode 512</a> located in Newark, NJ |
| 64 | and set up just like the canonical server (1) with the addition of a |
| 65 | cron job for synchronization as in server (3). |
| 66 |
+8
-3
| --- www/server.wiki | ||
| +++ www/server.wiki | ||
| @@ -15,11 +15,13 @@ | ||
| 15 | 15 | <p> |
| 16 | 16 | Both of these commands start a Fossil server on port 8080 on the local machine, |
| 17 | 17 | which can be accessed with the URL: <tt>http://localhost:8080/</tt> using any |
| 18 | 18 | handy web browser. The difference between the two commands is that "ui", in |
| 19 | 19 | addition to starting the Fossil server, also starts a web browser and points it |
| 20 | -to the URL mentioned above. | |
| 20 | +to the URL mentioned above. On the other hand, the "ui" command binds to | |
| 21 | +the loopback IP address only (127.0.0.1) so that the "ui" command cannot be | |
| 22 | +used to serve content to a different machine. | |
| 21 | 23 | </p> |
| 22 | 24 | <p> |
| 23 | 25 | NOTES: |
| 24 | 26 | <ol> |
| 25 | 27 | <li>The option "--port NNN" will start the server on port "NNN" instead of 8080. |
| @@ -70,19 +72,22 @@ | ||
| 70 | 72 | </p> |
| 71 | 73 | </blockquote> |
| 72 | 74 | |
| 73 | 75 | <h3>Serving multiple repositories with one script</h3><blockquote> |
| 74 | 76 | <p> |
| 75 | -This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory (call it 'fossils'). So as before, create a script (again, 'repo'): | |
| 77 | +This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory. | |
| 78 | +(Call the directory 'fossils'). All repositories served, in this case, must | |
| 79 | +use the ".fossil" filename suffix. | |
| 80 | +As before, create a script (again, 'repo'): | |
| 76 | 81 | <blockquote><tt> |
| 77 | 82 | #!/path-to/fossil<br> |
| 78 | 83 | directory: /path-to-repo/fossils<br> |
| 79 | 84 | notfound: http://url-to-go-to-if-repo-not-found/ |
| 80 | 85 | </tt></blockquote> |
| 81 | 86 | </p> |
| 82 | 87 | <p> |
| 83 | -Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX" (if it exists). This makes serving multiple projects on one server pretty painless. | |
| 88 | +Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX.fossil" (if it exists). This makes serving multiple projects on one server pretty painless. | |
| 84 | 89 | </p> |
| 85 | 90 | </blockquote> |
| 86 | 91 | |
| 87 | 92 | <h2>Securing a repository with SSL</h2><blockquote> |
| 88 | 93 | <p> |
| 89 | 94 |
| --- www/server.wiki | |
| +++ www/server.wiki | |
| @@ -15,11 +15,13 @@ | |
| 15 | <p> |
| 16 | Both of these commands start a Fossil server on port 8080 on the local machine, |
| 17 | which can be accessed with the URL: <tt>http://localhost:8080/</tt> using any |
| 18 | handy web browser. The difference between the two commands is that "ui", in |
| 19 | addition to starting the Fossil server, also starts a web browser and points it |
| 20 | to the URL mentioned above. |
| 21 | </p> |
| 22 | <p> |
| 23 | NOTES: |
| 24 | <ol> |
| 25 | <li>The option "--port NNN" will start the server on port "NNN" instead of 8080. |
| @@ -70,19 +72,22 @@ | |
| 70 | </p> |
| 71 | </blockquote> |
| 72 | |
| 73 | <h3>Serving multiple repositories with one script</h3><blockquote> |
| 74 | <p> |
| 75 | This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory (call it 'fossils'). So as before, create a script (again, 'repo'): |
| 76 | <blockquote><tt> |
| 77 | #!/path-to/fossil<br> |
| 78 | directory: /path-to-repo/fossils<br> |
| 79 | notfound: http://url-to-go-to-if-repo-not-found/ |
| 80 | </tt></blockquote> |
| 81 | </p> |
| 82 | <p> |
| 83 | Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX" (if it exists). This makes serving multiple projects on one server pretty painless. |
| 84 | </p> |
| 85 | </blockquote> |
| 86 | |
| 87 | <h2>Securing a repository with SSL</h2><blockquote> |
| 88 | <p> |
| 89 |
| --- www/server.wiki | |
| +++ www/server.wiki | |
| @@ -15,11 +15,13 @@ | |
| 15 | <p> |
| 16 | Both of these commands start a Fossil server on port 8080 on the local machine, |
| 17 | which can be accessed with the URL: <tt>http://localhost:8080/</tt> using any |
| 18 | handy web browser. The difference between the two commands is that "ui", in |
| 19 | addition to starting the Fossil server, also starts a web browser and points it |
| 20 | to the URL mentioned above. On the other hand, the "ui" command binds to |
| 21 | the loopback IP address only (127.0.0.1) so that the "ui" command cannot be |
| 22 | used to serve content to a different machine. |
| 23 | </p> |
| 24 | <p> |
| 25 | NOTES: |
| 26 | <ol> |
| 27 | <li>The option "--port NNN" will start the server on port "NNN" instead of 8080. |
| @@ -70,19 +72,22 @@ | |
| 72 | </p> |
| 73 | </blockquote> |
| 74 | |
| 75 | <h3>Serving multiple repositories with one script</h3><blockquote> |
| 76 | <p> |
| 77 | This scenario is almost identical to the previous one. However, here we will assume you have multiple repositories, in one directory. |
| 78 | (Call the directory 'fossils'). All repositories served, in this case, must |
| 79 | use the ".fossil" filename suffix. |
| 80 | As before, create a script (again, 'repo'): |
| 81 | <blockquote><tt> |
| 82 | #!/path-to/fossil<br> |
| 83 | directory: /path-to-repo/fossils<br> |
| 84 | notfound: http://url-to-go-to-if-repo-not-found/ |
| 85 | </tt></blockquote> |
| 86 | </p> |
| 87 | <p> |
| 88 | Once deployed, a URL like: <tt>http://mydomain.org/cgi-bin/repo/XYZ</tt> will serve up the repository "fossils/XYX.fossil" (if it exists). This makes serving multiple projects on one server pretty painless. |
| 89 | </p> |
| 90 | </blockquote> |
| 91 | |
| 92 | <h2>Securing a repository with SSL</h2><blockquote> |
| 93 | <p> |
| 94 |