]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql_delete.c
Replace explicit checks for "/" with calls to IsPathSeparator, strchr with first_path...
[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-2006 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
14    version 2 as amended with additional clauses defined in the
15    file LICENSE in the main source directory.
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 
20    the file LICENSE for additional details.
21
22  */
23
24 /* *****FIXME**** fix fixed length of select_cmd[] and insert_cmd[] */
25
26 /* The following is necessary so that we do not include
27  * the dummy external definition of DB.
28  */
29 #define __SQL_C                       /* indicate that this is sql.c */
30
31 #include "bacula.h"
32 #include "cats.h"
33
34
35 #if    HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL
36 /* -----------------------------------------------------------------------
37  *
38  *   Generic Routines (or almost generic)
39  *
40  * -----------------------------------------------------------------------
41  */
42
43 /*
44  * Delete Pool record, must also delete all associated
45  *  Media records.
46  *
47  *  Returns: 0 on error
48  *           1 on success
49  *           PoolId = number of Pools deleted (should be 1)
50  *           NumVols = number of Media records deleted
51  */
52 int
53 db_delete_pool_record(JCR *jcr, B_DB *mdb, POOL_DBR *pr)
54 {
55    SQL_ROW row;
56
57    db_lock(mdb);
58    Mmsg(mdb->cmd, "SELECT PoolId FROM Pool WHERE Name='%s'", pr->Name);
59    Dmsg1(10, "selectpool: %s\n", mdb->cmd);
60
61    pr->PoolId = pr->NumVols = 0;
62
63    if (QUERY_DB(jcr, mdb, mdb->cmd)) {
64
65       mdb->num_rows = sql_num_rows(mdb);
66
67       if (mdb->num_rows == 0) {
68          Mmsg(mdb->errmsg, _("No pool record %s exists\n"), pr->Name);
69          sql_free_result(mdb);
70          db_unlock(mdb);
71          return 0;
72       } else if (mdb->num_rows != 1) {
73          Mmsg(mdb->errmsg, _("Expecting one pool record, got %d\n"), mdb->num_rows);
74          sql_free_result(mdb);
75          db_unlock(mdb);
76          return 0;
77       }
78       if ((row = sql_fetch_row(mdb)) == NULL) {
79          Mmsg1(&mdb->errmsg, _("Error fetching row %s\n"), sql_strerror(mdb));
80          db_unlock(mdb);
81          return 0;
82       }
83       pr->PoolId = str_to_int64(row[0]);
84       sql_free_result(mdb);
85    }
86
87    /* Delete Media owned by this pool */
88    Mmsg(mdb->cmd,
89 "DELETE FROM Media WHERE Media.PoolId = %d", pr->PoolId);
90
91    pr->NumVols = DELETE_DB(jcr, mdb, mdb->cmd);
92    Dmsg1(200, "Deleted %d Media records\n", pr->NumVols);
93
94    /* Delete Pool */
95    Mmsg(mdb->cmd,
96 "DELETE FROM Pool WHERE Pool.PoolId = %d", pr->PoolId);
97    pr->PoolId = DELETE_DB(jcr, mdb, mdb->cmd);
98    Dmsg1(200, "Deleted %d Pool records\n", pr->PoolId);
99
100    db_unlock(mdb);
101    return 1;
102 }
103
104 #define MAX_DEL_LIST_LEN 1000000
105
106 struct s_del_ctx {
107    JobId_t *JobId;
108    int num_ids;                       /* ids stored */
109    int max_ids;                       /* size of array */
110    int num_del;                       /* number deleted */
111    int tot_ids;                       /* total to process */
112 };
113
114 /*
115  * Called here to make in memory list of JobIds to be
116  *  deleted. The in memory list will then be transversed
117  *  to issue the SQL DELETE commands.  Note, the list
118  *  is allowed to get to MAX_DEL_LIST_LEN to limit the
119  *  maximum malloc'ed memory.
120  */
121 static int delete_handler(void *ctx, int num_fields, char **row)
122 {
123    struct s_del_ctx *del = (struct s_del_ctx *)ctx;
124
125    if (del->num_ids == MAX_DEL_LIST_LEN) {
126       return 1;
127    }
128    if (del->num_ids == del->max_ids) {
129       del->max_ids = (del->max_ids * 3) / 2;
130       del->JobId = (JobId_t *)brealloc(del->JobId, sizeof(JobId_t) *
131          del->max_ids);
132    }
133    del->JobId[del->num_ids++] = (JobId_t)str_to_int64(row[0]);
134    return 0;
135 }
136
137
138 /*
139  * This routine will purge (delete) all records
140  * associated with a particular Volume. It will
141  * not delete the media record itself.
142  */
143 static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr)
144 {
145    POOLMEM *query = get_pool_memory(PM_MESSAGE);
146    struct s_del_ctx del;
147    char ed1[50];
148    int i;
149
150    del.num_ids = 0;
151    del.tot_ids = 0;
152    del.num_del = 0;
153    del.max_ids = 0;
154    Mmsg(mdb->cmd, "SELECT JobId from JobMedia WHERE MediaId=%d", mr->MediaId);
155    del.max_ids = mr->VolJobs;
156    if (del.max_ids < 100) {
157       del.max_ids = 100;
158    } else if (del.max_ids > MAX_DEL_LIST_LEN) {
159       del.max_ids = MAX_DEL_LIST_LEN;
160    }
161    del.JobId = (JobId_t *)malloc(sizeof(JobId_t) * del.max_ids);
162    db_sql_query(mdb, mdb->cmd, delete_handler, (void *)&del);
163
164    for (i=0; i < del.num_ids; i++) {
165       Dmsg1(400, "Delete JobId=%d\n", del.JobId[i]);
166       Mmsg(query, "DELETE FROM Job WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
167       db_sql_query(mdb, query, NULL, (void *)NULL);
168       Mmsg(query, "DELETE FROM File WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
169       db_sql_query(mdb, query, NULL, (void *)NULL);
170       Mmsg(query, "DELETE FROM JobMedia WHERE JobId=%s", edit_int64(del.JobId[i], ed1));
171       db_sql_query(mdb, query, NULL, (void *)NULL);
172    }
173    free(del.JobId);
174    free_pool_memory(query);
175    return 1;
176 }
177
178 /* Delete Media record and all records that
179  * are associated with it.
180  */
181 int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
182 {
183    db_lock(mdb);
184    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
185       db_unlock(mdb);
186       return 0;
187    }
188    /* Do purge if not already purged */
189    if (strcmp(mr->VolStatus, "Purged") != 0) {
190       /* Delete associated records */
191       do_media_purge(mdb, mr);
192    }
193
194    Mmsg(mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId);
195    db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL);
196    db_unlock(mdb);
197    return 1;
198 }
199
200 /*
201  * Purge all records associated with a
202  * media record. This does not delete the
203  * media record itself. But the media status
204  * is changed to "Purged".
205  */
206 int db_purge_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr)
207 {
208    db_lock(mdb);
209    if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) {
210       db_unlock(mdb);
211       return 0;
212    }
213    /* Delete associated records */
214    do_media_purge(mdb, mr);           /* Note, always purge */
215
216    /* Mark Volume as purged */
217    strcpy(mr->VolStatus, "Purged");
218    if (!db_update_media_record(jcr, mdb, mr)) {
219       db_unlock(mdb);
220       return 0;
221    }
222
223    db_unlock(mdb);
224    return 1;
225 }
226
227
228 #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/