]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_delete.c
Backport from BEE
[bacula/bacula] / bacula / src / cats / sql_delete.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    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    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  * Bacula Catalog Database Delete record interface routines
18  *
19  *    Written by Kern Sibbald, December 2000
20  *
21  */
22
23 #include "bacula.h"
24
25 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
26
27 #include "cats.h"
28 #include "bdb_priv.h"
29 #include "sql_glue.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
48 db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
49 {
50    SQL_ROW row;
51    int num_rows;
52    char esc[MAX_ESCAPE_NAME_LENGTH];
53
54    db_lock(mdb);
55    mdb->db_escape_string(jcr, esc, pr->Name, strlen(pr->Name));
56    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", esc);
57    Dmsg1(10, "selectpool: %s\n", mdb->cmd);
58
59    pr->PoolId = pr->NumVols = 0;
60
61    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
62
63       num_rows = sql_num_rows(mdb);
64       if (num_rows == 0) {
65          Mmsg(mdb->errmsg, _("No pool record %s exists\n"), pr->Name);
66          sql_free_result(mdb);
67          db_unlock(mdb);
68          return 0;
69       } else if (num_rows != 1) {
70          Mmsg(mdb->errmsg, _("Expecting one pool record, got %d\n"), num_rows);
71          sql_free_result(mdb);
72          db_unlock(mdb);
73          return 0;
74       }
75       if ((row = sql_fetch_row(mdb)) == NULL) {
76          Mmsg1(&mdb->errmsg, _("Error fetching row %s\n"), sql_strerror(mdb));
77          db_unlock(mdb);
78          return 0;
79       }
80       pr->PoolId = str_to_int64(row[0]);
81       sql_free_result(mdb);
82    }
83
84    /* Delete Media owned by this pool */
85    Mmsg(mdb->cmd,
86 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
87
88    pr->NumVols = DELETE_DB(jcr, mdb, mdb->cmd);
89    Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
90
91    /* Delete Pool */
92    Mmsg(mdb->cmd,
93 "DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
94    pr->PoolId = DELETE_DB(jcr, mdb, mdb->cmd);
95    Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
96
97    db_unlock(mdb);
98    return 1;
99 }
100
101 #define MAX_DEL_LIST_LEN 1000000
102
103 struct s_del_ctx {
104    JobId_t *JobId;
105    int num_ids;                       /* ids stored */
106    int max_ids;                       /* size of array */
107    int num_del;                       /* number deleted */
108    int tot_ids;                       /* total to process */
109 };
110
111 /*
112  * Called here to make in memory list of JobIds to be
113  *  deleted. The in memory list will then be transversed
114  *  to issue the SQL DELETE commands.  Note, the list
115  *  is allowed to get to MAX_DEL_LIST_LEN to limit the
116  *  maximum malloc'ed memory.
117  */
118 static int delete_handler(void *ctx, int num_fields, char **row)
119 {
120    struct s_del_ctx *del = (struct s_del_ctx *)ctx;
121
122    if (del->num_ids == MAX_DEL_LIST_LEN) {
123       return 1;
124    }
125    if (del->num_ids == del->max_ids) {
126       del->max_ids = (del->max_ids * 3) / 2;
127       del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
128          del->max_ids);
129    }
130    del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
131    return 0;
132 }
133
134
135 /*
136  * This routine will purge (delete) all records
137  * associated with a particular Volume. It will
138  * not delete the media record itself.
139  * TODO: This function is broken and it doesn't purge
140  *       File, BaseFiles, Log, ...
141  *       We call it from relabel and delete volume=, both ensure
142  *       that the volume is properly purged.
143  */
144 static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
145 {
146    POOLMEM *query = get_pool_memory(PM_MESSAGE);
147    struct s_del_ctx del;
148    char ed1[50];
149    int i;
150
151    del.num_ids = 0;
152    del.tot_ids = 0;
153    del.num_del = 0;
154    del.max_ids = 0;
155    Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
156    del.max_ids = mr->VolJobs;
157    if (del.max_ids < 100) {
158       del.max_ids = 100;
159    } else if (del.max_ids > MAX_DEL_LIST_LEN) {
160       del.max_ids = MAX_DEL_LIST_LEN;
161    }
162    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
163    db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
164
165    for (i=0; i < del.num_ids; i++) {
166       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
167       Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
168       db_sql_query(mdb, query, NULL, (void *)NULL);
169       Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
170       db_sql_query(mdb, query, NULL, (void *)NULL);
171       Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
172       db_sql_query(mdb, query, NULL, (void *)NULL);
173    }
174    free(del.JobId);
175    free_pool_memory(query);
176    return 1;
177 }
178
179 /* Delete Media record and all records that
180  * are associated with it.
181  */
182 int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
183 {
184    db_lock(mdb);
185    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
186       db_unlock(mdb);
187       return 0;
188    }
189    /* Do purge if not already purged */
190    if (strcmp(mr->VolStatus, "Purged") != 0) {
191       /* Delete associated records */
192       do_media_purge(mdb, mr);
193    }
194
195    Mmsg(mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
196    db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
197    db_unlock(mdb);
198    return 1;
199 }
200
201 /*
202  * Purge all records associated with a
203  * media record. This does not delete the
204  * media record itself. But the media status
205  * is changed to "Purged".
206  */
207 int db_purge_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
208 {
209    db_lock(mdb);
210    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
211       db_unlock(mdb);
212       return 0;
213    }
214    /* Delete associated records */
215    do_media_purge(mdb, mr);           /* Note, always purge */
216
217    /* Mark Volume as purged */
218    strcpy(mr->VolStatus, "Purged");
219    if (!db_update_media_record(jcr, mdb, mr)) {
220       db_unlock(mdb);
221       return 0;
222    }
223
224    db_unlock(mdb);
225    return 1;
226 }
227
228
229 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */