Fossil SCM

Refactored to use a shared query-rendering routine.

stephan 2008-02-03 16:32 trunk
Commit 02a7c850b417e4cee4d7068ca8bff77da6e5ae30
1 file changed +196 -113
+196 -113
--- src/tagview.c
+++ src/tagview.c
@@ -27,34 +27,161 @@
2727
*/
2828
#include <assert.h>
2929
#include "config.h"
3030
#include "tagview.h"
3131
32
-
33
-/*
34
-** Output a single entry for a menu generated using an HTML table.
35
-** If zLink is not NULL or an empty string, then it is the page that
36
-** the menu entry will hyperlink to. If zLink is NULL or "", then
37
-** the menu entry has no hyperlink - it is disabled.
38
-*/
39
-void tagview_menu_entry(
40
- const char *zTitle,
41
- const char *zLink,
42
- const char *zDesc
43
-){
44
- @ <tr><td valign="top" align="right">
45
- if( zLink && zLink[0] ){
46
- @ <a href="%s(g.zBaseURL)/%s(zLink)">%h(zTitle)</a>
47
- }else{
48
- @ %h(zTitle)
49
- }
50
- @ </td><td valign="top">%h(zDesc)</td></tr>
51
-}
52
-
32
+/**
33
+tagview_strxform_f is a typedef for funcs with
34
+the following policy:
35
+
36
+The accept a string which they then transform into
37
+some other form. They return a transformed copy,
38
+which the caller is responsible for freeing.
39
+
40
+The intention of this is to provide a way for
41
+a generic query routine to format specific column
42
+data (e.g. transform an object ID into a link to
43
+that object).
44
+*/
45
+typedef char * (*tagview_strxform_f)( char const * );
46
+
47
+#if 0
48
+/** A no-op transformer which can be used as a placeholder. */
49
+static char * tagview_xf_copy( char const * uuid )
50
+{
51
+ int len = strlen(uuid) + 1;
52
+ char * ret = (char *) malloc( len );
53
+ ret[len] = '\0';
54
+ strncpy( ret, uuid, len-1 );
55
+ return ret;
56
+}
57
+#endif
58
+
59
+/** Returns a hyperlink to uuid. */
60
+static char * tagview_xf_link_to_uuid( char const * uuid )
61
+{
62
+ const int offset = 10;
63
+ char shortname[offset+1];
64
+ shortname[offset] = '\0';
65
+ memcpy( shortname, uuid, offset );
66
+ return mprintf( "<tt><a href='%s/vinfo/%s'><strong>%s</strong>%s</a></tt>",
67
+ g.zBaseURL, uuid, shortname, uuid+offset );
68
+}
69
+
70
+/** Returns a hyperlink to the given tag. */
71
+static char * tagview_xf_link_to_tagid( char const * tagid )
72
+{
73
+ return mprintf( "<a href='%s/tagview?tagid=%s'>%s</a>",
74
+ g.zBaseURL, tagid, tagid );
75
+}
76
+
77
+/** Returns a hyperlink to the named tag. */
78
+static char * tagview_xf_link_to_tagname( char const * tagid )
79
+{
80
+ return mprintf( "<a href='%s/tagview/%s'>%s</a>",
81
+ g.zBaseURL, tagid, tagid );
82
+}
83
+
84
+
85
+
86
+/**
87
+* tagview_run_query():
88
+*
89
+* A very primitive helper to run an SQL query and table-ize the
90
+* results.
91
+*
92
+* The sql parameter should be a single, complete SQL statement.
93
+*
94
+* The coln parameter is optional (it may be 0). If it is 0 then the
95
+* column names using in the output will be taken directly from the
96
+* SQL. If it is not null then it must have as many entries as the SQL
97
+* result has columns. Each entry is a column name for the SQL result
98
+* column of the same index. Any given entry may be 0, in which case
99
+* the column name from the SQL is used.
100
+*
101
+* The xform argument is an array of transformation functions (type
102
+* tagview_strxform_f). The array, or any single entry, may be 0, but
103
+* if the array is non-0 then it must have at least as many entries as
104
+* colnames does. Each index corresponds directly to an entry in
105
+* colnames and the SQL results. Any given entry may be 0 If it has
106
+* fewer, undefined behaviour results. If a column has an entry in
107
+* xform, then the xform function will be called to transform the
108
+* column data before rendering it. This function takes care of freeing
109
+* the strings created by the xform functions.
110
+*
111
+* Example:
112
+*
113
+* char const * const colnames[] = {
114
+* "Tag ID", "Tag Name", "Something Else", "UUID"
115
+* };
116
+* tagview_strxform_f xf[] = {
117
+* tagview_xf_link_to_tagid,
118
+* tagview_xf_link_to_tagname,
119
+* 0,
120
+* tagview_xf_link_to_uuid
121
+* };
122
+* tagview_run_query( "select a,b,c,d from foo", colnames, xf );
123
+*
124
+*/
125
+static void tagview_run_query(
126
+ char const * sql,
127
+ char const * const * coln,
128
+ tagview_strxform_f * xform )
129
+{
130
+
131
+ Stmt st;
132
+ @ <table cellpadding='4px' border='1'><tbody>
133
+ int i = 0;
134
+ int rc = db_prepare( &st, sql );
135
+ /**
136
+ Achtung: makeheaders apparently can't pull the function
137
+ name from this:
138
+ if( SQLITE_OK != db_prepare( &st, sql ) )
139
+ */
140
+ if( SQLITE_OK != rc )
141
+ {
142
+ @ tagview_run_query(): Error processing SQL: [%s(sql)]
143
+ return;
144
+ }
145
+ int colc = db_column_count(&st);
146
+ @ <tr>
147
+ for( i = 0; i < colc; ++i ) {
148
+ if( coln )
149
+ {
150
+ @ <th>%s(coln[i] ? coln[i] : db_column_name(&st,i))</th>
151
+ }
152
+ else
153
+ {
154
+ @ <td>%s(db_column_name(&st,i))</td>
155
+ }
156
+ }
157
+ @ </tr>
158
+
159
+
160
+ while( SQLITE_ROW == db_step(&st) ){
161
+ @ <tr>
162
+ for( i = 0; i < colc; ++i ) {
163
+ char * xf = 0;
164
+ char const * xcf = 0;
165
+ xcf = (xform && xform[i])
166
+ ? (xf=(xform[i])(db_column_text(&st,i)))
167
+ : db_column_text(&st,i);
168
+ @ <td>%s(xcf)</td>
169
+ if( xf ) free( xf );
170
+ }
171
+ @ </tr>
172
+ }
173
+ db_finalize( &st );
174
+ @ </tbody></table>
175
+}
176
+
177
+/**
178
+ Lists all tags matching the given LIKE clause (which
179
+may be 0).
180
+*/
53181
static void tagview_page_list_tags( char const * like )
54182
{
55
- Stmt st;
56183
char * likeclause = 0;
57184
const int limit = 10;
58185
char * limitstr = 0;
59186
if( like && strlen(like) )
60187
{
@@ -64,61 +191,37 @@
64191
else
65192
{
66193
limitstr = mprintf( "LIMIT %d", limit );
67194
@ <h2>%d(limit) most recent tags:</h2>
68195
}
69
- @ <table cellpadding='4px' border='1'><tbody>
70
- @ <tr>
71
- @ <th>Tag ID</th>
72
- @ <th>Tag name</th>
73
- @ <th>Timestamp</th>
74
- @ <th>Version</th>
75
- @ </tr>
76196
char * sql = mprintf(
77197
"SELECT t.tagid, t.tagname, DATETIME(tx.mtime), b.uuid "
78198
"FROM tag t, tagxref tx, blob b "
79199
"WHERE (t.tagid=tx.tagid) and (tx.srcid=b.rid) "
80200
"AND (tx.tagtype != 0) %s "
81201
"ORDER BY tx.mtime DESC %s",
82202
likeclause ? likeclause : " ",
83203
limitstr ? limitstr : " "
84204
);
85
- db_prepare( &st, sql );
86
- if( likeclause ) free( likeclause );
87
- free( sql );
88
- while( SQLITE_ROW == db_step(&st) ){
89
- int tagid = db_column_int( &st, 0 );
90
- char const * tagname = db_column_text( &st, 1 );
91
- char const * tagtime = db_column_text( &st, 2 );
92
- char const * uuid = db_column_text( &st, 3 );
93
- const int offset = 10;
94
- char shortname[offset+1];
95
- shortname[offset] = '\0';
96
- memcpy( shortname, uuid, offset );
97
- @ <tr>
98
- @ <td><tt>
99
- @ <a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a>
100
- @ </tt></td>
101
- @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td>
102
- @ <td align='center'><tt>%s(tagtime)</tt></td>
103
- @ <td><tt>
104
- @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
105
- @ </tt></td></tr>
106
- }
107
- db_finalize( &st );
108
- @ </tbody></table>
109
- @ <hr/>TODOs include:
110
- @ <ul>
111
- @ <li>Page through long tags lists.</li>
112
- @ <li>Refactor the internal report routines to be reusable.</li>
113
- @ <li>Allow different sorting.</li>
114
- @ <li>Selectively filter out wiki/ticket/baseline</li>
115
- @ <li>?</li>
116
- @ </ul>
117
-
118
-}
119
-
205
+ /* " AND t.tagname NOT GLOB 'wiki-*'" // Do we want this?? */
206
+
207
+ char const * const colnames[] = {
208
+ "Tag ID", "Name", "Timestamp", "Version"
209
+ };
210
+ tagview_strxform_f xf[] = {
211
+ tagview_xf_link_to_tagid,
212
+ tagview_xf_link_to_tagname,
213
+ 0,
214
+ tagview_xf_link_to_uuid
215
+ };
216
+ tagview_run_query( sql, colnames, xf );
217
+ free( sql );
218
+}
219
+
220
+/**
221
+A small search form which forwards to ?like=SEARCH_STRING
222
+*/
120223
static void tagview_page_search_miniform(void){
121224
char const * like = P("like");
122225
@ <div style='font-size:smaller'>
123226
@ <form action='/tagview' method='post'>
124227
@ Search for tags:
@@ -131,76 +234,56 @@
131234
132235
static void tagview_page_default(void){
133236
tagview_page_list_tags( 0 );
134237
}
135238
239
+/**
240
+ Lists all tags matching the given tagid.
241
+*/
136242
static void tagview_page_tag_by_id( int tagid )
137243
{
138
- Stmt st;
244
+ @ <h2>Tag #%d(tagid):</h2>
139245
char * sql = mprintf(
140246
"SELECT DISTINCT (t.tagname), DATETIME(tx.mtime), b.uuid "
141247
"FROM tag t, tagxref tx, blob b "
142248
"WHERE (t.tagid=%d) AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
143249
"ORDER BY tx.mtime DESC",
144250
tagid);
145
- db_prepare( &st, sql );
146
- free( sql );
147
- @ <h2>Tag ID %d(tagid):</h2>
148
- @ <table cellpadding='4px' border='1'><tbody>
149
- @ <tr><th>Tag name</th><th>Timestamp</th><th>Version</th></tr>
150
- while( SQLITE_ROW == db_step(&st) )
151
- {
152
- char const * tagname = db_column_text( &st, 0 );
153
- char const * tagtime = db_column_text( &st, 1 );
154
- char const * uuid = db_column_text( &st, 2 );
155
- const int offset = 10;
156
- char shortname[offset+1];
157
- shortname[offset] = '\0';
158
- memcpy( shortname, uuid, offset );
159
- @ <tr>
160
- @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td>
161
- @ <td align='center'><tt>%s(tagtime)</tt></td>
162
- @ <td><tt>
163
- @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
164
- @ </tt></td></tr>
165
- }
166
- @ </tbody></table>
167
- db_finalize( &st );
168
-}
169
-
251
+ char const * const colnames[] = {
252
+ "Tag Name", "Timestamp", "Version"
253
+ };
254
+ tagview_strxform_f xf[] = {
255
+ tagview_xf_link_to_tagname,
256
+ 0,
257
+ tagview_xf_link_to_uuid
258
+ };
259
+ tagview_run_query( sql, colnames, xf );
260
+ free(sql);
261
+}
262
+
263
+/**
264
+ Lists all tags matching the given tag name.
265
+*/
170266
static void tagview_page_tag_by_name( char const * tagname )
171267
{
172
- Stmt st;
268
+ @ <h2>Tag '%s(tagname)':</h2>
173269
char * sql = mprintf(
174270
"SELECT DISTINCT t.tagid, DATETIME(tx.mtime), b.uuid "
175271
"FROM tag t, tagxref tx, blob b "
176272
"WHERE (t.tagname='%q') AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
177273
"ORDER BY tx.mtime DESC",
178274
tagname);
179
- db_prepare( &st, sql );
275
+ char const * const colnames[] = {
276
+ "Tag ID", "Timestamp", "Version"
277
+ };
278
+ tagview_strxform_f xf[] = {
279
+ tagview_xf_link_to_tagid,
280
+ 0,
281
+ tagview_xf_link_to_uuid
282
+ };
283
+ tagview_run_query( sql, colnames, xf );
180284
free( sql );
181
- @ <h2>Tag '%s(tagname)':</h2>
182
- @ <table cellpadding='4px' border='1'><tbody>
183
- @ <tr><th>Tag ID</th><th>Timestamp</th><th>Version</th></tr>
184
- while( SQLITE_ROW == db_step(&st) )
185
- {
186
- int tagid = db_column_int( &st, 0 );
187
- char const * tagtime = db_column_text( &st, 1 );
188
- char const * uuid = db_column_text( &st, 2 );
189
- const int offset = 10;
190
- char shortname[offset+1];
191
- shortname[offset] = '\0';
192
- memcpy( shortname, uuid, offset );
193
- @ <tr>
194
- @ <td><tt><a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a></tt></td>
195
- @ <td align='center'><tt>%s(tagtime)</tt></td>
196
- @ <td><tt>
197
- @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
198
- @ </tt></td></tr>
199
- }
200
- @ </tbody></table>
201
- db_finalize( &st );
202285
}
203286
204287
205288
/*
206289
** WEBPAGE: /tagview
207290
--- src/tagview.c
+++ src/tagview.c
@@ -27,34 +27,161 @@
27 */
28 #include <assert.h>
29 #include "config.h"
30 #include "tagview.h"
31
32
33 /*
34 ** Output a single entry for a menu generated using an HTML table.
35 ** If zLink is not NULL or an empty string, then it is the page that
36 ** the menu entry will hyperlink to. If zLink is NULL or "", then
37 ** the menu entry has no hyperlink - it is disabled.
38 */
39 void tagview_menu_entry(
40 const char *zTitle,
41 const char *zLink,
42 const char *zDesc
43 ){
44 @ <tr><td valign="top" align="right">
45 if( zLink && zLink[0] ){
46 @ <a href="%s(g.zBaseURL)/%s(zLink)">%h(zTitle)</a>
47 }else{
48 @ %h(zTitle)
49 }
50 @ </td><td valign="top">%h(zDesc)</td></tr>
51 }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53 static void tagview_page_list_tags( char const * like )
54 {
55 Stmt st;
56 char * likeclause = 0;
57 const int limit = 10;
58 char * limitstr = 0;
59 if( like && strlen(like) )
60 {
@@ -64,61 +191,37 @@
64 else
65 {
66 limitstr = mprintf( "LIMIT %d", limit );
67 @ <h2>%d(limit) most recent tags:</h2>
68 }
69 @ <table cellpadding='4px' border='1'><tbody>
70 @ <tr>
71 @ <th>Tag ID</th>
72 @ <th>Tag name</th>
73 @ <th>Timestamp</th>
74 @ <th>Version</th>
75 @ </tr>
76 char * sql = mprintf(
77 "SELECT t.tagid, t.tagname, DATETIME(tx.mtime), b.uuid "
78 "FROM tag t, tagxref tx, blob b "
79 "WHERE (t.tagid=tx.tagid) and (tx.srcid=b.rid) "
80 "AND (tx.tagtype != 0) %s "
81 "ORDER BY tx.mtime DESC %s",
82 likeclause ? likeclause : " ",
83 limitstr ? limitstr : " "
84 );
85 db_prepare( &st, sql );
86 if( likeclause ) free( likeclause );
87 free( sql );
88 while( SQLITE_ROW == db_step(&st) ){
89 int tagid = db_column_int( &st, 0 );
90 char const * tagname = db_column_text( &st, 1 );
91 char const * tagtime = db_column_text( &st, 2 );
92 char const * uuid = db_column_text( &st, 3 );
93 const int offset = 10;
94 char shortname[offset+1];
95 shortname[offset] = '\0';
96 memcpy( shortname, uuid, offset );
97 @ <tr>
98 @ <td><tt>
99 @ <a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a>
100 @ </tt></td>
101 @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td>
102 @ <td align='center'><tt>%s(tagtime)</tt></td>
103 @ <td><tt>
104 @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
105 @ </tt></td></tr>
106 }
107 db_finalize( &st );
108 @ </tbody></table>
109 @ <hr/>TODOs include:
110 @ <ul>
111 @ <li>Page through long tags lists.</li>
112 @ <li>Refactor the internal report routines to be reusable.</li>
113 @ <li>Allow different sorting.</li>
114 @ <li>Selectively filter out wiki/ticket/baseline</li>
115 @ <li>?</li>
116 @ </ul>
117
118 }
119
120 static void tagview_page_search_miniform(void){
121 char const * like = P("like");
122 @ <div style='font-size:smaller'>
123 @ <form action='/tagview' method='post'>
124 @ Search for tags:
@@ -131,76 +234,56 @@
131
132 static void tagview_page_default(void){
133 tagview_page_list_tags( 0 );
134 }
135
 
 
 
136 static void tagview_page_tag_by_id( int tagid )
137 {
138 Stmt st;
139 char * sql = mprintf(
140 "SELECT DISTINCT (t.tagname), DATETIME(tx.mtime), b.uuid "
141 "FROM tag t, tagxref tx, blob b "
142 "WHERE (t.tagid=%d) AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
143 "ORDER BY tx.mtime DESC",
144 tagid);
145 db_prepare( &st, sql );
146 free( sql );
147 @ <h2>Tag ID %d(tagid):</h2>
148 @ <table cellpadding='4px' border='1'><tbody>
149 @ <tr><th>Tag name</th><th>Timestamp</th><th>Version</th></tr>
150 while( SQLITE_ROW == db_step(&st) )
151 {
152 char const * tagname = db_column_text( &st, 0 );
153 char const * tagtime = db_column_text( &st, 1 );
154 char const * uuid = db_column_text( &st, 2 );
155 const int offset = 10;
156 char shortname[offset+1];
157 shortname[offset] = '\0';
158 memcpy( shortname, uuid, offset );
159 @ <tr>
160 @ <td><tt><a href='%s(g.zBaseURL)/tagview/%q(tagname)'>%s(tagname)</a></tt></td>
161 @ <td align='center'><tt>%s(tagtime)</tt></td>
162 @ <td><tt>
163 @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
164 @ </tt></td></tr>
165 }
166 @ </tbody></table>
167 db_finalize( &st );
168 }
169
170 static void tagview_page_tag_by_name( char const * tagname )
171 {
172 Stmt st;
173 char * sql = mprintf(
174 "SELECT DISTINCT t.tagid, DATETIME(tx.mtime), b.uuid "
175 "FROM tag t, tagxref tx, blob b "
176 "WHERE (t.tagname='%q') AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
177 "ORDER BY tx.mtime DESC",
178 tagname);
179 db_prepare( &st, sql );
 
 
 
 
 
 
 
 
180 free( sql );
181 @ <h2>Tag '%s(tagname)':</h2>
182 @ <table cellpadding='4px' border='1'><tbody>
183 @ <tr><th>Tag ID</th><th>Timestamp</th><th>Version</th></tr>
184 while( SQLITE_ROW == db_step(&st) )
185 {
186 int tagid = db_column_int( &st, 0 );
187 char const * tagtime = db_column_text( &st, 1 );
188 char const * uuid = db_column_text( &st, 2 );
189 const int offset = 10;
190 char shortname[offset+1];
191 shortname[offset] = '\0';
192 memcpy( shortname, uuid, offset );
193 @ <tr>
194 @ <td><tt><a href='%s(g.zBaseURL)/tagview?tagid=%d(tagid)'>%d(tagid)</a></tt></td>
195 @ <td align='center'><tt>%s(tagtime)</tt></td>
196 @ <td><tt>
197 @ <a href='%s(g.zBaseURL)/vinfo/%s(uuid)'><strong>%s(shortname)</strong>%s(uuid+offset)</a>
198 @ </tt></td></tr>
199 }
200 @ </tbody></table>
201 db_finalize( &st );
202 }
203
204
205 /*
206 ** WEBPAGE: /tagview
207
--- src/tagview.c
+++ src/tagview.c
@@ -27,34 +27,161 @@
27 */
28 #include <assert.h>
29 #include "config.h"
30 #include "tagview.h"
31
32 /**
33 tagview_strxform_f is a typedef for funcs with
34 the following policy:
35
36 The accept a string which they then transform into
37 some other form. They return a transformed copy,
38 which the caller is responsible for freeing.
39
40 The intention of this is to provide a way for
41 a generic query routine to format specific column
42 data (e.g. transform an object ID into a link to
43 that object).
44 */
45 typedef char * (*tagview_strxform_f)( char const * );
46
47 #if 0
48 /** A no-op transformer which can be used as a placeholder. */
49 static char * tagview_xf_copy( char const * uuid )
50 {
51 int len = strlen(uuid) + 1;
52 char * ret = (char *) malloc( len );
53 ret[len] = '\0';
54 strncpy( ret, uuid, len-1 );
55 return ret;
56 }
57 #endif
58
59 /** Returns a hyperlink to uuid. */
60 static char * tagview_xf_link_to_uuid( char const * uuid )
61 {
62 const int offset = 10;
63 char shortname[offset+1];
64 shortname[offset] = '\0';
65 memcpy( shortname, uuid, offset );
66 return mprintf( "<tt><a href='%s/vinfo/%s'><strong>%s</strong>%s</a></tt>",
67 g.zBaseURL, uuid, shortname, uuid+offset );
68 }
69
70 /** Returns a hyperlink to the given tag. */
71 static char * tagview_xf_link_to_tagid( char const * tagid )
72 {
73 return mprintf( "<a href='%s/tagview?tagid=%s'>%s</a>",
74 g.zBaseURL, tagid, tagid );
75 }
76
77 /** Returns a hyperlink to the named tag. */
78 static char * tagview_xf_link_to_tagname( char const * tagid )
79 {
80 return mprintf( "<a href='%s/tagview/%s'>%s</a>",
81 g.zBaseURL, tagid, tagid );
82 }
83
84
85
86 /**
87 * tagview_run_query():
88 *
89 * A very primitive helper to run an SQL query and table-ize the
90 * results.
91 *
92 * The sql parameter should be a single, complete SQL statement.
93 *
94 * The coln parameter is optional (it may be 0). If it is 0 then the
95 * column names using in the output will be taken directly from the
96 * SQL. If it is not null then it must have as many entries as the SQL
97 * result has columns. Each entry is a column name for the SQL result
98 * column of the same index. Any given entry may be 0, in which case
99 * the column name from the SQL is used.
100 *
101 * The xform argument is an array of transformation functions (type
102 * tagview_strxform_f). The array, or any single entry, may be 0, but
103 * if the array is non-0 then it must have at least as many entries as
104 * colnames does. Each index corresponds directly to an entry in
105 * colnames and the SQL results. Any given entry may be 0 If it has
106 * fewer, undefined behaviour results. If a column has an entry in
107 * xform, then the xform function will be called to transform the
108 * column data before rendering it. This function takes care of freeing
109 * the strings created by the xform functions.
110 *
111 * Example:
112 *
113 * char const * const colnames[] = {
114 * "Tag ID", "Tag Name", "Something Else", "UUID"
115 * };
116 * tagview_strxform_f xf[] = {
117 * tagview_xf_link_to_tagid,
118 * tagview_xf_link_to_tagname,
119 * 0,
120 * tagview_xf_link_to_uuid
121 * };
122 * tagview_run_query( "select a,b,c,d from foo", colnames, xf );
123 *
124 */
125 static void tagview_run_query(
126 char const * sql,
127 char const * const * coln,
128 tagview_strxform_f * xform )
129 {
130
131 Stmt st;
132 @ <table cellpadding='4px' border='1'><tbody>
133 int i = 0;
134 int rc = db_prepare( &st, sql );
135 /**
136 Achtung: makeheaders apparently can't pull the function
137 name from this:
138 if( SQLITE_OK != db_prepare( &st, sql ) )
139 */
140 if( SQLITE_OK != rc )
141 {
142 @ tagview_run_query(): Error processing SQL: [%s(sql)]
143 return;
144 }
145 int colc = db_column_count(&st);
146 @ <tr>
147 for( i = 0; i < colc; ++i ) {
148 if( coln )
149 {
150 @ <th>%s(coln[i] ? coln[i] : db_column_name(&st,i))</th>
151 }
152 else
153 {
154 @ <td>%s(db_column_name(&st,i))</td>
155 }
156 }
157 @ </tr>
158
159
160 while( SQLITE_ROW == db_step(&st) ){
161 @ <tr>
162 for( i = 0; i < colc; ++i ) {
163 char * xf = 0;
164 char const * xcf = 0;
165 xcf = (xform && xform[i])
166 ? (xf=(xform[i])(db_column_text(&st,i)))
167 : db_column_text(&st,i);
168 @ <td>%s(xcf)</td>
169 if( xf ) free( xf );
170 }
171 @ </tr>
172 }
173 db_finalize( &st );
174 @ </tbody></table>
175 }
176
177 /**
178 Lists all tags matching the given LIKE clause (which
179 may be 0).
180 */
181 static void tagview_page_list_tags( char const * like )
182 {
 
183 char * likeclause = 0;
184 const int limit = 10;
185 char * limitstr = 0;
186 if( like && strlen(like) )
187 {
@@ -64,61 +191,37 @@
191 else
192 {
193 limitstr = mprintf( "LIMIT %d", limit );
194 @ <h2>%d(limit) most recent tags:</h2>
195 }
 
 
 
 
 
 
 
196 char * sql = mprintf(
197 "SELECT t.tagid, t.tagname, DATETIME(tx.mtime), b.uuid "
198 "FROM tag t, tagxref tx, blob b "
199 "WHERE (t.tagid=tx.tagid) and (tx.srcid=b.rid) "
200 "AND (tx.tagtype != 0) %s "
201 "ORDER BY tx.mtime DESC %s",
202 likeclause ? likeclause : " ",
203 limitstr ? limitstr : " "
204 );
205 /* " AND t.tagname NOT GLOB 'wiki-*'" // Do we want this?? */
206
207 char const * const colnames[] = {
208 "Tag ID", "Name", "Timestamp", "Version"
209 };
210 tagview_strxform_f xf[] = {
211 tagview_xf_link_to_tagid,
212 tagview_xf_link_to_tagname,
213 0,
214 tagview_xf_link_to_uuid
215 };
216 tagview_run_query( sql, colnames, xf );
217 free( sql );
218 }
219
220 /**
221 A small search form which forwards to ?like=SEARCH_STRING
222 */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223 static void tagview_page_search_miniform(void){
224 char const * like = P("like");
225 @ <div style='font-size:smaller'>
226 @ <form action='/tagview' method='post'>
227 @ Search for tags:
@@ -131,76 +234,56 @@
234
235 static void tagview_page_default(void){
236 tagview_page_list_tags( 0 );
237 }
238
239 /**
240 Lists all tags matching the given tagid.
241 */
242 static void tagview_page_tag_by_id( int tagid )
243 {
244 @ <h2>Tag #%d(tagid):</h2>
245 char * sql = mprintf(
246 "SELECT DISTINCT (t.tagname), DATETIME(tx.mtime), b.uuid "
247 "FROM tag t, tagxref tx, blob b "
248 "WHERE (t.tagid=%d) AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
249 "ORDER BY tx.mtime DESC",
250 tagid);
251 char const * const colnames[] = {
252 "Tag Name", "Timestamp", "Version"
253 };
254 tagview_strxform_f xf[] = {
255 tagview_xf_link_to_tagname,
256 0,
257 tagview_xf_link_to_uuid
258 };
259 tagview_run_query( sql, colnames, xf );
260 free(sql);
261 }
262
263 /**
264 Lists all tags matching the given tag name.
265 */
 
 
 
 
 
 
 
 
 
 
266 static void tagview_page_tag_by_name( char const * tagname )
267 {
268 @ <h2>Tag '%s(tagname)':</h2>
269 char * sql = mprintf(
270 "SELECT DISTINCT t.tagid, DATETIME(tx.mtime), b.uuid "
271 "FROM tag t, tagxref tx, blob b "
272 "WHERE (t.tagname='%q') AND (t.tagid=tx.tagid) AND (tx.srcid=b.rid) "
273 "ORDER BY tx.mtime DESC",
274 tagname);
275 char const * const colnames[] = {
276 "Tag ID", "Timestamp", "Version"
277 };
278 tagview_strxform_f xf[] = {
279 tagview_xf_link_to_tagid,
280 0,
281 tagview_xf_link_to_uuid
282 };
283 tagview_run_query( sql, colnames, xf );
284 free( sql );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
285 }
286
287
288 /*
289 ** WEBPAGE: /tagview
290

Keyboard Shortcuts

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