]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_delete.c
- Convert more atoi to str_to_int64() for DB.
[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$
7  */
8
9 /*
10    Copyright (C) 2000-2005 Kern Sibbald
11
12    This program is free software; you can redistribute it and/or
13    modify it under the terms of the GNU General Public License as
14    published by the Free Software Foundation; either version 2 of
15    the License, or (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20    General Public License for more details.
21
22    You should have received a copy of the GNU General Public
23    License along with this program; if not, write to the Free
24    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25    MA 02111-1307, USA.
26
27  */
28
29 /* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
30
31 /* The following is necessary so that we do not include
32  * the dummy external definition of DB.
33  */
34 #define __SQL_C                       /* indicate that this is sql.c */
35
36 #include "bacula.h"
37 #include "cats.h"
38
39
40 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
41 /* -----------------------------------------------------------------------
42  *
43  *   Generic Routines (or almost generic)
44  *
45  * -----------------------------------------------------------------------
46  */
47
48 /* Imported subroutines */
49 extern void print_dashes(B_DB *mdb);
50 extern void print_result(B_DB *mdb);
51 extern int QueryDB(const char *file, int line, JCR *jcr, B_DB *db, char *select_cmd);
52 extern int DeleteDB(const char *file, int line, JCR *jcr, B_DB *db, char *delete_cmd);
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
68    db_lock(mdb);
69    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", pr->Name);
70    Dmsg1(10, "selectpool: %s\n", mdb->cmd);
71
72    pr->PoolId = pr->NumVols = 0;
73
74    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
75
76       mdb->num_rows = sql_num_rows(mdb);
77
78       if (mdb->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 (mdb->num_rows != 1) {
84          Mmsg(mdb->errmsg, _("Expecting one pool record, got %d\n"), mdb->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  */
154 static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
155 {
156    POOLMEM *query = get_pool_memory(PM_MESSAGE);
157    struct s_del_ctx del;
158    char ed1[50];
159    int i;
160
161    del.num_ids = 0;
162    del.tot_ids = 0;
163    del.num_del = 0;
164    del.max_ids = 0;
165    Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
166    del.max_ids = mr->VolJobs;
167    if (del.max_ids < 100) {
168       del.max_ids = 100;
169    } else if (del.max_ids > MAX_DEL_LIST_LEN) {
170       del.max_ids = MAX_DEL_LIST_LEN;
171    }
172    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
173    db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
174
175    for (i=0; i < del.num_ids; i++) {
176       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
177       Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
178       db_sql_query(mdb, query, NULL, (void *)NULL);
179       Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
180       db_sql_query(mdb, query, NULL, (void *)NULL);
181       Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
182       db_sql_query(mdb, query, NULL, (void *)NULL);
183    }
184    free(del.JobId);
185    free_pool_memory(query);
186    return 1;
187 }
188
189 /* Delete Media record and all records that
190  * are associated with it.
191  */
192 int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
193 {
194    db_lock(mdb);
195    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
196       db_unlock(mdb);
197       return 0;
198    }
199    /* Do purge if not already purged */
200    if (strcmp(mr->VolStatus, "Purged") != 0) {
201       /* Delete associated records */
202       do_media_purge(mdb, mr);
203    }
204
205    Mmsg(mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
206    db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
207    db_unlock(mdb);
208    return 1;
209 }
210
211 /*
212  * Purge all records associated with a
213  * media record. This does not delete the
214  * media record itself. But the media status
215  * is changed to "Purged".
216  */
217 int db_purge_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
218 {
219    db_lock(mdb);
220    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
221       db_unlock(mdb);
222       return 0;
223    }
224    /* Delete associated records */
225    do_media_purge(mdb, mr);           /* Note, always purge */
226
227    /* Mark Volume as purged */
228    strcpy(mr->VolStatus, "Purged");
229    if (!db_update_media_record(jcr, mdb, mr)) {
230       db_unlock(mdb);
231       return 0;
232    }
233
234    db_unlock(mdb);
235    return 1;
236 }
237
238
239 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/