Fossil SCM

Added /json/report/run. Fixed an SQL syntax bug in report/list (only affected non-priveleged accounts).

stephan 2011-10-08 10:18 UTC json-multitag-test
Commit 8907163ea4c66147b79f82436160f78d341f6bb6
3 files changed +12 -8 +39 -2 +117 -5
+12 -8
--- ajax/index.html
+++ ajax/index.html
@@ -237,23 +237,27 @@
237237
<input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
238238
<input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
239239
<input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
240240
<input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
241241
<input type='button' value='tag/add'
242
-onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
242
+ onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
243243
<input type='button' value='tag/cancel'
244
-onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
244
+ onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
245245
<input type='button' value='tag/find'
246
-onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
246
+ onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
247247
<input type='button' value='diff'
248
-onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
248
+ onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
249249
<input type='button' value='diff/A/B'
250
-onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251
-<input type='button' value='report/list'
252
-onclick='TheApp.cgi.sendCommand("/json/report/list")' />
250
+ onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251
+
253252
<input type='button' value='query'
254
-onclick='TheApp.cgi.sendCommand("/json/query?format=o","SELECT * from user")' />
253
+ onclick='TheApp.cgi.sendCommand("/json/query?format=o","SELECT * from user")' />
254
+
255
+<input type='button' value='report list'
256
+ onclick='TheApp.cgi.sendCommand("/json/report/list")' />
257
+<input type='button' value='report run'
258
+ onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />
255259
256260
<!-- not yet ready...
257261
<input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
258262
-->
259263
260264
--- ajax/index.html
+++ ajax/index.html
@@ -237,23 +237,27 @@
237 <input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
238 <input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
239 <input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
240 <input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
241 <input type='button' value='tag/add'
242 onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
243 <input type='button' value='tag/cancel'
244 onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
245 <input type='button' value='tag/find'
246 onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
247 <input type='button' value='diff'
248 onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
249 <input type='button' value='diff/A/B'
250 onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251 <input type='button' value='report/list'
252 onclick='TheApp.cgi.sendCommand("/json/report/list")' />
253 <input type='button' value='query'
254 onclick='TheApp.cgi.sendCommand("/json/query?format=o","SELECT * from user")' />
 
 
 
 
 
255
256 <!-- not yet ready...
257 <input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
258 -->
259
260
--- ajax/index.html
+++ ajax/index.html
@@ -237,23 +237,27 @@
237 <input type='button' value='user/get' onclick='TheApp.cgi.sendCommand("/json/user/get?name=anonymous")' />
238 <input type='button' value='resultCodes' onclick='TheApp.cgi.sendCommand("/json/resultCodes")' />
239 <input type='button' value='tag/list' onclick='TheApp.cgi.sendCommand("/json/tag/list?includeTickets=false&raw=false")' />
240 <input type='button' value='tag/list/json' onclick='TheApp.cgi.sendCommand("/json/tag/list/json?raw=false")' />
241 <input type='button' value='tag/add'
242 onclick='TheApp.cgi.sendCommand("/json/tag/add",{name:"json-add-tag-test",checkin:"json",value:"tag test",propagate:false,raw:false})' />
243 <input type='button' value='tag/cancel'
244 onclick='TheApp.cgi.sendCommand("/json/tag/cancel",{name:"json-add-tag-test",checkin:"json",raw:false})' />
245 <input type='button' value='tag/find'
246 onclick='TheApp.cgi.sendCommand("/json/tag/find",{name:"json",type:"*",raw:false,limit:5})' />
247 <input type='button' value='diff'
248 onclick='TheApp.cgi.sendCommand("/json/diff",{v1:"b0e9b45baed6f885",v2:"5f225e261d836287",context:2})' />
249 <input type='button' value='diff/A/B'
250 onclick='TheApp.cgi.sendCommand("/json/diff/b0e9b45baed6f885/5f225e261d836287?context=2")' />
251
 
252 <input type='button' value='query'
253 onclick='TheApp.cgi.sendCommand("/json/query?format=o","SELECT * from user")' />
254
255 <input type='button' value='report list'
256 onclick='TheApp.cgi.sendCommand("/json/report/list")' />
257 <input type='button' value='report run'
258 onclick='TheApp.cgi.sendCommand("/json/report/run",{"report":2,"format":"o"})' />
259
260 <!-- not yet ready...
261 <input type='button' value='artifact/XYZ' onclick='TheApp.cgi.sendCommand("/json/artifact?uuid=json")' />
262 -->
263
264
+39 -2
--- src/json.c
+++ src/json.c
@@ -1315,10 +1315,15 @@
13151315
char const * part;
13161316
unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
13171317
unsigned int i = 1;
13181318
for( ; i < aLen; ++i ){
13191319
char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
1320
+ if(!part){
1321
+ fossil_warning("Iterating further than expected in %s.",
1322
+ __FILE__);
1323
+ break;
1324
+ }
13201325
blob_append(&path,part,-1);
13211326
if(i < (aLen-1)){
13221327
blob_append(&path,"/",1);
13231328
}
13241329
}
@@ -1592,26 +1597,58 @@
15921597
if(warnMsg){
15931598
json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
15941599
}
15951600
return v;
15961601
}
1602
+
1603
+/*
1604
+** Works just like json_stmt_to_array_of_obj(), but
1605
+** each row in the result set is represented as an
1606
+** Array instead of an Object.
1607
+*/
1608
+cson_value * json_stmt_to_array_of_array(Stmt *pStmt,
1609
+ cson_value * pTgt){
1610
+ cson_value * v = pTgt;
1611
+ cson_array * a = NULL;
1612
+ if(v && !cson_value_is_array(v)){
1613
+ return NULL;
1614
+ }
1615
+ while( (SQLITE_ROW==db_step(pStmt)) ){
1616
+ cson_value * row = NULL;
1617
+ if(!a){
1618
+ if(!v){
1619
+ v = cson_value_new_array();
1620
+ }
1621
+ a = cson_value_get_array(v);
1622
+ assert(NULL!=a);
1623
+ }
1624
+ row = cson_sqlite3_row_to_array(pStmt->pStmt);
1625
+ cson_array_append(a, row);
1626
+ }
1627
+ return v;
1628
+}
1629
+
15971630
15981631
/*
15991632
** Executes the given SQL and runs it through
16001633
** json_stmt_to_array_of_obj(), returning the result of that
16011634
** function. If resetBlob is true then blob_reset(pSql) is called
16021635
** after preparing the query.
1636
+**
1637
+** pTgt has the same semantics as described for
1638
+** json_stmt_to_array_of_obj().
16031639
*/
1604
-cson_value * json_sql_to_array_of_obj(Blob * pSql, char resetBlob){
1640
+cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_value * pTgt,
1641
+ char resetBlob){
16051642
Stmt q = empty_Stmt;
16061643
cson_value * pay = NULL;
16071644
assert( blob_size(pSql) > 0 );
16081645
db_prepare(&q, "%s", blob_str(pSql));
16091646
if(resetBlob){
16101647
blob_reset(pSql);
16111648
}
1612
- pay = json_stmt_to_array_of_obj(&q, NULL);
1649
+ pay = json_stmt_to_array_of_obj(&q, pTgt);
16131650
db_finalize(&q);
16141651
return pay;
16151652
16161653
}
16171654
16181655
--- src/json.c
+++ src/json.c
@@ -1315,10 +1315,15 @@
1315 char const * part;
1316 unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
1317 unsigned int i = 1;
1318 for( ; i < aLen; ++i ){
1319 char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
 
 
 
 
 
1320 blob_append(&path,part,-1);
1321 if(i < (aLen-1)){
1322 blob_append(&path,"/",1);
1323 }
1324 }
@@ -1592,26 +1597,58 @@
1592 if(warnMsg){
1593 json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
1594 }
1595 return v;
1596 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1597
1598 /*
1599 ** Executes the given SQL and runs it through
1600 ** json_stmt_to_array_of_obj(), returning the result of that
1601 ** function. If resetBlob is true then blob_reset(pSql) is called
1602 ** after preparing the query.
 
 
 
1603 */
1604 cson_value * json_sql_to_array_of_obj(Blob * pSql, char resetBlob){
 
1605 Stmt q = empty_Stmt;
1606 cson_value * pay = NULL;
1607 assert( blob_size(pSql) > 0 );
1608 db_prepare(&q, "%s", blob_str(pSql));
1609 if(resetBlob){
1610 blob_reset(pSql);
1611 }
1612 pay = json_stmt_to_array_of_obj(&q, NULL);
1613 db_finalize(&q);
1614 return pay;
1615
1616 }
1617
1618
--- src/json.c
+++ src/json.c
@@ -1315,10 +1315,15 @@
1315 char const * part;
1316 unsigned int aLen = g.json.dispatchDepth+1; /*cson_array_length_get(g.json.cmd.a);*/
1317 unsigned int i = 1;
1318 for( ; i < aLen; ++i ){
1319 char const * part = cson_string_cstr(cson_value_get_string(cson_array_get(g.json.cmd.a, i)));
1320 if(!part){
1321 fossil_warning("Iterating further than expected in %s.",
1322 __FILE__);
1323 break;
1324 }
1325 blob_append(&path,part,-1);
1326 if(i < (aLen-1)){
1327 blob_append(&path,"/",1);
1328 }
1329 }
@@ -1592,26 +1597,58 @@
1597 if(warnMsg){
1598 json_warn( FSL_JSON_W_ROW_TO_JSON_FAILED, warnMsg );
1599 }
1600 return v;
1601 }
1602
1603 /*
1604 ** Works just like json_stmt_to_array_of_obj(), but
1605 ** each row in the result set is represented as an
1606 ** Array instead of an Object.
1607 */
1608 cson_value * json_stmt_to_array_of_array(Stmt *pStmt,
1609 cson_value * pTgt){
1610 cson_value * v = pTgt;
1611 cson_array * a = NULL;
1612 if(v && !cson_value_is_array(v)){
1613 return NULL;
1614 }
1615 while( (SQLITE_ROW==db_step(pStmt)) ){
1616 cson_value * row = NULL;
1617 if(!a){
1618 if(!v){
1619 v = cson_value_new_array();
1620 }
1621 a = cson_value_get_array(v);
1622 assert(NULL!=a);
1623 }
1624 row = cson_sqlite3_row_to_array(pStmt->pStmt);
1625 cson_array_append(a, row);
1626 }
1627 return v;
1628 }
1629
1630
1631 /*
1632 ** Executes the given SQL and runs it through
1633 ** json_stmt_to_array_of_obj(), returning the result of that
1634 ** function. If resetBlob is true then blob_reset(pSql) is called
1635 ** after preparing the query.
1636 **
1637 ** pTgt has the same semantics as described for
1638 ** json_stmt_to_array_of_obj().
1639 */
1640 cson_value * json_sql_to_array_of_obj(Blob * pSql, cson_value * pTgt,
1641 char resetBlob){
1642 Stmt q = empty_Stmt;
1643 cson_value * pay = NULL;
1644 assert( blob_size(pSql) > 0 );
1645 db_prepare(&q, "%s", blob_str(pSql));
1646 if(resetBlob){
1647 blob_reset(pSql);
1648 }
1649 pay = json_stmt_to_array_of_obj(&q, pTgt);
1650 db_finalize(&q);
1651 return pay;
1652
1653 }
1654
1655
+117 -5
--- src/json_report.c
+++ src/json_report.c
@@ -34,11 +34,11 @@
3434
*/
3535
static const JsonPageDef JsonPageDefs_Report[] = {
3636
{"create", json_report_create, 0},
3737
{"get", json_report_get, 0},
3838
{"list", json_report_list, 0},
39
-{"run", json_report_run, 1},
39
+{"run", json_report_run, 0},
4040
{"save", json_report_save, 0},
4141
/* Last entry MUST have a NULL name. */
4242
{NULL,NULL,0}
4343
};
4444
/*
@@ -66,29 +66,141 @@
6666
6767
static cson_value * json_report_list(){
6868
Blob sql = empty_blob;
6969
cson_value * pay = NULL;
7070
blob_append(&sql, "SELECT"
71
- " rn number,"
71
+ " rn AS report,"
7272
" title as title,"
7373
" owner as owner"
74
- " FROM reportfmt", -1);
74
+ " FROM reportfmt"
75
+ " WHERE 1", -1);
76
+ /* This logic was adapted from the HTML mode report list
77
+ page. However, for reasons i cannot explain, enbling this block
78
+ causes a crash in CGI mode when request is made via a user
79
+ without TktFmt.
80
+ */
7581
if(!g.perm.TktFmt){
7682
blob_append(&sql,
7783
" AND title NOT LIKE '_%'", -1);
7884
}
7985
blob_append(&sql," ORDER BY title",-1);
80
- pay = json_sql_to_array_of_obj(&sql, 1);
86
+ pay = json_sql_to_array_of_obj(&sql, NULL, 1);
8187
if(!pay){
8288
json_set_err(FSL_JSON_E_UNKNOWN,
8389
"Quite unexpected: no ticket reports found.");
8490
}
8591
return pay;
8692
}
8793
94
+/*
95
+** Impl for /json/report/run
96
+**
97
+** Options/arguments:
98
+**
99
+** report=int (CLI: -report # or -r #) is the report number to run.
100
+**
101
+** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands.
102
+**
103
+** format=a|o Specifies result format: a=each row is an arry, o=each
104
+** row is an object. Default=o.
105
+*/
88106
static cson_value * json_report_run(){
89
- return NULL;
107
+ int nReport;
108
+ Stmt q = empty_Stmt;
109
+ cson_object * pay = NULL;
110
+ cson_array * tktList = NULL;
111
+ char const * zFmt;
112
+ char * zTitle = NULL;
113
+ Blob sql = empty_blob;
114
+ int limit = 0;
115
+ cson_value * colNames = NULL;
116
+ int i;
117
+
118
+ nReport = json_find_option_int("report",NULL,"r",-1);
119
+ if( nReport <= 0 ){
120
+ char const * arg = json_command_arg(3);
121
+ if(arg && fossil_isdigit(*arg)) {
122
+ nReport = atoi(arg);
123
+ }
124
+ }
125
+ if(nReport <=0){
126
+ json_set_err(FSL_JSON_E_MISSING_ARGS,
127
+ "Missing or invalid 'number' (-n) parameter.");
128
+ goto error;
129
+ }
130
+ zFmt = json_find_option_cstr2("format",NULL,"f",3);
131
+ if(!zFmt) zFmt = "o";
132
+ db_prepare(&q,
133
+ "SELECT sqlcode, "
134
+ " title"
135
+ " FROM reportfmt"
136
+ " WHERE rn=%d",
137
+ nReport);
138
+ if(SQLITE_ROW != db_step(&q)){
139
+ json_set_err(FSL_JSON_E_INVALID_ARGS,
140
+ "Report number %d not found.",
141
+ nReport);
142
+ db_finalize(&q);
143
+ goto error;
144
+ }
145
+
146
+ limit = json_find_option_int("limit",NULL,"n",-1);
147
+
148
+
149
+ /* Copy over report's SQL...*/
150
+ blob_append(&sql, db_column_text(&q,0), -1);
151
+ zTitle = mprintf("%s", db_column_text(&q,1));
152
+ db_finalize(&q);
153
+ db_prepare(&q, "%s", blob_str(&sql));
154
+
155
+ /** Build the response... */
156
+ pay = cson_new_object();
157
+
158
+ cson_object_set(pay, "report", json_new_int(nReport));
159
+ cson_object_set(pay, "title", json_new_string(zTitle));
160
+ if(limit>0){
161
+ cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
162
+ }
163
+ free(zTitle);
164
+ zTitle = NULL;
165
+
166
+ if(g.perm.WrTkt){
167
+ cson_object_set(pay, "sqlcode",
168
+ cson_value_new_string(blob_str(&sql),
169
+ (unsigned int)blob_size(&sql)));
170
+ }
171
+ blob_reset(&sql);
172
+
173
+ colNames = cson_sqlite3_column_names(q.pStmt);
174
+ cson_object_set( pay, "columnNames", colNames);
175
+ for( i = 0 ; ((limit>0) ?(i < limit) : 1)
176
+ && (SQLITE_ROW == db_step(&q));
177
+ ++i){
178
+ cson_value * row = ('a'==*zFmt)
179
+ ? cson_sqlite3_row_to_array(q.pStmt)
180
+ : cson_sqlite3_row_to_object2(q.pStmt,
181
+ cson_value_get_array(colNames));
182
+ ;
183
+ if(row && !tktList){
184
+ tktList = cson_new_array();
185
+ }
186
+ cson_array_append(tktList, row);
187
+ }
188
+ db_finalize(&q);
189
+ cson_object_set(pay, "tickets",
190
+ tktList ? cson_array_value(tktList) : cson_value_null());
191
+
192
+ goto end;
193
+
194
+ error:
195
+ assert(0 != g.json.resultCode);
196
+ cson_value_free( cson_object_value(pay) );
197
+ pay = NULL;
198
+ end:
199
+
200
+ return pay ? cson_object_value(pay) : NULL;
201
+
90202
}
91203
92204
static cson_value * json_report_save(){
93205
return NULL;
94206
}
95207
--- src/json_report.c
+++ src/json_report.c
@@ -34,11 +34,11 @@
34 */
35 static const JsonPageDef JsonPageDefs_Report[] = {
36 {"create", json_report_create, 0},
37 {"get", json_report_get, 0},
38 {"list", json_report_list, 0},
39 {"run", json_report_run, 1},
40 {"save", json_report_save, 0},
41 /* Last entry MUST have a NULL name. */
42 {NULL,NULL,0}
43 };
44 /*
@@ -66,29 +66,141 @@
66
67 static cson_value * json_report_list(){
68 Blob sql = empty_blob;
69 cson_value * pay = NULL;
70 blob_append(&sql, "SELECT"
71 " rn number,"
72 " title as title,"
73 " owner as owner"
74 " FROM reportfmt", -1);
 
 
 
 
 
 
75 if(!g.perm.TktFmt){
76 blob_append(&sql,
77 " AND title NOT LIKE '_%'", -1);
78 }
79 blob_append(&sql," ORDER BY title",-1);
80 pay = json_sql_to_array_of_obj(&sql, 1);
81 if(!pay){
82 json_set_err(FSL_JSON_E_UNKNOWN,
83 "Quite unexpected: no ticket reports found.");
84 }
85 return pay;
86 }
87
 
 
 
 
 
 
 
 
 
 
 
 
88 static cson_value * json_report_run(){
89 return NULL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90 }
91
92 static cson_value * json_report_save(){
93 return NULL;
94 }
95
--- src/json_report.c
+++ src/json_report.c
@@ -34,11 +34,11 @@
34 */
35 static const JsonPageDef JsonPageDefs_Report[] = {
36 {"create", json_report_create, 0},
37 {"get", json_report_get, 0},
38 {"list", json_report_list, 0},
39 {"run", json_report_run, 0},
40 {"save", json_report_save, 0},
41 /* Last entry MUST have a NULL name. */
42 {NULL,NULL,0}
43 };
44 /*
@@ -66,29 +66,141 @@
66
67 static cson_value * json_report_list(){
68 Blob sql = empty_blob;
69 cson_value * pay = NULL;
70 blob_append(&sql, "SELECT"
71 " rn AS report,"
72 " title as title,"
73 " owner as owner"
74 " FROM reportfmt"
75 " WHERE 1", -1);
76 /* This logic was adapted from the HTML mode report list
77 page. However, for reasons i cannot explain, enbling this block
78 causes a crash in CGI mode when request is made via a user
79 without TktFmt.
80 */
81 if(!g.perm.TktFmt){
82 blob_append(&sql,
83 " AND title NOT LIKE '_%'", -1);
84 }
85 blob_append(&sql," ORDER BY title",-1);
86 pay = json_sql_to_array_of_obj(&sql, NULL, 1);
87 if(!pay){
88 json_set_err(FSL_JSON_E_UNKNOWN,
89 "Quite unexpected: no ticket reports found.");
90 }
91 return pay;
92 }
93
94 /*
95 ** Impl for /json/report/run
96 **
97 ** Options/arguments:
98 **
99 ** report=int (CLI: -report # or -r #) is the report number to run.
100 **
101 ** limit=int (CLI: -limit # or -n #) -n is for compat. with other commands.
102 **
103 ** format=a|o Specifies result format: a=each row is an arry, o=each
104 ** row is an object. Default=o.
105 */
106 static cson_value * json_report_run(){
107 int nReport;
108 Stmt q = empty_Stmt;
109 cson_object * pay = NULL;
110 cson_array * tktList = NULL;
111 char const * zFmt;
112 char * zTitle = NULL;
113 Blob sql = empty_blob;
114 int limit = 0;
115 cson_value * colNames = NULL;
116 int i;
117
118 nReport = json_find_option_int("report",NULL,"r",-1);
119 if( nReport <= 0 ){
120 char const * arg = json_command_arg(3);
121 if(arg && fossil_isdigit(*arg)) {
122 nReport = atoi(arg);
123 }
124 }
125 if(nReport <=0){
126 json_set_err(FSL_JSON_E_MISSING_ARGS,
127 "Missing or invalid 'number' (-n) parameter.");
128 goto error;
129 }
130 zFmt = json_find_option_cstr2("format",NULL,"f",3);
131 if(!zFmt) zFmt = "o";
132 db_prepare(&q,
133 "SELECT sqlcode, "
134 " title"
135 " FROM reportfmt"
136 " WHERE rn=%d",
137 nReport);
138 if(SQLITE_ROW != db_step(&q)){
139 json_set_err(FSL_JSON_E_INVALID_ARGS,
140 "Report number %d not found.",
141 nReport);
142 db_finalize(&q);
143 goto error;
144 }
145
146 limit = json_find_option_int("limit",NULL,"n",-1);
147
148
149 /* Copy over report's SQL...*/
150 blob_append(&sql, db_column_text(&q,0), -1);
151 zTitle = mprintf("%s", db_column_text(&q,1));
152 db_finalize(&q);
153 db_prepare(&q, "%s", blob_str(&sql));
154
155 /** Build the response... */
156 pay = cson_new_object();
157
158 cson_object_set(pay, "report", json_new_int(nReport));
159 cson_object_set(pay, "title", json_new_string(zTitle));
160 if(limit>0){
161 cson_object_set(pay, "limit", json_new_int((limit<0) ? 0 : limit));
162 }
163 free(zTitle);
164 zTitle = NULL;
165
166 if(g.perm.WrTkt){
167 cson_object_set(pay, "sqlcode",
168 cson_value_new_string(blob_str(&sql),
169 (unsigned int)blob_size(&sql)));
170 }
171 blob_reset(&sql);
172
173 colNames = cson_sqlite3_column_names(q.pStmt);
174 cson_object_set( pay, "columnNames", colNames);
175 for( i = 0 ; ((limit>0) ?(i < limit) : 1)
176 && (SQLITE_ROW == db_step(&q));
177 ++i){
178 cson_value * row = ('a'==*zFmt)
179 ? cson_sqlite3_row_to_array(q.pStmt)
180 : cson_sqlite3_row_to_object2(q.pStmt,
181 cson_value_get_array(colNames));
182 ;
183 if(row && !tktList){
184 tktList = cson_new_array();
185 }
186 cson_array_append(tktList, row);
187 }
188 db_finalize(&q);
189 cson_object_set(pay, "tickets",
190 tktList ? cson_array_value(tktList) : cson_value_null());
191
192 goto end;
193
194 error:
195 assert(0 != g.json.resultCode);
196 cson_value_free( cson_object_value(pay) );
197 pay = NULL;
198 end:
199
200 return pay ? cson_object_value(pay) : NULL;
201
202 }
203
204 static cson_value * json_report_save(){
205 return NULL;
206 }
207

Keyboard Shortcuts

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