Fossil SCM

Work on the logic for parsing command-line options to the "bundle export". The same routine might well be useful for other routines, like "timeline".

drh 2014-11-25 20:49 UTC DBP-workflow
Commit 8a57413e825ee1be05390ee123c3cf54e1915294
3 files changed +115 -8 +2 -4 +55 -39
+115 -8
--- src/bundle.c
+++ src/bundle.c
@@ -28,15 +28,15 @@
2828
@ CREATE TABLE IF NOT EXISTS "%w".bconfig(
2929
@ bcname TEXT,
3030
@ bcvalue ANY
3131
@ );
3232
@ CREATE TABLE IF NOT EXISTS "%w".bblob(
33
-@ blobid INTEGER PRIMARY KEY,
34
-@ uuid TEXT NOT NULL,
35
-@ sz INT NOT NULL,
36
-@ delta ANY,
37
-@ data BLOB
33
+@ blobid INTEGER PRIMARY KEY, -- Blob ID
34
+@ uuid TEXT NOT NULL, -- SHA1 hash of expanded blob
35
+@ sz INT NOT NULL, -- Size of blob after expansion
36
+@ delta INT REFERENCES bblob, -- Delta compression basis, or NULL
37
+@ data BLOB -- compressed content
3838
@ );
3939
;
4040
4141
/*
4242
** Attach a bundle file to the current database connection using the
@@ -87,11 +87,120 @@
8787
blob_reset(&hash);
8888
}
8989
db_end_transaction(0);
9090
db_finalize(&q);
9191
}
92
-
92
+
93
+/*
94
+** Identify a subsection of the checkin tree using command-line switches.
95
+** There must be one of the following switch available:
96
+**
97
+** --branch BRANCHNAME All checkins on the most recent
98
+** instance of BRANCHNAME
99
+** --from TAG1 [--to TAG2] Checkin TAG1 and all primary descendants
100
+** up to and including TAG2
101
+** --checkin TAG Checkin TAG only
102
+**
103
+** Store the RIDs for all applicable checkins in the zTab table that
104
+** should already exist. Invoke fossil_fatal() if any kind of error is
105
+** seen.
106
+*/
107
+void subtree_from_arguments(const char *zTab){
108
+ const char *zBr;
109
+ const char *zFrom;
110
+ const char *zTo;
111
+ const char *zCkin;
112
+ int rid, endRid;
113
+
114
+ zBr = find_option("branch",0,1);
115
+ zFrom = find_option("from",0,1);
116
+ zTo = find_option("to",0,1);
117
+ zCkin = find_option("checkin",0,1);
118
+ if( zCkin ){
119
+ if( zFrom ) fossil_fatal("cannot use both --checkin and --from");
120
+ if( zBr ) fossil_fatal("cannot use both --checkin and --branch");
121
+ rid = symbolic_name_to_rid(zCkin, "ci");
122
+ endRid = rid;
123
+ }else{
124
+ endRid = zTo ? name_to_typed_rid(zTo, "ci") : 0;
125
+ }
126
+ if( zFrom ){
127
+ rid = name_to_typed_rid(zFrom, "ci");
128
+ }else if( zBr ){
129
+ rid = name_to_typed_rid(zBr, "br");
130
+ }else if( zCkin==0 ){
131
+ fossil_fatal("need on of: --branch, --from, --checkin");
132
+ }
133
+ db_multi_exec("INSERT OR IGNORE INTO \"%w\" VALUES(%d)", zTab, rid);
134
+ if( rid!=endRid ){
135
+ Blob sql;
136
+ blob_zero(&sql);
137
+ blob_appendf(&sql,
138
+ "WITH RECURSIVE child(rid) AS (VALUES(%d) UNION ALL "
139
+ " SELECT cid FROM plink, child"
140
+ " WHERE plink.pid=child.rid"
141
+ " AND plink.isPrim", rid);
142
+ if( endRid>0 ){
143
+ double endTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d",
144
+ endRid);
145
+ blob_appendf(&sql,
146
+ " AND child.rid!=%d"
147
+ " AND (SELECT mtime FROM event WHERE objid=plink.cid)<=%.17g",
148
+ endRid, endTime
149
+ );
150
+ }
151
+ if( zBr ){
152
+ blob_appendf(&sql,
153
+ " AND EXISTS(SELECT 1 FROM tagxref"
154
+ " WHERE tagid=%d AND tagtype>0"
155
+ " AND value=%Q and rid=plink.cid))",
156
+ TAG_BRANCH, zBr);
157
+ }
158
+ blob_appendf(&sql, ") INSERT OR IGNORE INTO \"%w\" SELECT rid FROM child;",
159
+ zTab);
160
+ db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
161
+ }
162
+}
163
+
164
+/*
165
+** COMMAND: test-subtree
166
+**
167
+** Usage: %fossil test-subtree ?OPTIONS?
168
+**
169
+** Show the subset of checkins that match the supplied options. This
170
+** command is used to test the subtree_from_options() subroutine in the
171
+** implementation and does not really have any other practical use that
172
+** we know of.
173
+**
174
+** Options:
175
+** --branch BRANCH Include only checkins on BRANCH
176
+** --from TAG Start the subtree at TAG
177
+** --to TAG End the subtree at TAG
178
+** --checkin TAG The subtree is the single checkin TAG
179
+*/
180
+void test_subtree_cmd(void){
181
+ Stmt q;
182
+ db_find_and_open_repository(0,0);
183
+ db_begin_transaction();
184
+ db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);");
185
+ subtree_from_arguments("tobundle");
186
+ db_prepare(&q,
187
+ "SELECT "
188
+ " (SELECT substr(uuid,1,10) FROM blob WHERE rid=tobundle.rid),"
189
+ " (SELECT substr(comment,1,30) FROM event WHERE objid=tobundle.rid),"
190
+ " tobundle.rid"
191
+ " FROM tobundle;"
192
+ );
193
+ while( db_step(&q)==SQLITE_ROW ){
194
+ fossil_print("%5d %s %s\n",
195
+ db_column_int(&q, 2),
196
+ db_column_text(&q, 0),
197
+ db_column_text(&q, 1));
198
+ }
199
+ db_finalize(&q);
200
+ db_end_transaction(1);
201
+}
93202
94203
/*
95204
** COMMAND: bundle
96205
**
97206
** Usage: %fossil bundle SUBCOMMAND ARGS...
@@ -103,12 +212,10 @@
103212
** as determined by OPTIONS. OPTIONS include:
104213
**
105214
** --branch BRANCH Package all check-ins on BRANCH.
106215
** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2.
107216
** --m COMMENT Add the comment to the bundle.
108
-** --standalone The bundle will not include any deltas
109
-** against files not in the bundle.
110217
** --explain Just explain what would have happened.
111218
**
112219
** fossil bundle import BUNDLE ?--publish? ?--explain?
113220
**
114221
** Import the bundle in file BUNDLE into the repository. The --publish
115222
--- src/bundle.c
+++ src/bundle.c
@@ -28,15 +28,15 @@
28 @ CREATE TABLE IF NOT EXISTS "%w".bconfig(
29 @ bcname TEXT,
30 @ bcvalue ANY
31 @ );
32 @ CREATE TABLE IF NOT EXISTS "%w".bblob(
33 @ blobid INTEGER PRIMARY KEY,
34 @ uuid TEXT NOT NULL,
35 @ sz INT NOT NULL,
36 @ delta ANY,
37 @ data BLOB
38 @ );
39 ;
40
41 /*
42 ** Attach a bundle file to the current database connection using the
@@ -87,11 +87,120 @@
87 blob_reset(&hash);
88 }
89 db_end_transaction(0);
90 db_finalize(&q);
91 }
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
94 /*
95 ** COMMAND: bundle
96 **
97 ** Usage: %fossil bundle SUBCOMMAND ARGS...
@@ -103,12 +212,10 @@
103 ** as determined by OPTIONS. OPTIONS include:
104 **
105 ** --branch BRANCH Package all check-ins on BRANCH.
106 ** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2.
107 ** --m COMMENT Add the comment to the bundle.
108 ** --standalone The bundle will not include any deltas
109 ** against files not in the bundle.
110 ** --explain Just explain what would have happened.
111 **
112 ** fossil bundle import BUNDLE ?--publish? ?--explain?
113 **
114 ** Import the bundle in file BUNDLE into the repository. The --publish
115
--- src/bundle.c
+++ src/bundle.c
@@ -28,15 +28,15 @@
28 @ CREATE TABLE IF NOT EXISTS "%w".bconfig(
29 @ bcname TEXT,
30 @ bcvalue ANY
31 @ );
32 @ CREATE TABLE IF NOT EXISTS "%w".bblob(
33 @ blobid INTEGER PRIMARY KEY, -- Blob ID
34 @ uuid TEXT NOT NULL, -- SHA1 hash of expanded blob
35 @ sz INT NOT NULL, -- Size of blob after expansion
36 @ delta INT REFERENCES bblob, -- Delta compression basis, or NULL
37 @ data BLOB -- compressed content
38 @ );
39 ;
40
41 /*
42 ** Attach a bundle file to the current database connection using the
@@ -87,11 +87,120 @@
87 blob_reset(&hash);
88 }
89 db_end_transaction(0);
90 db_finalize(&q);
91 }
92
93 /*
94 ** Identify a subsection of the checkin tree using command-line switches.
95 ** There must be one of the following switch available:
96 **
97 ** --branch BRANCHNAME All checkins on the most recent
98 ** instance of BRANCHNAME
99 ** --from TAG1 [--to TAG2] Checkin TAG1 and all primary descendants
100 ** up to and including TAG2
101 ** --checkin TAG Checkin TAG only
102 **
103 ** Store the RIDs for all applicable checkins in the zTab table that
104 ** should already exist. Invoke fossil_fatal() if any kind of error is
105 ** seen.
106 */
107 void subtree_from_arguments(const char *zTab){
108 const char *zBr;
109 const char *zFrom;
110 const char *zTo;
111 const char *zCkin;
112 int rid, endRid;
113
114 zBr = find_option("branch",0,1);
115 zFrom = find_option("from",0,1);
116 zTo = find_option("to",0,1);
117 zCkin = find_option("checkin",0,1);
118 if( zCkin ){
119 if( zFrom ) fossil_fatal("cannot use both --checkin and --from");
120 if( zBr ) fossil_fatal("cannot use both --checkin and --branch");
121 rid = symbolic_name_to_rid(zCkin, "ci");
122 endRid = rid;
123 }else{
124 endRid = zTo ? name_to_typed_rid(zTo, "ci") : 0;
125 }
126 if( zFrom ){
127 rid = name_to_typed_rid(zFrom, "ci");
128 }else if( zBr ){
129 rid = name_to_typed_rid(zBr, "br");
130 }else if( zCkin==0 ){
131 fossil_fatal("need on of: --branch, --from, --checkin");
132 }
133 db_multi_exec("INSERT OR IGNORE INTO \"%w\" VALUES(%d)", zTab, rid);
134 if( rid!=endRid ){
135 Blob sql;
136 blob_zero(&sql);
137 blob_appendf(&sql,
138 "WITH RECURSIVE child(rid) AS (VALUES(%d) UNION ALL "
139 " SELECT cid FROM plink, child"
140 " WHERE plink.pid=child.rid"
141 " AND plink.isPrim", rid);
142 if( endRid>0 ){
143 double endTime = db_double(0.0, "SELECT mtime FROM event WHERE objid=%d",
144 endRid);
145 blob_appendf(&sql,
146 " AND child.rid!=%d"
147 " AND (SELECT mtime FROM event WHERE objid=plink.cid)<=%.17g",
148 endRid, endTime
149 );
150 }
151 if( zBr ){
152 blob_appendf(&sql,
153 " AND EXISTS(SELECT 1 FROM tagxref"
154 " WHERE tagid=%d AND tagtype>0"
155 " AND value=%Q and rid=plink.cid))",
156 TAG_BRANCH, zBr);
157 }
158 blob_appendf(&sql, ") INSERT OR IGNORE INTO \"%w\" SELECT rid FROM child;",
159 zTab);
160 db_multi_exec("%s", blob_str(&sql)/*safe-for-%s*/);
161 }
162 }
163
164 /*
165 ** COMMAND: test-subtree
166 **
167 ** Usage: %fossil test-subtree ?OPTIONS?
168 **
169 ** Show the subset of checkins that match the supplied options. This
170 ** command is used to test the subtree_from_options() subroutine in the
171 ** implementation and does not really have any other practical use that
172 ** we know of.
173 **
174 ** Options:
175 ** --branch BRANCH Include only checkins on BRANCH
176 ** --from TAG Start the subtree at TAG
177 ** --to TAG End the subtree at TAG
178 ** --checkin TAG The subtree is the single checkin TAG
179 */
180 void test_subtree_cmd(void){
181 Stmt q;
182 db_find_and_open_repository(0,0);
183 db_begin_transaction();
184 db_multi_exec("CREATE TEMP TABLE tobundle(rid INTEGER PRIMARY KEY);");
185 subtree_from_arguments("tobundle");
186 db_prepare(&q,
187 "SELECT "
188 " (SELECT substr(uuid,1,10) FROM blob WHERE rid=tobundle.rid),"
189 " (SELECT substr(comment,1,30) FROM event WHERE objid=tobundle.rid),"
190 " tobundle.rid"
191 " FROM tobundle;"
192 );
193 while( db_step(&q)==SQLITE_ROW ){
194 fossil_print("%5d %s %s\n",
195 db_column_int(&q, 2),
196 db_column_text(&q, 0),
197 db_column_text(&q, 1));
198 }
199 db_finalize(&q);
200 db_end_transaction(1);
201 }
202
203 /*
204 ** COMMAND: bundle
205 **
206 ** Usage: %fossil bundle SUBCOMMAND ARGS...
@@ -103,12 +212,10 @@
212 ** as determined by OPTIONS. OPTIONS include:
213 **
214 ** --branch BRANCH Package all check-ins on BRANCH.
215 ** --from TAG1 --to TAG2 Package check-ins between TAG1 and TAG2.
216 ** --m COMMENT Add the comment to the bundle.
 
 
217 ** --explain Just explain what would have happened.
218 **
219 ** fossil bundle import BUNDLE ?--publish? ?--explain?
220 **
221 ** Import the bundle in file BUNDLE into the repository. The --publish
222
+2 -4
--- src/name.c
+++ src/name.c
@@ -413,15 +413,13 @@
413413
int rid;
414414
415415
if( zName==0 || zName[0]==0 ) return 0;
416416
rid = symbolic_name_to_rid(zName, zType);
417417
if( rid<0 ){
418
- fossil_error(1, "ambiguous name: %s", zName);
419
- return 0;
418
+ fossil_fatal("ambiguous name: %s", zName);
420419
}else if( rid==0 ){
421
- fossil_error(1, "not found: %s", zName);
422
- return 0;
420
+ fossil_fatal("not found: %s", zName);
423421
}else{
424422
return rid;
425423
}
426424
}
427425
int name_to_rid(const char *zName){
428426
--- src/name.c
+++ src/name.c
@@ -413,15 +413,13 @@
413 int rid;
414
415 if( zName==0 || zName[0]==0 ) return 0;
416 rid = symbolic_name_to_rid(zName, zType);
417 if( rid<0 ){
418 fossil_error(1, "ambiguous name: %s", zName);
419 return 0;
420 }else if( rid==0 ){
421 fossil_error(1, "not found: %s", zName);
422 return 0;
423 }else{
424 return rid;
425 }
426 }
427 int name_to_rid(const char *zName){
428
--- src/name.c
+++ src/name.c
@@ -413,15 +413,13 @@
413 int rid;
414
415 if( zName==0 || zName[0]==0 ) return 0;
416 rid = symbolic_name_to_rid(zName, zType);
417 if( rid<0 ){
418 fossil_fatal("ambiguous name: %s", zName);
 
419 }else if( rid==0 ){
420 fossil_fatal("not found: %s", zName);
 
421 }else{
422 return rid;
423 }
424 }
425 int name_to_rid(const char *zName){
426
+55 -39
--- src/purge.c
+++ src/purge.c
@@ -79,61 +79,81 @@
7979
** (i) ATTACHMENT
8080
** (j) TICKETCHNG
8181
** (7) If any ticket artifacts were removed (6j) then rebuild the
8282
** corresponding ticket entries. Possibly remove entries from
8383
** the ticket table.
84
+**
85
+** Stops 1-4 (saving the purged artifacts into the graveyard) are only
86
+** undertaken if the moveToGraveyard flag is true.
8487
*/
8588
int purge_artifact_list(
8689
const char *zTab, /* TEMP table containing list of RIDS to be purged */
87
- const char *zNote /* Text of the purgeevent.pnotes field */
90
+ const char *zNote, /* Text of the purgeevent.pnotes field */
91
+ int moveToGraveyard /* Move purged artifacts into the graveyard */
8892
){
8993
int peid = 0; /* New purgeevent ID */
9094
Stmt q; /* General-use prepared statement */
9195
9296
assert( g.repositoryOpen ); /* Main database must already be open */
9397
db_begin_transaction();
98
+
99
+ /* Make sure we are not removing a manifest that is the baseline of some
100
+ ** manifest that is being left behind. This step is not strictly necessary.
101
+ ** is is just a safety check. */
94102
if( purge_baseline_out_from_under_delta(zTab) ){
95103
fossil_fatal("attempt to purge a baseline manifest without also purging "
96104
"all of its deltas");
97105
}
98
- db_multi_exec(zPurgeInit /*works-like:"%w%w"*/,
99
- db_name("repository"), db_name("repository"));
100
- db_multi_exec(
101
- "INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote
102
- );
103
- peid = db_last_insert_rowid();
106
+
107
+ /* Make sure that no delta that is left behind requires a purged artifact
108
+ ** as its basis. If such artifacts exist, go ahead and undelta them now.
109
+ */
104110
db_prepare(&q, "SELECT rid FROM delta WHERE srcid IN \"%w\""
105111
" AND rid NOT IN \"%w\"", zTab, zTab);
106112
while( db_step(&q)==SQLITE_ROW ){
107113
int rid = db_column_int(&q, 0);
108114
content_undelta(rid);
109115
verify_before_commit(rid);
110116
}
111117
db_finalize(&q);
112
- db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\""
113
- " AND srcid NOT IN \"%w\"", zTab, zTab);
114
- while( db_step(&q)==SQLITE_ROW ){
115
- int rid = db_column_int(&q, 0);
116
- content_undelta(rid);
117
- }
118
- db_finalize(&q);
119
- db_multi_exec(
120
- "INSERT INTO purgeitem(peid,orid,uuid,sz,isPrivate,data)"
121
- " SELECT %d, rid, uuid, size,"
122
- " EXISTS(SELECT 1 FROM private WHERE private.rid=blob.rid),"
123
- " content"
124
- " FROM blob WHERE rid IN \"%w\"",
125
- peid, zTab
126
- );
127
- db_multi_exec(
128
- "UPDATE purgeitem"
129
- " SET srcid=(SELECT piid FROM purgeitem px, delta"
130
- " WHERE px.orid=delta.srcid"
131
- " AND delta.rid=purgeitem.orid)"
132
- " WHERE peid=%d",
133
- peid
134
- );
118
+
119
+ /* Construct the graveyard and copy the artifacts to be purged into the
120
+ ** graveyard */
121
+ if( moveToGraveyard ){
122
+ db_multi_exec(zPurgeInit /*works-like:"%w%w"*/,
123
+ db_name("repository"), db_name("repository"));
124
+ db_multi_exec(
125
+ "INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote
126
+ );
127
+ peid = db_last_insert_rowid();
128
+ db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\""
129
+ " AND srcid NOT IN \"%w\"", zTab, zTab);
130
+ while( db_step(&q)==SQLITE_ROW ){
131
+ int rid = db_column_int(&q, 0);
132
+ content_undelta(rid);
133
+ }
134
+ db_finalize(&q);
135
+ db_multi_exec(
136
+ "INSERT INTO purgeitem(peid,orid,uuid,sz,isPrivate,data)"
137
+ " SELECT %d, rid, uuid, size,"
138
+ " EXISTS(SELECT 1 FROM private WHERE private.rid=blob.rid),"
139
+ " content"
140
+ " FROM blob WHERE rid IN \"%w\"",
141
+ peid, zTab
142
+ );
143
+ db_multi_exec(
144
+ "UPDATE purgeitem"
145
+ " SET srcid=(SELECT piid FROM purgeitem px, delta"
146
+ " WHERE px.orid=delta.srcid"
147
+ " AND delta.rid=purgeitem.orid)"
148
+ " WHERE peid=%d",
149
+ peid
150
+ );
151
+ }
152
+
153
+ /* Remove the artifacts being purged. Also remove all references to those
154
+ ** artifacts from the secondary tables. */
135155
db_multi_exec("DELETE FROM blob WHERE rid IN \"%w\"", zTab);
136156
db_multi_exec("DELETE FROM delta WHERE rid IN \"%w\"", zTab);
137157
db_multi_exec("DELETE FROM delta WHERE srcid IN \"%w\"", zTab);
138158
db_multi_exec("DELETE FROM event WHERE objid IN \"%w\"", zTab);
139159
db_multi_exec("DELETE FROM private WHERE rid IN \"%w\"", zTab);
@@ -160,10 +180,12 @@
160180
while( db_step(&q)==SQLITE_ROW ){
161181
ticket_rebuild_entry(db_column_text(&q, 0));
162182
}
163183
db_finalize(&q);
164184
db_multi_exec("DROP TABLE \"%w_tickets\"", zTab);
185
+
186
+ /* Mission accomplished */
165187
db_end_transaction(0);
166188
return peid;
167189
}
168190
169191
/*
@@ -476,18 +498,12 @@
476498
db_begin_transaction();
477499
i = strncmp(zSubcmd,"checkin",n)==0 ? 3 : 2;
478500
if( i>=g.argc ) usage("[checkin] TAGS... [--explain]");
479501
db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
480502
for(; i<g.argc; i++){
481
- int r = symbolic_name_to_rid(g.argv[i], "br");
482
- if( r>0 ){
483
- compute_descendants(r, 1000000000);
484
- }else if( r==0 ){
485
- fossil_fatal("not found: %s", g.argv[i]);
486
- }else{
487
- fossil_fatal("ambiguous: %s\n", g.argv[i]);
488
- }
503
+ int r = name_to_typed_rid(g.argv[i], "br");
504
+ compute_descendants(r, 1000000000);
489505
}
490506
vid = db_lget_int("checkout",0);
491507
if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
492508
fossil_fatal("cannot purge the current checkout");
493509
}
@@ -501,13 +517,13 @@
501517
if( i++ > 0 ) fossil_print("%.78c\n",'-');
502518
whatis_rid(db_column_int(&q,0), 0);
503519
}
504520
db_finalize(&q);
505521
}else{
506
- int peid = purge_artifact_list("ok","");
522
+ int peid = purge_artifact_list("ok","",1);
507523
fossil_print("%d checkins and %d artifacts purged.\n", nCkin, nArtifact);
508524
fossil_print("undoable using \"%s purge undo %d\".\n",
509525
g.nameOfExe, peid);
510526
}
511527
db_end_transaction(explainOnly||dryRun);
512528
}
513529
}
514530
--- src/purge.c
+++ src/purge.c
@@ -79,61 +79,81 @@
79 ** (i) ATTACHMENT
80 ** (j) TICKETCHNG
81 ** (7) If any ticket artifacts were removed (6j) then rebuild the
82 ** corresponding ticket entries. Possibly remove entries from
83 ** the ticket table.
 
 
 
84 */
85 int purge_artifact_list(
86 const char *zTab, /* TEMP table containing list of RIDS to be purged */
87 const char *zNote /* Text of the purgeevent.pnotes field */
 
88 ){
89 int peid = 0; /* New purgeevent ID */
90 Stmt q; /* General-use prepared statement */
91
92 assert( g.repositoryOpen ); /* Main database must already be open */
93 db_begin_transaction();
 
 
 
 
94 if( purge_baseline_out_from_under_delta(zTab) ){
95 fossil_fatal("attempt to purge a baseline manifest without also purging "
96 "all of its deltas");
97 }
98 db_multi_exec(zPurgeInit /*works-like:"%w%w"*/,
99 db_name("repository"), db_name("repository"));
100 db_multi_exec(
101 "INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote
102 );
103 peid = db_last_insert_rowid();
104 db_prepare(&q, "SELECT rid FROM delta WHERE srcid IN \"%w\""
105 " AND rid NOT IN \"%w\"", zTab, zTab);
106 while( db_step(&q)==SQLITE_ROW ){
107 int rid = db_column_int(&q, 0);
108 content_undelta(rid);
109 verify_before_commit(rid);
110 }
111 db_finalize(&q);
112 db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\""
113 " AND srcid NOT IN \"%w\"", zTab, zTab);
114 while( db_step(&q)==SQLITE_ROW ){
115 int rid = db_column_int(&q, 0);
116 content_undelta(rid);
117 }
118 db_finalize(&q);
119 db_multi_exec(
120 "INSERT INTO purgeitem(peid,orid,uuid,sz,isPrivate,data)"
121 " SELECT %d, rid, uuid, size,"
122 " EXISTS(SELECT 1 FROM private WHERE private.rid=blob.rid),"
123 " content"
124 " FROM blob WHERE rid IN \"%w\"",
125 peid, zTab
126 );
127 db_multi_exec(
128 "UPDATE purgeitem"
129 " SET srcid=(SELECT piid FROM purgeitem px, delta"
130 " WHERE px.orid=delta.srcid"
131 " AND delta.rid=purgeitem.orid)"
132 " WHERE peid=%d",
133 peid
134 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135 db_multi_exec("DELETE FROM blob WHERE rid IN \"%w\"", zTab);
136 db_multi_exec("DELETE FROM delta WHERE rid IN \"%w\"", zTab);
137 db_multi_exec("DELETE FROM delta WHERE srcid IN \"%w\"", zTab);
138 db_multi_exec("DELETE FROM event WHERE objid IN \"%w\"", zTab);
139 db_multi_exec("DELETE FROM private WHERE rid IN \"%w\"", zTab);
@@ -160,10 +180,12 @@
160 while( db_step(&q)==SQLITE_ROW ){
161 ticket_rebuild_entry(db_column_text(&q, 0));
162 }
163 db_finalize(&q);
164 db_multi_exec("DROP TABLE \"%w_tickets\"", zTab);
 
 
165 db_end_transaction(0);
166 return peid;
167 }
168
169 /*
@@ -476,18 +498,12 @@
476 db_begin_transaction();
477 i = strncmp(zSubcmd,"checkin",n)==0 ? 3 : 2;
478 if( i>=g.argc ) usage("[checkin] TAGS... [--explain]");
479 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
480 for(; i<g.argc; i++){
481 int r = symbolic_name_to_rid(g.argv[i], "br");
482 if( r>0 ){
483 compute_descendants(r, 1000000000);
484 }else if( r==0 ){
485 fossil_fatal("not found: %s", g.argv[i]);
486 }else{
487 fossil_fatal("ambiguous: %s\n", g.argv[i]);
488 }
489 }
490 vid = db_lget_int("checkout",0);
491 if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
492 fossil_fatal("cannot purge the current checkout");
493 }
@@ -501,13 +517,13 @@
501 if( i++ > 0 ) fossil_print("%.78c\n",'-');
502 whatis_rid(db_column_int(&q,0), 0);
503 }
504 db_finalize(&q);
505 }else{
506 int peid = purge_artifact_list("ok","");
507 fossil_print("%d checkins and %d artifacts purged.\n", nCkin, nArtifact);
508 fossil_print("undoable using \"%s purge undo %d\".\n",
509 g.nameOfExe, peid);
510 }
511 db_end_transaction(explainOnly||dryRun);
512 }
513 }
514
--- src/purge.c
+++ src/purge.c
@@ -79,61 +79,81 @@
79 ** (i) ATTACHMENT
80 ** (j) TICKETCHNG
81 ** (7) If any ticket artifacts were removed (6j) then rebuild the
82 ** corresponding ticket entries. Possibly remove entries from
83 ** the ticket table.
84 **
85 ** Stops 1-4 (saving the purged artifacts into the graveyard) are only
86 ** undertaken if the moveToGraveyard flag is true.
87 */
88 int purge_artifact_list(
89 const char *zTab, /* TEMP table containing list of RIDS to be purged */
90 const char *zNote, /* Text of the purgeevent.pnotes field */
91 int moveToGraveyard /* Move purged artifacts into the graveyard */
92 ){
93 int peid = 0; /* New purgeevent ID */
94 Stmt q; /* General-use prepared statement */
95
96 assert( g.repositoryOpen ); /* Main database must already be open */
97 db_begin_transaction();
98
99 /* Make sure we are not removing a manifest that is the baseline of some
100 ** manifest that is being left behind. This step is not strictly necessary.
101 ** is is just a safety check. */
102 if( purge_baseline_out_from_under_delta(zTab) ){
103 fossil_fatal("attempt to purge a baseline manifest without also purging "
104 "all of its deltas");
105 }
106
107 /* Make sure that no delta that is left behind requires a purged artifact
108 ** as its basis. If such artifacts exist, go ahead and undelta them now.
109 */
 
 
110 db_prepare(&q, "SELECT rid FROM delta WHERE srcid IN \"%w\""
111 " AND rid NOT IN \"%w\"", zTab, zTab);
112 while( db_step(&q)==SQLITE_ROW ){
113 int rid = db_column_int(&q, 0);
114 content_undelta(rid);
115 verify_before_commit(rid);
116 }
117 db_finalize(&q);
118
119 /* Construct the graveyard and copy the artifacts to be purged into the
120 ** graveyard */
121 if( moveToGraveyard ){
122 db_multi_exec(zPurgeInit /*works-like:"%w%w"*/,
123 db_name("repository"), db_name("repository"));
124 db_multi_exec(
125 "INSERT INTO purgeevent(ctime,pnotes) VALUES(now(),%Q)", zNote
126 );
127 peid = db_last_insert_rowid();
128 db_prepare(&q, "SELECT rid FROM delta WHERE rid IN \"%w\""
129 " AND srcid NOT IN \"%w\"", zTab, zTab);
130 while( db_step(&q)==SQLITE_ROW ){
131 int rid = db_column_int(&q, 0);
132 content_undelta(rid);
133 }
134 db_finalize(&q);
135 db_multi_exec(
136 "INSERT INTO purgeitem(peid,orid,uuid,sz,isPrivate,data)"
137 " SELECT %d, rid, uuid, size,"
138 " EXISTS(SELECT 1 FROM private WHERE private.rid=blob.rid),"
139 " content"
140 " FROM blob WHERE rid IN \"%w\"",
141 peid, zTab
142 );
143 db_multi_exec(
144 "UPDATE purgeitem"
145 " SET srcid=(SELECT piid FROM purgeitem px, delta"
146 " WHERE px.orid=delta.srcid"
147 " AND delta.rid=purgeitem.orid)"
148 " WHERE peid=%d",
149 peid
150 );
151 }
152
153 /* Remove the artifacts being purged. Also remove all references to those
154 ** artifacts from the secondary tables. */
155 db_multi_exec("DELETE FROM blob WHERE rid IN \"%w\"", zTab);
156 db_multi_exec("DELETE FROM delta WHERE rid IN \"%w\"", zTab);
157 db_multi_exec("DELETE FROM delta WHERE srcid IN \"%w\"", zTab);
158 db_multi_exec("DELETE FROM event WHERE objid IN \"%w\"", zTab);
159 db_multi_exec("DELETE FROM private WHERE rid IN \"%w\"", zTab);
@@ -160,10 +180,12 @@
180 while( db_step(&q)==SQLITE_ROW ){
181 ticket_rebuild_entry(db_column_text(&q, 0));
182 }
183 db_finalize(&q);
184 db_multi_exec("DROP TABLE \"%w_tickets\"", zTab);
185
186 /* Mission accomplished */
187 db_end_transaction(0);
188 return peid;
189 }
190
191 /*
@@ -476,18 +498,12 @@
498 db_begin_transaction();
499 i = strncmp(zSubcmd,"checkin",n)==0 ? 3 : 2;
500 if( i>=g.argc ) usage("[checkin] TAGS... [--explain]");
501 db_multi_exec("CREATE TEMP TABLE ok(rid INTEGER PRIMARY KEY)");
502 for(; i<g.argc; i++){
503 int r = name_to_typed_rid(g.argv[i], "br");
504 compute_descendants(r, 1000000000);
 
 
 
 
 
 
505 }
506 vid = db_lget_int("checkout",0);
507 if( db_exists("SELECT 1 FROM ok WHERE rid=%d",vid) ){
508 fossil_fatal("cannot purge the current checkout");
509 }
@@ -501,13 +517,13 @@
517 if( i++ > 0 ) fossil_print("%.78c\n",'-');
518 whatis_rid(db_column_int(&q,0), 0);
519 }
520 db_finalize(&q);
521 }else{
522 int peid = purge_artifact_list("ok","",1);
523 fossil_print("%d checkins and %d artifacts purged.\n", nCkin, nArtifact);
524 fossil_print("undoable using \"%s purge undo %d\".\n",
525 g.nameOfExe, peid);
526 }
527 db_end_transaction(explainOnly||dryRun);
528 }
529 }
530

Keyboard Shortcuts

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