2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
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.
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.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Bacula Catalog Database Delete record interface routines
22 * Written by Kern Sibbald, December 2000-2014
28 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
31 /* -----------------------------------------------------------------------
33 * Generic Routines (or almost generic)
35 * -----------------------------------------------------------------------
39 * Delete Pool record, must also delete all associated
44 * PoolId = number of Pools deleted (should be 1)
45 * NumVols = number of Media records deleted
47 int BDB::bdb_delete_pool_record(JCR *jcr, POOL_DBR *pr)
50 char esc[MAX_ESCAPE_NAME_LENGTH];
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);
57 pr->PoolId = pr->NumVols = 0;
59 if (QueryDB(jcr, cmd)) {
60 int nrows = sql_num_rows();
62 Mmsg(errmsg, _("No pool record %s exists\n"), pr->Name);
66 } else if (nrows != 1) {
67 Mmsg(errmsg, _("Expecting one pool record, got %d\n"), nrows);
72 if ((row = sql_fetch_row()) == NULL) {
73 Mmsg1(&errmsg, _("Error fetching row %s\n"), sql_strerror());
77 pr->PoolId = str_to_int64(row[0]);
81 /* Delete Media owned by this pool */
83 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
85 pr->NumVols = DeleteDB(jcr, cmd);
86 Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
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);
98 #define MAX_DEL_LIST_LEN 1000000
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 */
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.
115 static int delete_handler(void *ctx, int num_fields, char **row)
117 struct s_del_ctx *del = (struct s_del_ctx *)ctx;
119 if (del->num_ids == MAX_DEL_LIST_LEN) {
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) *
127 del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
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.
141 static int do_media_purge(BDB *mdb, MEDIA_DBR *mr)
143 POOLMEM *query = get_pool_memory(PM_MESSAGE);
144 struct s_del_ctx del;
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) {
156 } else if (del.max_ids > MAX_DEL_LIST_LEN) {
157 del.max_ids = MAX_DEL_LIST_LEN;
159 del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
160 mdb->bdb_sql_query(mdb->cmd, delete_handler, (void *)&del);
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);
172 free_pool_memory(query);
176 /* Delete Media record and all records that
177 * are associated with it.
179 int BDB::bdb_delete_media_record(JCR *jcr, MEDIA_DBR *mr)
182 if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
186 /* Do purge if not already purged */
187 if (strcmp(mr->VolStatus, "Purged") != 0) {
188 /* Delete associated records */
189 do_media_purge(this, mr);
192 Mmsg(cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
193 bdb_sql_query(cmd, NULL, (void *)NULL);
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".
204 int BDB::bdb_purge_media_record(JCR *jcr, MEDIA_DBR *mr)
207 if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
211 /* Delete associated records */
212 do_media_purge(this, mr); /* Note, always purge */
214 /* Mark Volume as purged */
215 strcpy(mr->VolStatus, "Purged");
216 if (!bdb_update_media_record(jcr, mr)) {
225 /* Delete Snapshot record */
226 int BDB::bdb_delete_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
229 if (sr->SnapshotId == 0 && !bdb_get_snapshot_record(jcr, sr)) {
234 Mmsg(cmd, "DELETE FROM Snapshot WHERE SnapshotId=%d", sr->SnapshotId);
235 bdb_sql_query(cmd, NULL, (void *)NULL);
240 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */