2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 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
27 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL
30 /* -----------------------------------------------------------------------
32 * Generic Routines (or almost generic)
34 * -----------------------------------------------------------------------
38 * Delete Pool record, must also delete all associated
43 * PoolId = number of Pools deleted (should be 1)
44 * NumVols = number of Media records deleted
46 int BDB::bdb_delete_pool_record(JCR *jcr, POOL_DBR *pr)
49 char esc[MAX_ESCAPE_NAME_LENGTH];
52 bdb_escape_string(jcr, esc, pr->Name, strlen(pr->Name));
53 Mmsg(cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", esc);
54 Dmsg1(10, "selectpool: %s\n", cmd);
56 pr->PoolId = pr->NumVols = 0;
58 if (QueryDB(jcr, cmd)) {
59 int nrows = sql_num_rows();
61 Mmsg(errmsg, _("No pool record %s exists\n"), pr->Name);
65 } else if (nrows != 1) {
66 Mmsg(errmsg, _("Expecting one pool record, got %d\n"), nrows);
71 if ((row = sql_fetch_row()) == NULL) {
72 Mmsg1(&errmsg, _("Error fetching row %s\n"), sql_strerror());
76 pr->PoolId = str_to_int64(row[0]);
80 /* Delete Media owned by this pool */
82 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
84 pr->NumVols = DeleteDB(jcr, cmd);
85 Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
89 "DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
90 pr->PoolId = DeleteDB(jcr, cmd);
91 Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
97 #define MAX_DEL_LIST_LEN 1000000
101 int num_ids; /* ids stored */
102 int max_ids; /* size of array */
103 int num_del; /* number deleted */
104 int tot_ids; /* total to process */
108 * Called here to make in memory list of JobIds to be
109 * deleted. The in memory list will then be transversed
110 * to issue the SQL DELETE commands. Note, the list
111 * is allowed to get to MAX_DEL_LIST_LEN to limit the
112 * maximum malloc'ed memory.
114 static int delete_handler(void *ctx, int num_fields, char **row)
116 struct s_del_ctx *del = (struct s_del_ctx *)ctx;
118 if (del->num_ids == MAX_DEL_LIST_LEN) {
121 if (del->num_ids == del->max_ids) {
122 del->max_ids = (del->max_ids * 3) / 2;
123 del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
126 del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
132 * This routine will purge (delete) all records
133 * associated with a particular Volume. It will
134 * not delete the media record itself.
135 * TODO: This function is broken and it doesn't purge
136 * File, BaseFiles, Log, ...
137 * We call it from relabel and delete volume=, both ensure
138 * that the volume is properly purged.
140 static int do_media_purge(BDB *mdb, MEDIA_DBR *mr)
142 POOLMEM *query = get_pool_memory(PM_MESSAGE);
143 struct s_del_ctx del;
151 Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%lu", mr->MediaId);
152 del.max_ids = mr->VolJobs;
153 if (del.max_ids < 100) {
155 } else if (del.max_ids > MAX_DEL_LIST_LEN) {
156 del.max_ids = MAX_DEL_LIST_LEN;
158 del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
159 mdb->bdb_sql_query(mdb->cmd, delete_handler, (void *)&del);
161 for (i=0; i < del.num_ids; i++) {
162 Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
163 Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
164 mdb->bdb_sql_query(query, NULL, (void *)NULL);
165 Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
166 mdb->bdb_sql_query(query, NULL, (void *)NULL);
167 Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
168 mdb->bdb_sql_query(query, NULL, (void *)NULL);
171 free_pool_memory(query);
175 /* Delete Media record and all records that
176 * are associated with it.
178 int BDB::bdb_delete_media_record(JCR *jcr, MEDIA_DBR *mr)
181 if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
185 /* Do purge if not already purged */
186 if (strcmp(mr->VolStatus, "Purged") != 0) {
187 /* Delete associated records */
188 do_media_purge(this, mr);
191 Mmsg(cmd, "DELETE FROM Media WHERE MediaId=%lu", mr->MediaId);
192 bdb_sql_query(cmd, NULL, (void *)NULL);
198 * Purge all records associated with a
199 * media record. This does not delete the
200 * media record itself. But the media status
201 * is changed to "Purged".
203 int BDB::bdb_purge_media_record(JCR *jcr, MEDIA_DBR *mr)
206 if (mr->MediaId == 0 && !bdb_get_media_record(jcr, mr)) {
210 /* Delete associated records */
211 do_media_purge(this, mr); /* Note, always purge */
213 /* Mark Volume as purged */
214 strcpy(mr->VolStatus, "Purged");
215 if (!bdb_update_media_record(jcr, mr)) {
224 /* Delete Snapshot record */
225 int BDB::bdb_delete_snapshot_record(JCR *jcr, SNAPSHOT_DBR *sr)
228 if (sr->SnapshotId == 0 && !bdb_get_snapshot_record(jcr, sr)) {
233 Mmsg(cmd, "DELETE FROM Snapshot WHERE SnapshotId=%d", sr->SnapshotId);
234 bdb_sql_query(cmd, NULL, (void *)NULL);
239 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL */