]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_delete.c
Backport of class based catalog backends into Branch-5.1.
[bacula/bacula] / bacula / src / cats / sql_delete.c
1 /*
2  * Bacula Catalog Database Delete record interface routines
3  *
4  *    Kern Sibbald, December 2000
5  *
6  *    Version $Id: sql_delete.c 7380 2008-07-14 10:42:59Z kerns $
7  */
8 /*
9    Bacula® - The Network Backup Solution
10
11    Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
12
13    The main author of Bacula is Kern Sibbald, with contributions from
14    many others, a complete list can be found in the file AUTHORS.
15    This program is Free Software; you can redistribute it and/or
16    modify it under the terms of version three of the GNU Affero General Public
17    License as published by the Free Software Foundation and included
18    in the file LICENSE.
19
20    This program is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23    General Public License for more details.
24
25    You should have received a copy of the GNU Affero General Public License
26    along with this program; if not, write to the Free Software
27    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28    02110-1301, USA.
29
30    Bacula® is a registered trademark of Kern Sibbald.
31    The licensor of Bacula is the Free Software Foundation Europe
32    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
33    Switzerland, email:ftf@fsfeurope.org.
34 */
35
36 /* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
37
38 #include "bacula.h"
39
40
41 #if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
42
43 #include "cats.h"
44 #include "bdb_priv.h"
45 #include "sql_glue.h"
46
47 /* -----------------------------------------------------------------------
48  *
49  *   Generic Routines (or almost generic)
50  *
51  * -----------------------------------------------------------------------
52  */
53
54 /*
55  * Delete Pool record, must also delete all associated
56  *  Media records.
57  *
58  *  Returns: 0 on error
59  *           1 on success
60  *           PoolId = number of Pools deleted (should be 1)
61  *           NumVols = number of Media records deleted
62  */
63 int
64 db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
65 {
66    SQL_ROW row;
67    int num_rows;
68
69    db_lock(mdb);
70    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", pr->Name);
71    Dmsg1(10, "selectpool: %s\n", mdb->cmd);
72
73    pr->PoolId = pr->NumVols = 0;
74
75    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
76
77       num_rows = sql_num_rows(mdb);
78       if (num_rows == 0) {
79          Mmsg(mdb->errmsg, _("No pool record %s exists\n"), pr->Name);
80          sql_free_result(mdb);
81          db_unlock(mdb);
82          return 0;
83       } else if (num_rows != 1) {
84          Mmsg(mdb->errmsg, _("Expecting one pool record, got %d\n"), num_rows);
85          sql_free_result(mdb);
86          db_unlock(mdb);
87          return 0;
88       }
89       if ((row = sql_fetch_row(mdb)) == NULL) {
90          Mmsg1(&mdb->errmsg, _("Error fetching row %s\n"), sql_strerror(mdb));
91          db_unlock(mdb);
92          return 0;
93       }
94       pr->PoolId = str_to_int64(row[0]);
95       sql_free_result(mdb);
96    }
97
98    /* Delete Media owned by this pool */
99    Mmsg(mdb->cmd,
100 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
101
102    pr->NumVols = DELETE_DB(jcr, mdb, mdb->cmd);
103    Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
104
105    /* Delete Pool */
106    Mmsg(mdb->cmd,
107 "DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
108    pr->PoolId = DELETE_DB(jcr, mdb, mdb->cmd);
109    Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
110
111    db_unlock(mdb);
112    return 1;
113 }
114
115 #define MAX_DEL_LIST_LEN 1000000
116
117 struct s_del_ctx {
118    JobId_t *JobId;
119    int num_ids;                       /* ids stored */
120    int max_ids;                       /* size of array */
121    int num_del;                       /* number deleted */
122    int tot_ids;                       /* total to process */
123 };
124
125 /*
126  * Called here to make in memory list of JobIds to be
127  *  deleted. The in memory list will then be transversed
128  *  to issue the SQL DELETE commands.  Note, the list
129  *  is allowed to get to MAX_DEL_LIST_LEN to limit the
130  *  maximum malloc'ed memory.
131  */
132 static int delete_handler(void *ctx, int num_fields, char **row)
133 {
134    struct s_del_ctx *del = (struct s_del_ctx *)ctx;
135
136    if (del->num_ids == MAX_DEL_LIST_LEN) {
137       return 1;
138    }
139    if (del->num_ids == del->max_ids) {
140       del->max_ids = (del->max_ids * 3) / 2;
141       del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
142          del->max_ids);
143    }
144    del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
145    return 0;
146 }
147
148
149 /*
150  * This routine will purge (delete) all records
151  * associated with a particular Volume. It will
152  * not delete the media record itself.
153  * TODO: This function is broken and it doesn't purge
154  *       File, BaseFiles, Log, ...
155  *       We call it from relabel and delete volume=, both ensure
156  *       that the volume is properly purged.
157  */
158 static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
159 {
160    POOLMEM *query = get_pool_memory(PM_MESSAGE);
161    struct s_del_ctx del;
162    char ed1[50];
163    int i;
164
165    del.num_ids = 0;
166    del.tot_ids = 0;
167    del.num_del = 0;
168    del.max_ids = 0;
169    Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
170    del.max_ids = mr->VolJobs;
171    if (del.max_ids < 100) {
172       del.max_ids = 100;
173    } else if (del.max_ids > MAX_DEL_LIST_LEN) {
174       del.max_ids = MAX_DEL_LIST_LEN;
175    }
176    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
177    db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
178
179    for (i=0; i < del.num_ids; i++) {
180       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
181       Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
182       db_sql_query(mdb, query, NULL, (void *)NULL);
183       Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
184       db_sql_query(mdb, query, NULL, (void *)NULL);
185       Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
186       db_sql_query(mdb, query, NULL, (void *)NULL);
187    }
188    free(del.JobId);
189    free_pool_memory(query);
190    return 1;
191 }
192
193 /* Delete Media record and all records that
194  * are associated with it.
195  */
196 int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
197 {
198    db_lock(mdb);
199    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
200       db_unlock(mdb);
201       return 0;
202    }
203    /* Do purge if not already purged */
204    if (strcmp(mr->VolStatus, "Purged") != 0) {
205       /* Delete associated records */
206       do_media_purge(mdb, mr);
207    }
208
209    Mmsg(mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
210    db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
211    db_unlock(mdb);
212    return 1;
213 }
214
215 /*
216  * Purge all records associated with a
217  * media record. This does not delete the
218  * media record itself. But the media status
219  * is changed to "Purged".
220  */
221 int db_purge_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
222 {
223    db_lock(mdb);
224    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
225       db_unlock(mdb);
226       return 0;
227    }
228    /* Delete associated records */
229    do_media_purge(mdb, mr);           /* Note, always purge */
230
231    /* Mark Volume as purged */
232    strcpy(mr->VolStatus, "Purged");
233    if (!db_update_media_record(jcr, mdb, mr)) {
234       db_unlock(mdb);
235       return 0;
236    }
237
238    db_unlock(mdb);
239    return 1;
240 }
241
242
243 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_POSTGRESQL || HAVE_INGRES */