Fossil SCM

Added downloadPath link to /json/dir output when --checkin is specified. Optimized no-checkin cases to use a temp view instead of temp table.

stephan 2012-03-25 01:29 trunk
Commit 517d0ef8a5c88c86cf3fa5c8c7ae61232061aa01
1 file changed +53 -24
+53 -24
--- src/json_dir.c
+++ src/json_dir.c
@@ -48,19 +48,20 @@
4848
/*
4949
** Impl of /json/dir. 98% of it was taken directly
5050
** from browse.c::page_dir()
5151
*/
5252
static cson_value * json_page_dir_list(){
53
- cson_object * zPayload = NULL;
54
- cson_array * zEntries = NULL;
55
- cson_object * zEntry = NULL;
56
- cson_array * keyStore = NULL;
53
+ cson_object * zPayload = NULL; /* return value */
54
+ cson_array * zEntries = NULL; /* accumulated list of entries. */
55
+ cson_object * zEntry = NULL; /* a single dir/file entry. */
56
+ cson_array * keyStore = NULL; /* garbage collector for shared strings. */
5757
cson_string * zKeyName = NULL;
5858
cson_string * zKeySize = NULL;
5959
cson_string * zKeyIsDir = NULL;
6060
cson_string * zKeyUuid = NULL;
6161
cson_string * zKeyTime = NULL;
62
+ cson_string * zKeyRaw = NULL;
6263
char * zD = NULL;
6364
char const * zDX = NULL;
6465
int nD;
6566
char * zUuid = NULL;
6667
char const * zCI = NULL;
@@ -86,10 +87,12 @@
8687
"Checkin name [%s] is unresolved.",
8788
zCI);
8889
return NULL;
8990
}
9091
}
92
+
93
+ /* Jump through some hoops to find the directory name... */
9194
zDX = json_find_option_cstr("name",NULL,NULL);
9295
if(!zDX && !g.isHTTP){
9396
zDX = json_command_arg(g.json.dispatchDepth+1);
9497
}
9598
if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){
@@ -107,26 +110,34 @@
107110
**
108111
** Subdirectory names begin with "/". This causes them to sort
109112
** first and it also gives us an easy way to distinguish files
110113
** from directories in the loop that follows.
111114
*/
112
- db_multi_exec(
113
- "CREATE TEMP TABLE json_dir_files(n UNIQUE NOT NULL %s, u, sz, mtime DEFAULT NULL);",
114
- filename_collation()
115
- );
116115
117116
if( zCI ){
118117
Stmt ins;
119118
ManifestFile *pFile;
120119
ManifestFile *pPrev = 0;
121120
int nPrev = 0;
122121
int c;
123122
123
+ db_multi_exec(
124
+ "CREATE TEMP TABLE json_dir_files("
125
+ " n UNIQUE NOT NULL %s," /* file name */
126
+ " fn UNIQUE NOT NULL %s," /* full file name */
127
+ " u DEFAULT NULL," /* file uuid */
128
+ " sz DEFAULT -1," /* file size */
129
+ " mtime DEFAULT NULL" /* file mtime in unix epoch format */
130
+ ");",
131
+ filename_collation(), filename_collation()
132
+ );
133
+
124134
db_prepare(&ins,
125
- "INSERT OR IGNORE INTO json_dir_files (n,u,sz,mtime) "
135
+ "INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) "
126136
"SELECT"
127137
" pathelement(:path,0),"
138
+ " CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath,"
128139
" a.uuid,"
129140
" a.size,"
130141
" CAST(strftime('%%s',e.mtime) AS INTEGER) "
131142
"FROM"
132143
" mlink m, "
@@ -135,11 +146,12 @@
135146
" blob b "
136147
"WHERE"
137148
" e.objid=m.mid"
138149
" AND a.rid=m.fid"/*FILE artifact*/
139150
" AND b.rid=m.mid"/*CHECKIN artifact*/
140
- " AND a.uuid=:uuid"
151
+ " AND a.uuid=:uuid",
152
+ zD, zD
141153
);
142154
manifest_file_rewind(pM);
143155
while( (pFile = manifest_file_next(pM,0))!=0 ){
144156
if( nD>0
145157
&& ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1)))
@@ -152,10 +164,11 @@
152164
&& (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/')
153165
){
154166
continue;
155167
}
156168
db_bind_text( &ins, ":path", &pFile->zName[nD] );
169
+ db_bind_text( &ins, ":abspath", &pFile->zName[nD] );
157170
db_bind_text( &ins, ":uuid", pFile->zUuid );
158171
db_step(&ins);
159172
db_reset(&ins);
160173
pPrev = pFile;
161174
for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){}
@@ -163,39 +176,49 @@
163176
}
164177
db_finalize(&ins);
165178
}else if( zD && *zD ){
166179
if( filenames_are_case_sensitive() ){
167180
db_multi_exec(
168
- "INSERT OR IGNORE INTO json_dir_files"
169
- " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename"
170
- " WHERE name GLOB '%q/*'",
171
- nD, zD
181
+ "CREATE TEMP VIEW json_dir_files AS"
182
+ " SELECT DISTINCT(pathelement(name,%d)) AS n,"
183
+ " %Q||'/'||name AS fn,"
184
+ " NULL AS u, NULL AS sz, NULL AS mtime"
185
+ " FROM filename"
186
+ " WHERE name GLOB '%q/*'"
187
+ " GROUP BY n",
188
+ nD, zD, zD
172189
);
173190
}else{
174191
db_multi_exec(
175
- "INSERT OR IGNORE INTO json_dir_files"
176
- " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename"
177
- " WHERE name LIKE '%q/%%'",
178
- nD, zD
192
+ "CREATE TEMP VIEW json_dir_files AS"
193
+ " SELECT DISTINCT(pathelement(name,%d)) AS n, "
194
+ " %Q||'/'||name AS fn,"
195
+ " NULL AS u, NULL AS sz, NULL AS mtime"
196
+ " FROM filename"
197
+ " WHERE name LIKE '%q/%%'"
198
+ " GROUP BY n",
199
+ nD, zD, zD
179200
);
180201
}
181202
}else{
182203
db_multi_exec(
183
- "INSERT OR IGNORE INTO json_dir_files"
184
- " SELECT pathelement(name,0), NULL, NULL, NULL FROM filename"
204
+ "CREATE TEMP VIEW json_dir_files"
205
+ " AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn"
206
+ " FROM filename"
185207
);
186208
}
187209
188210
if(zCI){
189211
db_prepare( &q, "SELECT"
190212
" n as name,"
213
+ " fn as fullname,"
191214
" u as uuid,"
192215
" sz as size,"
193216
" mtime as mtime "
194217
"FROM json_dir_files ORDER BY n");
195218
}else{/* UUIDs are all NULL. */
196
- db_prepare( &q, "SELECT n as name FROM json_dir_files ORDER BY n");
219
+ db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n");
197220
}
198221
199222
zKeyName = cson_new_string("name",4);
200223
zKeyUuid = cson_new_string("uuid",4);
201224
zKeyIsDir = cson_new_string("isDir",5);
@@ -207,10 +230,12 @@
207230
if( zCI ){
208231
zKeySize = cson_new_string("size",4);
209232
cson_array_append( keyStore, cson_string_value(zKeySize) );
210233
zKeyTime = cson_new_string("timestamp",9);
211234
cson_array_append( keyStore, cson_string_value(zKeyTime) );
235
+ zKeyRaw = cson_new_string("downloadPath",12);
236
+ cson_array_append( keyStore, cson_string_value(zKeyRaw) );
212237
}
213238
zPayload = cson_new_object();
214239
cson_object_set_s( zPayload, zKeyName,
215240
json_new_string((zD&&*zD) ? zD : "/") );
216241
if( zUuid ){
@@ -239,18 +264,22 @@
239264
one of the files in that directory :/. Entries with no
240265
--checkin may refer to N versions, and therefore we cannot
241266
associate a single size and uuid with them (and fetching all
242267
would be overkill for most use cases).
243268
*/
244
- char const * u = db_column_text(&q,1);
245
- sqlite_int64 const sz = db_column_int64(&q,2);
246
- sqlite_int64 const ts = db_column_int64(&q,3);
269
+ char const * fullName = db_column_text(&q,1);
270
+ char const * u = db_column_text(&q,2);
271
+ sqlite_int64 const sz = db_column_int64(&q,3);
272
+ sqlite_int64 const ts = db_column_int64(&q,4);
247273
cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) );
248274
cson_object_set_s(zEntry, zKeySize,
249275
cson_value_new_integer( (cson_int_t)sz ));
250276
cson_object_set_s(zEntry, zKeyTime,
251277
cson_value_new_integer( (cson_int_t)ts ));
278
+ cson_object_set_s(zEntry, zKeyRaw,
279
+ json_new_string_f("/raw/%s?name=%s",
280
+ fullName, u));
252281
}
253282
}
254283
db_finalize(&q);
255284
if(pM){
256285
manifest_destroy(pM);
257286
--- src/json_dir.c
+++ src/json_dir.c
@@ -48,19 +48,20 @@
48 /*
49 ** Impl of /json/dir. 98% of it was taken directly
50 ** from browse.c::page_dir()
51 */
52 static cson_value * json_page_dir_list(){
53 cson_object * zPayload = NULL;
54 cson_array * zEntries = NULL;
55 cson_object * zEntry = NULL;
56 cson_array * keyStore = NULL;
57 cson_string * zKeyName = NULL;
58 cson_string * zKeySize = NULL;
59 cson_string * zKeyIsDir = NULL;
60 cson_string * zKeyUuid = NULL;
61 cson_string * zKeyTime = NULL;
 
62 char * zD = NULL;
63 char const * zDX = NULL;
64 int nD;
65 char * zUuid = NULL;
66 char const * zCI = NULL;
@@ -86,10 +87,12 @@
86 "Checkin name [%s] is unresolved.",
87 zCI);
88 return NULL;
89 }
90 }
 
 
91 zDX = json_find_option_cstr("name",NULL,NULL);
92 if(!zDX && !g.isHTTP){
93 zDX = json_command_arg(g.json.dispatchDepth+1);
94 }
95 if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){
@@ -107,26 +110,34 @@
107 **
108 ** Subdirectory names begin with "/". This causes them to sort
109 ** first and it also gives us an easy way to distinguish files
110 ** from directories in the loop that follows.
111 */
112 db_multi_exec(
113 "CREATE TEMP TABLE json_dir_files(n UNIQUE NOT NULL %s, u, sz, mtime DEFAULT NULL);",
114 filename_collation()
115 );
116
117 if( zCI ){
118 Stmt ins;
119 ManifestFile *pFile;
120 ManifestFile *pPrev = 0;
121 int nPrev = 0;
122 int c;
123
 
 
 
 
 
 
 
 
 
 
 
124 db_prepare(&ins,
125 "INSERT OR IGNORE INTO json_dir_files (n,u,sz,mtime) "
126 "SELECT"
127 " pathelement(:path,0),"
 
128 " a.uuid,"
129 " a.size,"
130 " CAST(strftime('%%s',e.mtime) AS INTEGER) "
131 "FROM"
132 " mlink m, "
@@ -135,11 +146,12 @@
135 " blob b "
136 "WHERE"
137 " e.objid=m.mid"
138 " AND a.rid=m.fid"/*FILE artifact*/
139 " AND b.rid=m.mid"/*CHECKIN artifact*/
140 " AND a.uuid=:uuid"
 
141 );
142 manifest_file_rewind(pM);
143 while( (pFile = manifest_file_next(pM,0))!=0 ){
144 if( nD>0
145 && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1)))
@@ -152,10 +164,11 @@
152 && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/')
153 ){
154 continue;
155 }
156 db_bind_text( &ins, ":path", &pFile->zName[nD] );
 
157 db_bind_text( &ins, ":uuid", pFile->zUuid );
158 db_step(&ins);
159 db_reset(&ins);
160 pPrev = pFile;
161 for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){}
@@ -163,39 +176,49 @@
163 }
164 db_finalize(&ins);
165 }else if( zD && *zD ){
166 if( filenames_are_case_sensitive() ){
167 db_multi_exec(
168 "INSERT OR IGNORE INTO json_dir_files"
169 " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename"
170 " WHERE name GLOB '%q/*'",
171 nD, zD
 
 
 
 
172 );
173 }else{
174 db_multi_exec(
175 "INSERT OR IGNORE INTO json_dir_files"
176 " SELECT pathelement(name,%d), NULL, NULL, NULL FROM filename"
177 " WHERE name LIKE '%q/%%'",
178 nD, zD
 
 
 
 
179 );
180 }
181 }else{
182 db_multi_exec(
183 "INSERT OR IGNORE INTO json_dir_files"
184 " SELECT pathelement(name,0), NULL, NULL, NULL FROM filename"
 
185 );
186 }
187
188 if(zCI){
189 db_prepare( &q, "SELECT"
190 " n as name,"
 
191 " u as uuid,"
192 " sz as size,"
193 " mtime as mtime "
194 "FROM json_dir_files ORDER BY n");
195 }else{/* UUIDs are all NULL. */
196 db_prepare( &q, "SELECT n as name FROM json_dir_files ORDER BY n");
197 }
198
199 zKeyName = cson_new_string("name",4);
200 zKeyUuid = cson_new_string("uuid",4);
201 zKeyIsDir = cson_new_string("isDir",5);
@@ -207,10 +230,12 @@
207 if( zCI ){
208 zKeySize = cson_new_string("size",4);
209 cson_array_append( keyStore, cson_string_value(zKeySize) );
210 zKeyTime = cson_new_string("timestamp",9);
211 cson_array_append( keyStore, cson_string_value(zKeyTime) );
 
 
212 }
213 zPayload = cson_new_object();
214 cson_object_set_s( zPayload, zKeyName,
215 json_new_string((zD&&*zD) ? zD : "/") );
216 if( zUuid ){
@@ -239,18 +264,22 @@
239 one of the files in that directory :/. Entries with no
240 --checkin may refer to N versions, and therefore we cannot
241 associate a single size and uuid with them (and fetching all
242 would be overkill for most use cases).
243 */
244 char const * u = db_column_text(&q,1);
245 sqlite_int64 const sz = db_column_int64(&q,2);
246 sqlite_int64 const ts = db_column_int64(&q,3);
 
247 cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) );
248 cson_object_set_s(zEntry, zKeySize,
249 cson_value_new_integer( (cson_int_t)sz ));
250 cson_object_set_s(zEntry, zKeyTime,
251 cson_value_new_integer( (cson_int_t)ts ));
 
 
 
252 }
253 }
254 db_finalize(&q);
255 if(pM){
256 manifest_destroy(pM);
257
--- src/json_dir.c
+++ src/json_dir.c
@@ -48,19 +48,20 @@
48 /*
49 ** Impl of /json/dir. 98% of it was taken directly
50 ** from browse.c::page_dir()
51 */
52 static cson_value * json_page_dir_list(){
53 cson_object * zPayload = NULL; /* return value */
54 cson_array * zEntries = NULL; /* accumulated list of entries. */
55 cson_object * zEntry = NULL; /* a single dir/file entry. */
56 cson_array * keyStore = NULL; /* garbage collector for shared strings. */
57 cson_string * zKeyName = NULL;
58 cson_string * zKeySize = NULL;
59 cson_string * zKeyIsDir = NULL;
60 cson_string * zKeyUuid = NULL;
61 cson_string * zKeyTime = NULL;
62 cson_string * zKeyRaw = NULL;
63 char * zD = NULL;
64 char const * zDX = NULL;
65 int nD;
66 char * zUuid = NULL;
67 char const * zCI = NULL;
@@ -86,10 +87,12 @@
87 "Checkin name [%s] is unresolved.",
88 zCI);
89 return NULL;
90 }
91 }
92
93 /* Jump through some hoops to find the directory name... */
94 zDX = json_find_option_cstr("name",NULL,NULL);
95 if(!zDX && !g.isHTTP){
96 zDX = json_command_arg(g.json.dispatchDepth+1);
97 }
98 if(zDX && (!*zDX || (0==strcmp(zDX,"/")))){
@@ -107,26 +110,34 @@
110 **
111 ** Subdirectory names begin with "/". This causes them to sort
112 ** first and it also gives us an easy way to distinguish files
113 ** from directories in the loop that follows.
114 */
 
 
 
 
115
116 if( zCI ){
117 Stmt ins;
118 ManifestFile *pFile;
119 ManifestFile *pPrev = 0;
120 int nPrev = 0;
121 int c;
122
123 db_multi_exec(
124 "CREATE TEMP TABLE json_dir_files("
125 " n UNIQUE NOT NULL %s," /* file name */
126 " fn UNIQUE NOT NULL %s," /* full file name */
127 " u DEFAULT NULL," /* file uuid */
128 " sz DEFAULT -1," /* file size */
129 " mtime DEFAULT NULL" /* file mtime in unix epoch format */
130 ");",
131 filename_collation(), filename_collation()
132 );
133
134 db_prepare(&ins,
135 "INSERT OR IGNORE INTO json_dir_files (n,fn,u,sz,mtime) "
136 "SELECT"
137 " pathelement(:path,0),"
138 " CASE WHEN %Q IS NULL THEN '' ELSE %Q||'/' END ||:abspath,"
139 " a.uuid,"
140 " a.size,"
141 " CAST(strftime('%%s',e.mtime) AS INTEGER) "
142 "FROM"
143 " mlink m, "
@@ -135,11 +146,12 @@
146 " blob b "
147 "WHERE"
148 " e.objid=m.mid"
149 " AND a.rid=m.fid"/*FILE artifact*/
150 " AND b.rid=m.mid"/*CHECKIN artifact*/
151 " AND a.uuid=:uuid",
152 zD, zD
153 );
154 manifest_file_rewind(pM);
155 while( (pFile = manifest_file_next(pM,0))!=0 ){
156 if( nD>0
157 && ((pFile->zName[nD-1]!='/') || (0!=memcmp(pFile->zName, zD, nD-1)))
@@ -152,10 +164,11 @@
164 && (pFile->zName[nD+nPrev]==0 || pFile->zName[nD+nPrev]=='/')
165 ){
166 continue;
167 }
168 db_bind_text( &ins, ":path", &pFile->zName[nD] );
169 db_bind_text( &ins, ":abspath", &pFile->zName[nD] );
170 db_bind_text( &ins, ":uuid", pFile->zUuid );
171 db_step(&ins);
172 db_reset(&ins);
173 pPrev = pFile;
174 for(nPrev=0; (c=pPrev->zName[nD+nPrev]) && c!='/'; nPrev++){}
@@ -163,39 +176,49 @@
176 }
177 db_finalize(&ins);
178 }else if( zD && *zD ){
179 if( filenames_are_case_sensitive() ){
180 db_multi_exec(
181 "CREATE TEMP VIEW json_dir_files AS"
182 " SELECT DISTINCT(pathelement(name,%d)) AS n,"
183 " %Q||'/'||name AS fn,"
184 " NULL AS u, NULL AS sz, NULL AS mtime"
185 " FROM filename"
186 " WHERE name GLOB '%q/*'"
187 " GROUP BY n",
188 nD, zD, zD
189 );
190 }else{
191 db_multi_exec(
192 "CREATE TEMP VIEW json_dir_files AS"
193 " SELECT DISTINCT(pathelement(name,%d)) AS n, "
194 " %Q||'/'||name AS fn,"
195 " NULL AS u, NULL AS sz, NULL AS mtime"
196 " FROM filename"
197 " WHERE name LIKE '%q/%%'"
198 " GROUP BY n",
199 nD, zD, zD
200 );
201 }
202 }else{
203 db_multi_exec(
204 "CREATE TEMP VIEW json_dir_files"
205 " AS SELECT DISTINCT(pathelement(name,0)) AS n, NULL AS fn"
206 " FROM filename"
207 );
208 }
209
210 if(zCI){
211 db_prepare( &q, "SELECT"
212 " n as name,"
213 " fn as fullname,"
214 " u as uuid,"
215 " sz as size,"
216 " mtime as mtime "
217 "FROM json_dir_files ORDER BY n");
218 }else{/* UUIDs are all NULL. */
219 db_prepare( &q, "SELECT n, fn FROM json_dir_files ORDER BY n");
220 }
221
222 zKeyName = cson_new_string("name",4);
223 zKeyUuid = cson_new_string("uuid",4);
224 zKeyIsDir = cson_new_string("isDir",5);
@@ -207,10 +230,12 @@
230 if( zCI ){
231 zKeySize = cson_new_string("size",4);
232 cson_array_append( keyStore, cson_string_value(zKeySize) );
233 zKeyTime = cson_new_string("timestamp",9);
234 cson_array_append( keyStore, cson_string_value(zKeyTime) );
235 zKeyRaw = cson_new_string("downloadPath",12);
236 cson_array_append( keyStore, cson_string_value(zKeyRaw) );
237 }
238 zPayload = cson_new_object();
239 cson_object_set_s( zPayload, zKeyName,
240 json_new_string((zD&&*zD) ? zD : "/") );
241 if( zUuid ){
@@ -239,18 +264,22 @@
264 one of the files in that directory :/. Entries with no
265 --checkin may refer to N versions, and therefore we cannot
266 associate a single size and uuid with them (and fetching all
267 would be overkill for most use cases).
268 */
269 char const * fullName = db_column_text(&q,1);
270 char const * u = db_column_text(&q,2);
271 sqlite_int64 const sz = db_column_int64(&q,3);
272 sqlite_int64 const ts = db_column_int64(&q,4);
273 cson_object_set_s(zEntry, zKeyUuid, json_new_string( u ) );
274 cson_object_set_s(zEntry, zKeySize,
275 cson_value_new_integer( (cson_int_t)sz ));
276 cson_object_set_s(zEntry, zKeyTime,
277 cson_value_new_integer( (cson_int_t)ts ));
278 cson_object_set_s(zEntry, zKeyRaw,
279 json_new_string_f("/raw/%s?name=%s",
280 fullName, u));
281 }
282 }
283 db_finalize(&q);
284 if(pM){
285 manifest_destroy(pM);
286

Keyboard Shortcuts

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