]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_delete.c
Change copyright as per agreement with FSFE
[bacula/bacula] / bacula / src / cats / sql_delete.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  * Bacula Catalog Database Delete record interface routines
21  *
22  *    Written by Kern Sibbald, December 2000-2014
23  *
24  */
25
26 #include  "bacula.h"
27
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
29 #include  "cats.h"
30  
31 /* -----------------------------------------------------------------------
32  *
33  *   Generic Routines (or almost generic)
34  *
35  * -----------------------------------------------------------------------
36  */
37
38 /*
39  * Delete Pool record, must also delete all associated
40  *  Media records.
41  *
42  *  Returns: 0 on error
43  *           1 on success
44  *           PoolId = number of Pools deleted (should be 1)
45  *           NumVols = number of Media records deleted
46  */
47 int BDB::bdb_delete_pool_record(JCR *jcr, POOL_DBR *pr)
48 {
49    SQL_ROW row;
50    char esc[MAX_ESCAPE_NAME_LENGTH];
51
52    bdb_lock();
53    bdb_escape_string(jcr, esc, pr->Name, strlen(pr->Name));
54    Mmsg(cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", esc);
55    Dmsg1(10, "selectpool: %s\n", cmd);
56
57    pr->PoolId = pr->NumVols = 0;
58
59    if (QueryDB(jcr, cmd)) {
60       int nrows = sql_num_rows();
61       if (nrows == 0) {
62          Mmsg(errmsg, _("No pool record %s exists\n"), pr->Name);
63          sql_free_result();
64          bdb_unlock();
65          return 0;
66       } else if (nrows != 1) {
67          Mmsg(errmsg, _("Expecting one pool record, got %d\n"), nrows);
68          sql_free_result();
69          bdb_unlock();
70          return 0;
71       }
72       if ((row = sql_fetch_row()) == NULL) {
73          Mmsg1(&errmsg, _("Error fetching row %s\n"), sql_strerror());
74          bdb_unlock();
75          return 0;
76       }
77       pr->PoolId = str_to_int64(row[0]);
78       sql_free_result();
79    }
80
81    /* Delete Media owned by this pool */
82    Mmsg(cmd,
83 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
84
85    pr->NumVols = DeleteDB(jcr, cmd);
86    Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
87
88    /* Delete Pool */
89    Mmsg(cmd,
90 "DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
91    pr->PoolId = DeleteDB(jcr, cmd);
92    Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
93
94    bdb_unlock();
95    return 1;
96 }
97
98 #define MAX_DEL_LIST_LEN 1000000
99
100 struct s_del_ctx {
101    JobId_t *JobId;
102    int num_ids;                       /* ids stored */
103    int max_ids;                       /* size of array */
104    int num_del;                       /* number deleted */
105    int tot_ids;                       /* total to process */
106 };
107
108 /*
109  * Called here to make in memory list of JobIds to be
110  *  deleted. The in memory list will then be transversed
111  *  to issue the SQL DELETE commands.  Note, the list
112  *  is allowed to get to MAX_DEL_LIST_LEN to limit the
113  *  maximum malloc'ed memory.
114  */
115 static int delete_handler(void *ctx, int num_fields, char **row)
116 {
117    struct s_del_ctx *del = (struct s_del_ctx *)ctx;
118
119    if (del->num_ids == MAX_DEL_LIST_LEN) {
120       return 1;
121    }
122    if (del->num_ids == del->max_ids) {
123       del->max_ids = (del->max_ids * 3) / 2;
124       del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
125          del->max_ids);
126    }
127    del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
128    return 0;
129 }
130
131
132 /*
133  * This routine will purge (delete) all records
134  * associated with a particular Volume. It will
135  * not delete the media record itself.
136  * TODO: This function is broken and it doesn't purge
137  *       File, BaseFiles, Log, ...
138  *       We call it from relabel and delete volume=, both ensure
139  *       that the volume is properly purged.
140  */
141 static int do_media_purge(BDB *mdb, MEDIA_DBR *mr)
142 {
143    POOLMEM *query = get_pool_memory(PM_MESSAGE);
144    struct s_del_ctx del;
145    char ed1[50];
146    int i;
147
148    del.num_ids = 0;
149    del.tot_ids = 0;
150    del.num_del = 0;
151    del.max_ids = 0;
152    Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
153    del.max_ids = mr->VolJobs;
154    if (del.max_ids < 100) {
155       del.max_ids = 100;
156    } else if (del.max_ids > MAX_DEL_LIST_LEN) {
157       del.max_ids = MAX_DEL_LIST_LEN;
158    }
159    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
160    mdb->bdb_sql_query(mdb->cmd, delete_handler, (void *)&del);
161
162    for (i=0; i < del.num_ids; i++) {
163       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
164       Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
165       mdb->bdb_sql_query(query, NULL, (void *)NULL);
166       Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
167       mdb->bdb_sql_query(query, NULL, (void *)NULL);
168       Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
169       mdb->bdb_sql_query(query, NULL, (void *)NULL);
170    }
171    free(del.JobId);
172    free_pool_memory(query);
173    return 1;
174 }
175
176 /* Delete Media record and all records that
177  * are associated with it.
178  */
179 int BDB::bdb_delete_media_record(JCR *jcr, MEDIA_DBR *mr)
180 {
181    bdb_lock();
182    if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
183       bdb_unlock();
184       return 0;
185    }
186    /* Do purge if not already purged */
187    if (strcmp(mr->VolStatus, "Purged") != 0) {
188       /* Delete associated records */
189       do_media_purge(this, mr);
190    }
191
192    Mmsg(cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
193    bdb_sql_query(cmd, NULL, (void *)NULL);
194    bdb_unlock();
195    return 1;
196 }
197
198 /*
199  * Purge all records associated with a
200  * media record. This does not delete the
201  * media record itself. But the media status
202  * is changed to "Purged".
203  */
204 int BDB::bdb_purge_media_record(JCR *jcr, MEDIA_DBR *mr)
205 {
206    bdb_lock();
207    if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
208       bdb_unlock();
209       return 0;
210    }
211    /* Delete associated records */
212    do_media_purge(this, mr);           /* Note, always purge */
213
214    /* Mark Volume as purged */
215    strcpy(mr->VolStatus, "Purged");
216    if (!bdb_update_media_record(jcr, mr)) {
217       bdb_unlock();
218       return 0;
219    }
220
221    bdb_unlock();
222    return 1;
223 }
224
225 /* Delete Snapshot record */
226 int BDB::bdb_delete_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
227 {
228    bdb_lock();
229    if (sr->SnapshotId == 0 && !bdb_get_snapshot_record(jcr, sr)) {
230       bdb_unlock();
231       return 0;
232    }
233
234    Mmsg(cmd, "DELETE FROM Snapshot WHERE SnapshotId=%d", sr->SnapshotId);
235    bdb_sql_query(cmd, NULL, (void *)NULL);
236    bdb_unlock();
237    return 1;
238 }
239
240 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */