1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, March 2000
25 */
26 /**
27 * @file
28 * BAREOS Catalog Database List records interface routines
29 */
30
31 #include "include/bareos.h"
32
33 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
34
35 # include "cats.h"
36 # include "lib/edit.h"
37
38 /* -----------------------------------------------------------------------
39 *
40 * Generic Routines (or almost generic)
41 *
42 * -----------------------------------------------------------------------
43 */
44
45 /**
46 * Submit general SQL query
47 */
ListSqlQuery(JobControlRecord * jcr,const char * query,OutputFormatter * sendit,e_list_type type,bool verbose)48 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
49 const char* query,
50 OutputFormatter* sendit,
51 e_list_type type,
52 bool verbose)
53 {
54 return ListSqlQuery(jcr, query, sendit, type, "query", verbose);
55 }
56
ListSqlQuery(JobControlRecord * jcr,SQL_QUERY query,OutputFormatter * sendit,e_list_type type,bool verbose)57 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
58 SQL_QUERY query,
59 OutputFormatter* sendit,
60 e_list_type type,
61 bool verbose)
62 {
63 return ListSqlQuery(jcr, query, sendit, type, "query", verbose);
64 }
65
ListSqlQuery(JobControlRecord * jcr,const char * query,OutputFormatter * sendit,e_list_type type,const char * description,bool verbose)66 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
67 const char* query,
68 OutputFormatter* sendit,
69 e_list_type type,
70 const char* description,
71 bool verbose)
72 {
73 bool retval = false;
74
75 DbLock(this);
76
77 if (!SqlQuery(query, QF_STORE_RESULT)) {
78 Mmsg(errmsg, _("Query failed: %s\n"), sql_strerror());
79 if (verbose) { sendit->Decoration(errmsg); }
80 goto bail_out;
81 }
82
83 sendit->ArrayStart(description);
84 ListResult(jcr, sendit, type);
85 sendit->ArrayEnd(description);
86 SqlFreeResult();
87 retval = true;
88
89 bail_out:
90 DbUnlock(this);
91 return retval;
92 }
93
ListSqlQuery(JobControlRecord * jcr,SQL_QUERY query,OutputFormatter * sendit,e_list_type type,const char * description,bool verbose)94 bool BareosDb::ListSqlQuery(JobControlRecord* jcr,
95 SQL_QUERY query,
96 OutputFormatter* sendit,
97 e_list_type type,
98 const char* description,
99 bool verbose)
100 {
101 return ListSqlQuery(jcr, get_predefined_query(query), sendit, type,
102 description, verbose);
103 }
104
ListPoolRecords(JobControlRecord * jcr,PoolDbRecord * pdbr,OutputFormatter * sendit,e_list_type type)105 void BareosDb::ListPoolRecords(JobControlRecord* jcr,
106 PoolDbRecord* pdbr,
107 OutputFormatter* sendit,
108 e_list_type type)
109 {
110 char esc[MAX_ESCAPE_NAME_LENGTH];
111
112 DbLock(this);
113 EscapeString(jcr, esc, pdbr->Name, strlen(pdbr->Name));
114
115 if (type == VERT_LIST) {
116 if (pdbr->Name[0] != 0) {
117 Mmsg(cmd,
118 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
119 "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
120 "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
121 "RecyclePoolId,LabelType "
122 "FROM Pool WHERE Name='%s'",
123 esc);
124 } else {
125 Mmsg(cmd,
126 "SELECT PoolId,Name,NumVols,MaxVols,UseOnce,UseCatalog,"
127 "AcceptAnyVolume,VolRetention,VolUseDuration,MaxVolJobs,MaxVolBytes,"
128 "AutoPrune,Recycle,PoolType,LabelFormat,Enabled,ScratchPoolId,"
129 "RecyclePoolId,LabelType "
130 "FROM Pool ORDER BY PoolId");
131 }
132 } else {
133 if (pdbr->Name[0] != 0) {
134 Mmsg(cmd,
135 "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
136 "FROM Pool WHERE Name='%s'",
137 esc);
138 } else {
139 Mmsg(cmd,
140 "SELECT PoolId,Name,NumVols,MaxVols,PoolType,LabelFormat "
141 "FROM Pool ORDER BY PoolId");
142 }
143 }
144
145 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
146
147 sendit->ArrayStart("pools");
148 ListResult(jcr, sendit, type);
149 sendit->ArrayEnd("pools");
150
151 SqlFreeResult();
152
153 bail_out:
154 DbUnlock(this);
155 }
156
ListClientRecords(JobControlRecord * jcr,char * clientname,OutputFormatter * sendit,e_list_type type)157 void BareosDb::ListClientRecords(JobControlRecord* jcr,
158 char* clientname,
159 OutputFormatter* sendit,
160 e_list_type type)
161 {
162 DbLock(this);
163 PoolMem clientfilter(PM_MESSAGE);
164
165 if (clientname) { clientfilter.bsprintf("WHERE Name = '%s'", clientname); }
166 if (type == VERT_LIST) {
167 Mmsg(cmd,
168 "SELECT ClientId,Name,Uname,AutoPrune,FileRetention,"
169 "JobRetention "
170 "FROM Client %s ORDER BY ClientId ",
171 clientfilter.c_str());
172 } else {
173 Mmsg(cmd,
174 "SELECT ClientId,Name,FileRetention,JobRetention "
175 "FROM Client %s ORDER BY ClientId",
176 clientfilter.c_str());
177 }
178
179 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
180
181 sendit->ArrayStart("clients");
182 ListResult(jcr, sendit, type);
183 sendit->ArrayEnd("clients");
184
185 SqlFreeResult();
186
187 bail_out:
188 DbUnlock(this);
189 }
190
ListStorageRecords(JobControlRecord * jcr,OutputFormatter * sendit,e_list_type type)191 void BareosDb::ListStorageRecords(JobControlRecord* jcr,
192 OutputFormatter* sendit,
193 e_list_type type)
194 {
195 DbLock(this);
196
197 Mmsg(cmd, "SELECT StorageId,Name,AutoChanger FROM Storage");
198
199 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
200
201 sendit->ArrayStart("storages");
202 ListResult(jcr, sendit, type);
203 sendit->ArrayEnd("storages");
204
205 SqlFreeResult();
206
207 bail_out:
208 DbUnlock(this);
209 }
210
211 /**
212 * If VolumeName is non-zero, list the record for that Volume
213 * otherwise, list the Volumes in the Pool specified by PoolId
214 */
ListMediaRecords(JobControlRecord * jcr,MediaDbRecord * mdbr,const char * range,bool count,OutputFormatter * sendit,e_list_type type)215 void BareosDb::ListMediaRecords(JobControlRecord* jcr,
216 MediaDbRecord* mdbr,
217 const char* range,
218 bool count,
219 OutputFormatter* sendit,
220 e_list_type type)
221 {
222 char ed1[50];
223 char esc[MAX_ESCAPE_NAME_LENGTH];
224 PoolMem select(PM_MESSAGE);
225 PoolMem query(PM_MESSAGE);
226
227 EscapeString(jcr, esc, mdbr->VolumeName, strlen(mdbr->VolumeName));
228
229 /*
230 * There is one case where ListMediaRecords() is called from SelectMediaDbr()
231 * with the range argument set to NULL. To avoid problems, we set the range to
232 * an empty string if range is set to NULL. Otherwise it would result in
233 * malformed SQL queries.
234 */
235 if (range == NULL) { range = ""; }
236
237 if (count) {
238 /* NOTE: ACLs are ignored. */
239 if (mdbr->VolumeName[0] != 0) {
240 FillQuery(query, SQL_QUERY::list_volumes_by_name_count_1, esc);
241 } else if (mdbr->PoolId > 0) {
242 FillQuery(query, SQL_QUERY::list_volumes_by_poolid_count_1,
243 edit_int64(mdbr->PoolId, ed1));
244 } else {
245 FillQuery(query, SQL_QUERY::list_volumes_count_0);
246 }
247 } else {
248 if (type == VERT_LIST) {
249 FillQuery(select, SQL_QUERY::list_volumes_select_long_0);
250 } else {
251 FillQuery(select, SQL_QUERY::list_volumes_select_0);
252 }
253
254 if (mdbr->VolumeName[0] != 0) {
255 query.bsprintf("%s WHERE VolumeName='%s'", select.c_str(), esc);
256 } else if (mdbr->PoolId > 0) {
257 query.bsprintf("%s WHERE PoolId=%s ORDER BY MediaId %s", select.c_str(),
258 edit_int64(mdbr->PoolId, ed1), range);
259 } else {
260 query.bsprintf("%s ORDER BY MediaId %s", select.c_str(), range);
261 }
262 }
263
264 DbLock(this);
265
266 if (!QUERY_DB(jcr, query.c_str())) { goto bail_out; }
267
268 ListResult(jcr, sendit, type);
269
270 SqlFreeResult();
271
272 bail_out:
273 DbUnlock(this);
274 }
275
276
ListJobmediaRecords(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)277 void BareosDb::ListJobmediaRecords(JobControlRecord* jcr,
278 uint32_t JobId,
279 OutputFormatter* sendit,
280 e_list_type type)
281 {
282 char ed1[50];
283
284 DbLock(this);
285 if (type == VERT_LIST) {
286 if (JobId > 0) { /* do by JobId */
287 Mmsg(cmd,
288 "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
289 "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
290 "JobMedia.EndBlock "
291 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
292 "AND JobMedia.JobId=%s",
293 edit_int64(JobId, ed1));
294 } else {
295 Mmsg(cmd,
296 "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName,"
297 "FirstIndex,LastIndex,StartFile,JobMedia.EndFile,StartBlock,"
298 "JobMedia.EndBlock "
299 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
300 }
301
302 } else {
303 if (JobId > 0) { /* do by JobId */
304 Mmsg(cmd,
305 "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
306 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
307 "AND JobMedia.JobId=%s",
308 edit_int64(JobId, ed1));
309 } else {
310 Mmsg(cmd,
311 "SELECT JobId,Media.VolumeName,FirstIndex,LastIndex "
312 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId");
313 }
314 }
315 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
316
317 sendit->ArrayStart("jobmedia");
318 ListResult(jcr, sendit, type);
319 sendit->ArrayEnd("jobmedia");
320
321 SqlFreeResult();
322
323 bail_out:
324 DbUnlock(this);
325 }
326
327
ListVolumesOfJobid(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)328 void BareosDb::ListVolumesOfJobid(JobControlRecord* jcr,
329 uint32_t JobId,
330 OutputFormatter* sendit,
331 e_list_type type)
332 {
333 char ed1[50];
334
335 if (JobId <= 0) { return; }
336
337 DbLock(this);
338 if (type == VERT_LIST) {
339 Mmsg(cmd,
340 "SELECT JobMediaId,JobId,Media.MediaId,Media.VolumeName "
341 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
342 "AND JobMedia.JobId=%s",
343 edit_int64(JobId, ed1));
344 } else {
345 Mmsg(cmd,
346 "SELECT DISTINCT Media.VolumeName "
347 "FROM JobMedia,Media WHERE Media.MediaId=JobMedia.MediaId "
348 "AND JobMedia.JobId=%s",
349 edit_int64(JobId, ed1));
350 }
351 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
352
353 sendit->ArrayStart("volumes");
354 ListResult(jcr, sendit, type);
355 sendit->ArrayEnd("volumes");
356
357 SqlFreeResult();
358
359 bail_out:
360 DbUnlock(this);
361 }
362
363
ListCopiesRecords(JobControlRecord * jcr,const char * range,const char * JobIds,OutputFormatter * send,e_list_type type)364 void BareosDb::ListCopiesRecords(JobControlRecord* jcr,
365 const char* range,
366 const char* JobIds,
367 OutputFormatter* send,
368 e_list_type type)
369 {
370 PoolMem str_jobids(PM_MESSAGE);
371
372 if (JobIds && JobIds[0]) {
373 Mmsg(str_jobids, " AND (Job.PriorJobId IN (%s) OR Job.JobId IN (%s)) ",
374 JobIds, JobIds);
375 }
376
377 DbLock(this);
378 Mmsg(cmd,
379 "SELECT DISTINCT Job.PriorJobId AS JobId, Job.Job, "
380 "Job.JobId AS CopyJobId, Media.MediaType "
381 "FROM Job "
382 "JOIN JobMedia USING (JobId) "
383 "JOIN Media USING (MediaId) "
384 "WHERE Job.Type = '%c' %s ORDER BY Job.PriorJobId DESC %s",
385 (char)JT_JOB_COPY, str_jobids.c_str(), range);
386
387 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
388
389 if (SqlNumRows()) {
390 if (JobIds && JobIds[0]) {
391 send->Decoration(_("These JobIds have copies as follows:\n"));
392 } else {
393 send->Decoration(_("The catalog contains copies as follows:\n"));
394 }
395
396 send->ArrayStart("copies");
397 ListResult(jcr, send, type);
398 send->ArrayEnd("copies");
399 }
400
401 SqlFreeResult();
402
403 bail_out:
404 DbUnlock(this);
405 }
406
ListLogRecords(JobControlRecord * jcr,const char * clientname,const char * range,bool reverse,OutputFormatter * sendit,e_list_type type)407 void BareosDb::ListLogRecords(JobControlRecord* jcr,
408 const char* clientname,
409 const char* range,
410 bool reverse,
411 OutputFormatter* sendit,
412 e_list_type type)
413 {
414 PoolMem client_filter(PM_MESSAGE);
415
416 if (clientname) {
417 Mmsg(client_filter, "AND Client.Name = '%s' ", clientname);
418 }
419
420 if (reverse) {
421 Mmsg(cmd,
422 "SELECT LogId, Job.Name AS JobName, Client.Name AS ClientName, Time, "
423 "LogText "
424 "FROM Log "
425 "JOIN Job USING (JobId) "
426 "LEFT JOIN Client USING (ClientId) "
427 "WHERE Job.Type != 'C' "
428 "%s"
429 "ORDER BY Log.LogId DESC %s",
430 client_filter.c_str(), range);
431 } else {
432 Mmsg(cmd,
433 "SELECT LogId, JobName, ClientName, Time, LogText FROM ("
434 "SELECT LogId, Job.Name AS JobName, Client.Name As ClientName, Time, "
435 "LogText "
436 "FROM Log "
437 "JOIN Job USING (JobId) "
438 "LEFT JOIN Client USING (ClientId) "
439 "WHERE Job.Type != 'C' "
440 "%s"
441 "ORDER BY Log.LogId DESC %s"
442 ") AS sub ORDER BY LogId ASC",
443 client_filter.c_str(), range);
444 }
445
446 if (type != VERT_LIST) {
447 /*
448 * When something else then a vertical list is requested set the list type
449 * to RAW_LIST e.g. non formated raw data as that makes the only sense for
450 * the logtext output. The logtext already has things like \n etc in it
451 * so we should just dump the raw content out for the best visible output.
452 */
453 type = RAW_LIST;
454 }
455
456 DbLock(this);
457
458 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
459
460 sendit->ArrayStart("log");
461 ListResult(jcr, sendit, type);
462 sendit->ArrayEnd("log");
463
464 SqlFreeResult();
465
466 bail_out:
467 DbUnlock(this);
468 }
469
ListJoblogRecords(JobControlRecord * jcr,uint32_t JobId,const char * range,bool count,OutputFormatter * sendit,e_list_type type)470 void BareosDb::ListJoblogRecords(JobControlRecord* jcr,
471 uint32_t JobId,
472 const char* range,
473 bool count,
474 OutputFormatter* sendit,
475 e_list_type type)
476 {
477 char ed1[50];
478
479 if (JobId <= 0) { return; }
480
481 DbLock(this);
482 if (count) {
483 FillQuery(SQL_QUERY::list_joblog_count_1, edit_int64(JobId, ed1));
484 } else {
485 FillQuery(SQL_QUERY::list_joblog_2, edit_int64(JobId, ed1), range);
486 if (type != VERT_LIST) {
487 /*
488 * When something else then a vertical list is requested set the list type
489 * to RAW_LIST e.g. non formated raw data as that makes the only sense for
490 * the logtext output. The logtext already has things like \n etc in it
491 * so we should just dump the raw content out for the best visible output.
492 */
493 type = RAW_LIST;
494 }
495 }
496
497 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
498
499 sendit->ArrayStart("joblog");
500 ListResult(jcr, sendit, type);
501 sendit->ArrayEnd("joblog");
502
503 SqlFreeResult();
504
505 bail_out:
506 DbUnlock(this);
507 }
508
509 /**
510 * list job statistics records for certain jobid
511 *
512 */
ListJobstatisticsRecords(JobControlRecord * jcr,uint32_t JobId,OutputFormatter * sendit,e_list_type type)513 void BareosDb::ListJobstatisticsRecords(JobControlRecord* jcr,
514 uint32_t JobId,
515 OutputFormatter* sendit,
516 e_list_type type)
517 {
518 char ed1[50];
519
520 if (JobId <= 0) { return; }
521 DbLock(this);
522 Mmsg(cmd,
523 "SELECT DeviceId, SampleTime, JobId, JobFiles, JobBytes "
524 "FROM JobStats "
525 "WHERE JobStats.JobId=%s "
526 "ORDER BY JobStats.SampleTime ",
527 edit_int64(JobId, ed1));
528 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
529
530 sendit->ArrayStart("jobstats");
531 ListResult(jcr, sendit, type);
532 sendit->ArrayEnd("jobstats");
533
534 SqlFreeResult();
535
536 bail_out:
537 DbUnlock(this);
538 }
539
540 /**
541 * List Job record(s) that match JobDbRecord
542 */
ListJobRecords(JobControlRecord * jcr,JobDbRecord * jr,const char * range,const char * clientname,int jobstatus,int joblevel,const char * volumename,const char * poolname,utime_t since_time,bool last,bool count,OutputFormatter * sendit,e_list_type type)543 void BareosDb::ListJobRecords(JobControlRecord* jcr,
544 JobDbRecord* jr,
545 const char* range,
546 const char* clientname,
547 int jobstatus,
548 int joblevel,
549 const char* volumename,
550 const char* poolname,
551 utime_t since_time,
552 bool last,
553 bool count,
554 OutputFormatter* sendit,
555 e_list_type type)
556 {
557 char ed1[50];
558 char dt[MAX_TIME_LENGTH];
559 char esc[MAX_ESCAPE_NAME_LENGTH];
560 PoolMem temp(PM_MESSAGE), selection(PM_MESSAGE), criteria(PM_MESSAGE);
561
562 if (jr->JobId > 0) {
563 temp.bsprintf("AND Job.JobId=%s", edit_int64(jr->JobId, ed1));
564 PmStrcat(selection, temp.c_str());
565 }
566
567 if (jr->Name[0] != 0) {
568 EscapeString(jcr, esc, jr->Name, strlen(jr->Name));
569 temp.bsprintf("AND Job.Name = '%s' ", esc);
570 PmStrcat(selection, temp.c_str());
571 }
572
573 if (clientname) {
574 temp.bsprintf("AND Client.Name = '%s' ", clientname);
575 PmStrcat(selection, temp.c_str());
576 }
577
578 if (jobstatus) {
579 temp.bsprintf("AND Job.JobStatus = '%c' ", jobstatus);
580 PmStrcat(selection, temp.c_str());
581 }
582
583 if (joblevel) {
584 temp.bsprintf("AND Job.Level = '%c' ", joblevel);
585 PmStrcat(selection, temp.c_str());
586 }
587
588 if (volumename) {
589 temp.bsprintf("AND Media.Volumename = '%s' ", volumename);
590 PmStrcat(selection, temp.c_str());
591 }
592
593 if (poolname) {
594 temp.bsprintf(
595 "AND Job.poolid = (SELECT poolid FROM pool WHERE name = '%s' LIMIT 1) ",
596 poolname);
597 PmStrcat(selection, temp.c_str());
598 }
599
600 if (since_time) {
601 bstrutime(dt, sizeof(dt), since_time);
602 temp.bsprintf("AND Job.SchedTime > '%s' ", dt);
603 PmStrcat(selection, temp.c_str());
604 }
605
606 DbLock(this);
607
608 if (count) {
609 FillQuery(SQL_QUERY::list_jobs_count, selection.c_str(), range);
610 } else if (last) {
611 if (type == VERT_LIST) {
612 FillQuery(SQL_QUERY::list_jobs_long_last, selection.c_str(), range);
613 } else {
614 FillQuery(SQL_QUERY::list_jobs_last, selection.c_str(), range);
615 }
616 } else {
617 if (type == VERT_LIST) {
618 FillQuery(SQL_QUERY::list_jobs_long, selection.c_str(), range);
619 } else {
620 FillQuery(SQL_QUERY::list_jobs, selection.c_str(), range);
621 }
622 }
623
624 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
625
626 sendit->ArrayStart("jobs");
627 ListResult(jcr, sendit, type);
628 sendit->ArrayEnd("jobs");
629
630 SqlFreeResult();
631
632 bail_out:
633 DbUnlock(this);
634 }
635
636 /**
637 * List Job totals
638 */
ListJobTotals(JobControlRecord * jcr,JobDbRecord * jr,OutputFormatter * sendit)639 void BareosDb::ListJobTotals(JobControlRecord* jcr,
640 JobDbRecord* jr,
641 OutputFormatter* sendit)
642 {
643 DbLock(this);
644
645 /*
646 * List by Job
647 */
648 Mmsg(cmd,
649 "SELECT count(*) AS Jobs,sum(JobFiles) "
650 "AS Files,sum(JobBytes) AS Bytes,Name AS Job FROM Job GROUP BY Name");
651
652 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
653
654 sendit->ArrayStart("jobs");
655 ListResult(jcr, sendit, HORZ_LIST);
656 sendit->ArrayEnd("jobs");
657
658 SqlFreeResult();
659
660 /*
661 * Do Grand Total
662 */
663 Mmsg(cmd,
664 "SELECT COUNT(*) AS Jobs,sum(JobFiles) "
665 "AS Files,sum(JobBytes) As Bytes FROM Job");
666
667 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
668
669 sendit->ObjectStart("jobtotals");
670 ListResult(jcr, sendit, HORZ_LIST);
671 sendit->ObjectEnd("jobtotals");
672
673 SqlFreeResult();
674
675 bail_out:
676 DbUnlock(this);
677 }
678
ListFilesForJob(JobControlRecord * jcr,JobId_t jobid,OutputFormatter * sendit)679 void BareosDb::ListFilesForJob(JobControlRecord* jcr,
680 JobId_t jobid,
681 OutputFormatter* sendit)
682 {
683 char ed1[50];
684 ListContext lctx(jcr, this, sendit, NF_LIST);
685
686 DbLock(this);
687
688 /*
689 * Stupid MySQL is NON-STANDARD !
690 */
691 if (GetTypeIndex() == SQL_TYPE_MYSQL) {
692 Mmsg(cmd,
693 "SELECT CONCAT(Path.Path,Name) AS Filename "
694 "FROM (SELECT PathId, Name FROM File WHERE JobId=%s "
695 "UNION ALL "
696 "SELECT PathId, Name "
697 "FROM BaseFiles JOIN File "
698 "ON (BaseFiles.FileId = File.FileId) "
699 "WHERE BaseFiles.JobId = %s"
700 ") AS F, Path "
701 "WHERE Path.PathId=F.PathId",
702 edit_int64(jobid, ed1), ed1);
703 } else {
704 Mmsg(cmd,
705 "SELECT Path.Path||Name AS Filename "
706 "FROM (SELECT PathId, Name FROM File WHERE JobId=%s "
707 "UNION ALL "
708 "SELECT PathId, Name "
709 "FROM BaseFiles JOIN File "
710 "ON (BaseFiles.FileId = File.FileId) "
711 "WHERE BaseFiles.JobId = %s"
712 ") AS F, Path "
713 "WHERE Path.PathId=F.PathId",
714 edit_int64(jobid, ed1), ed1);
715 }
716
717 sendit->ArrayStart("filenames");
718 if (!BigSqlQuery(cmd, ::ListResult, &lctx)) { goto bail_out; }
719 sendit->ArrayEnd("filenames");
720
721 SqlFreeResult();
722
723 bail_out:
724 DbUnlock(this);
725 }
726
ListBaseFilesForJob(JobControlRecord * jcr,JobId_t jobid,OutputFormatter * sendit)727 void BareosDb::ListBaseFilesForJob(JobControlRecord* jcr,
728 JobId_t jobid,
729 OutputFormatter* sendit)
730 {
731 char ed1[50];
732 ListContext lctx(jcr, this, sendit, NF_LIST);
733
734 DbLock(this);
735
736 /*
737 * Stupid MySQL is NON-STANDARD !
738 */
739 if (GetTypeIndex() == SQL_TYPE_MYSQL) {
740 Mmsg(cmd,
741 "SELECT CONCAT(Path.Path,File.Name) AS Filename "
742 "FROM BaseFiles, File, Path "
743 "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
744 "AND BaseFiles.FileId = File.FileId "
745 "AND Path.PathId=File.PathId",
746 edit_int64(jobid, ed1));
747 } else {
748 Mmsg(cmd,
749 "SELECT Path.Path||File.Name AS Filename "
750 "FROM BaseFiles, File, Path "
751 "WHERE BaseFiles.JobId=%s AND BaseFiles.BaseJobId = File.JobId "
752 "AND BaseFiles.FileId = File.FileId "
753 "AND Path.PathId=File.PathId",
754 edit_int64(jobid, ed1));
755 }
756
757 sendit->ArrayStart("files");
758 if (!BigSqlQuery(cmd, ::ListResult, &lctx)) { goto bail_out; }
759 sendit->ArrayEnd("files");
760
761 SqlFreeResult();
762
763 bail_out:
764 DbUnlock(this);
765 }
766
767 /**
768 * List fileset
769 */
ListFilesets(JobControlRecord * jcr,JobDbRecord * jr,const char * range,OutputFormatter * sendit,e_list_type type)770 void BareosDb::ListFilesets(JobControlRecord* jcr,
771 JobDbRecord* jr,
772 const char* range,
773 OutputFormatter* sendit,
774 e_list_type type)
775 {
776 char esc[MAX_ESCAPE_NAME_LENGTH];
777
778 DbLock(this);
779 if (jr->Name[0] != 0) {
780 EscapeString(jcr, esc, jr->Name, strlen(jr->Name));
781 Mmsg(cmd,
782 "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
783 "CreateTime, FileSetText "
784 "FROM Job, FileSet "
785 "WHERE Job.FileSetId = FileSet.FileSetId "
786 "AND Job.Name='%s'%s",
787 esc, range);
788 } else if (jr->Job[0] != 0) {
789 EscapeString(jcr, esc, jr->Job, strlen(jr->Job));
790 Mmsg(cmd,
791 "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
792 "CreateTime, FileSetText "
793 "FROM Job, FileSet "
794 "WHERE Job.FileSetId = FileSet.FileSetId "
795 "AND Job.Name='%s'%s",
796 esc, range);
797 } else if (jr->JobId != 0) {
798 Mmsg(cmd,
799 "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
800 "CreateTime, FileSetText "
801 "FROM Job, FileSet "
802 "WHERE Job.FileSetId = FileSet.FileSetId "
803 "AND Job.JobId='%s'%s",
804 edit_int64(jr->JobId, esc), range);
805 } else if (jr->FileSetId != 0) {
806 Mmsg(cmd,
807 "SELECT FileSetId, FileSet, MD5, CreateTime, FileSetText "
808 "FROM FileSet "
809 "WHERE FileSetId=%s",
810 edit_int64(jr->FileSetId, esc));
811 } else { /* all records */
812 Mmsg(cmd,
813 "SELECT DISTINCT FileSet.FileSetId AS FileSetId, FileSet, MD5, "
814 "CreateTime, FileSetText "
815 "FROM FileSet ORDER BY FileSetId ASC%s",
816 range);
817 }
818
819 if (!QUERY_DB(jcr, cmd)) { goto bail_out; }
820 sendit->ArrayStart("filesets");
821 ListResult(jcr, sendit, type);
822 sendit->ArrayEnd("filesets");
823
824 SqlFreeResult();
825
826 bail_out:
827 DbUnlock(this);
828 }
829 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || \
830 HAVE_DBI */
831