]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sql.c
2948c77d731bdd99a3e8bd7a41ca071fe4f25e80
[bacula/bacula] / bacula / src / cats / sql.c
1 /*
2  * Bacula Catalog Database interface routines
3  * 
4  *     Almost generic set of SQL database interface routines
5  *      (with a little more work)
6  *
7  *    Kern Sibbald, March 2000
8  *
9  *    Version $Id$
10  */
11
12 /*
13    Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
14
15    This program is free software; you can redistribute it and/or
16    modify it under the terms of the GNU General Public License as
17    published by the Free Software Foundation; either version 2 of
18    the License, or (at your option) any later version.
19
20    This program is distributed in the hope that it will be useful,
21    but 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 General Public
26    License along with this program; if not, write to the Free
27    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28    MA 02111-1307, USA.
29
30  */
31
32 /* The following is necessary so that we do not include
33  * the dummy external definition of B_DB.
34  */
35 #define __SQL_C                       /* indicate that this is sql.c */
36
37 #include "bacula.h"
38 #include "cats.h"
39
40 #if    HAVE_MYSQL | HAVE_SQLITE
41
42 /* Forward referenced subroutines */
43 void print_dashes(B_DB *mdb);
44 void print_result(B_DB *mdb);
45
46 /*
47  * Called here to retrieve an integer from the database
48  */
49 static int int_handler(void *ctx, int num_fields, char **row)
50 {
51    uint32_t *val = (uint32_t *)ctx;
52
53    if (row[0]) {
54       *val = atoi(row[0]);
55    } else {
56       *val = 0;
57    }
58    return 0;
59 }
60        
61
62
63 /* NOTE!!! The following routines expect that the
64  *  calling subroutine sets and clears the mutex
65  */
66
67 /* Check that the tables conrrespond to the version we want */
68 int check_tables_version(B_DB *mdb)
69 {
70    uint32_t version;
71    char *query = "SELECT VersionId FROM Version";
72   
73    version = 0;
74    db_sql_query(mdb, query, int_handler, (void *)&version);
75    if (version != BDB_VERSION) {
76       Mmsg(&mdb->errmsg, "Database version mismatch. Wanted %d, got %d\n",
77          BDB_VERSION, version);
78       Jmsg(mdb->jcr, M_FATAL, 0, mdb->errmsg);
79       return 0;
80    }
81    return 1;
82 }
83
84 /* Utility routine for queries */
85 int
86 QueryDB(char *file, int line, B_DB *mdb, char *cmd)
87 {
88    if (sql_query(mdb, cmd)) {
89       m_msg(file, line, &mdb->errmsg, _("query %s failed:\n%s\n"), cmd, sql_strerror(mdb));
90       j_msg(file, line, mdb->jcr, M_FATAL, 0, mdb->errmsg);
91       return 0;
92    }
93    mdb->result = sql_store_result(mdb);
94    
95    return mdb->result != NULL;
96 }
97
98 /* 
99  * Utility routine to do inserts   
100  * Returns: 0 on failure      
101  *          1 on success
102  */
103 int
104 InsertDB(char *file, int line, B_DB *mdb, char *cmd)
105 {
106    if (sql_query(mdb, cmd)) {
107       m_msg(file, line, &mdb->errmsg,  _("insert %s failed:\n%s\n"), cmd, sql_strerror(mdb));
108       j_msg(file, line, mdb->jcr, M_FATAL, 0, mdb->errmsg);
109       return 0;
110    }
111    if (mdb->have_insert_id) {
112       mdb->num_rows = sql_affected_rows(mdb);
113    } else {
114       mdb->num_rows = 1;
115    }
116    if (mdb->num_rows != 1) {
117       char ed1[30];
118       m_msg(file, line, &mdb->errmsg, _("Insertion problem: affect_rows=%s\n"), 
119          edit_uint64(mdb->num_rows, ed1));
120       j_msg(file, line, mdb->jcr, M_FATAL, 0, mdb->errmsg);  /* ***FIXME*** remove me */
121       return 0;
122    }
123    mdb->changes++;
124    return 1;
125 }
126
127 /* Utility routine for updates.
128  *  Returns: 0 on failure
129  *           1 on success  
130  */
131 int
132 UpdateDB(char *file, int line, B_DB *mdb, char *cmd)
133 {
134
135    if (sql_query(mdb, cmd)) {
136       m_msg(file, line, &mdb->errmsg, _("update %s failed:\n%s\n"), cmd, sql_strerror(mdb));
137       j_msg(file, line, mdb->jcr, M_ERROR, 0, mdb->errmsg);
138       j_msg(file, line, mdb->jcr, M_ERROR, 0, "%s\n", cmd);
139       return 0;
140    }
141    mdb->num_rows = sql_affected_rows(mdb);
142    if (mdb->num_rows != 1) {
143       char ed1[30];
144       m_msg(file, line, &mdb->errmsg, _("Update problem: affect_rows=%s\n"), 
145          edit_uint64(mdb->num_rows, ed1));
146       j_msg(file, line, mdb->jcr, M_ERROR, 0, mdb->errmsg);
147       j_msg(file, line, mdb->jcr, M_ERROR, 0, "%s\n", cmd);
148       return 0;
149    }
150    mdb->changes++;
151    return 1;
152 }
153
154 /* Utility routine for deletes   
155  *
156  * Returns: -1 on error
157  *           n number of rows affected
158  */
159 int
160 DeleteDB(char *file, int line, B_DB *mdb, char *cmd)
161 {
162
163    if (sql_query(mdb, cmd)) {
164       m_msg(file, line, &mdb->errmsg, _("delete %s failed:\n%s\n"), cmd, sql_strerror(mdb));
165       j_msg(file, line, mdb->jcr, M_ERROR, 0, mdb->errmsg);
166       return -1;
167    }
168    mdb->changes++;
169    return sql_affected_rows(mdb);
170 }
171
172
173 /*
174  * Get record max. Query is already in mdb->cmd
175  *  No locking done
176  *
177  * Returns: -1 on failure
178  *          count on success
179  */
180 int get_sql_record_max(B_DB *mdb)
181 {
182    SQL_ROW row;
183    int stat = 0;
184
185    if (QUERY_DB(mdb, mdb->cmd)) {
186       if ((row = sql_fetch_row(mdb)) == NULL) {
187          Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
188          stat = -1;
189       } else {
190          stat = atoi(row[0]);
191       }
192       sql_free_result(mdb);
193    } else {
194       Mmsg1(&mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
195       stat = -1;
196    }
197    return stat;
198 }
199
200 char *db_strerror(B_DB *mdb)
201 {
202    return mdb->errmsg;
203 }
204
205 void _db_lock(char *file, int line, B_DB *mdb)
206 {
207    int errstat;
208    if ((errstat=rwl_writelock(&mdb->lock)) != 0) {
209       j_msg(file, line, mdb->jcr, M_ABORT, 0, "rwl_writelock failure. ERR=%s\n",
210            strerror(errstat));
211    }
212 }    
213
214 void _db_unlock(char *file, int line, B_DB *mdb)
215 {
216    int errstat;
217    if ((errstat=rwl_writeunlock(&mdb->lock)) != 0) {
218       j_msg(file, line, mdb->jcr, M_ABORT, 0, "rwl_writeunlock failure. ERR=%s\n",
219            strerror(errstat));
220    }
221 }    
222
223 /*
224  * Start a transaction. This groups inserts and makes things
225  *  much more efficient. Usually started when inserting 
226  *  file attributes.
227  */
228 void db_start_transaction(B_DB *mdb)
229 {
230 #ifdef xAVE_SQLITE
231    db_lock(mdb);
232    /* Allow only 10,000 changes per transaction */
233    if (mdb->transaction && mdb->changes > 10000) {
234       db_end_transaction(mdb);
235    }
236    if (!mdb->transaction) {   
237       my_sqlite_query(mdb, "BEGIN");  /* begin transaction */
238       Dmsg0(400, "Start SQLite transaction\n");
239       mdb->transaction = 1;
240    }
241    db_unlock(mdb);
242 #endif
243
244 }
245
246 void db_end_transaction(B_DB *mdb)
247 {
248 #ifdef xAVE_SQLITE
249    db_lock(mdb);
250    if (mdb->transaction) {
251       my_sqlite_query(mdb, "COMMIT"); /* end transaction */
252       mdb->transaction = 0;
253       Dmsg1(400, "End SQLite transaction changes=%d\n", mdb->changes);
254    }
255    mdb->changes = 0;
256    db_unlock(mdb);
257 #endif
258 }
259
260
261 #endif /* HAVE_MYSQL | HAVE_SQLITE */