]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/sqlite.c
Implement Auto Prune and Auto Recycle
[bacula/bacula] / bacula / src / cats / sqlite.c
1 /*
2  * Bacula Catalog Database routines specific to SQLite
3  *
4  *    Kern Sibbald, January 2002
5  *
6  *    Version $Id$
7  */
8
9 /*
10    Copyright (C) 2002 Kern Sibbald and John Walker
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
30 /* The following is necessary so that we do not include
31  * the dummy external definition of DB.
32  */
33 #define __SQL_C                       /* indicate that this is sql.c */
34
35 #include "bacula.h"
36 #include "cats.h"
37
38 #ifdef HAVE_SQLITE
39
40 /* -----------------------------------------------------------------------
41  *
42  *    SQLite dependent defines and subroutines
43  *
44  * -----------------------------------------------------------------------
45  */
46
47 extern char *working_directory;
48
49 /* List of open databases */
50 static BQUEUE db_list = {&db_list, &db_list};
51
52 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
53
54 int QueryDB(char *file, int line, B_DB *db, char *select_cmd);
55
56
57 /*
58  * Initialize database data structure. In principal this should
59  * never have errors, or it is really fatal.
60  */
61 B_DB *
62 db_init_database(char *db_name, char *db_user, char *db_password)
63 {
64    B_DB *mdb;
65
66    P(mutex);                          /* lock DB queue */
67    /* Look to see if DB already open */
68    for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
69       if (strcmp(mdb->db_name, db_name) == 0) {
70          Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
71          mdb->ref_count++;
72          V(mutex);
73          return mdb;                  /* already open */
74       }
75    }
76    Dmsg0(100, "db_open first time\n");
77    mdb = (B_DB *) malloc(sizeof(B_DB));
78    memset(mdb, 0, sizeof(B_DB));
79    mdb->db_name = bstrdup(db_name);
80    mdb->have_insert_id = TRUE; 
81    mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */
82    *mdb->errmsg = 0;
83    mdb->cmd = get_pool_memory(PM_EMSG);    /* get command buffer */
84    mdb->ref_count = 1;
85    qinsert(&db_list, &mdb->bq);            /* put db in list */
86    V(mutex);
87    return mdb;
88 }
89
90 /*
91  * Now actually open the database.  This can generate errors,
92  * which are returned in the errmsg
93  */
94 int
95 db_open_database(B_DB *mdb)
96 {
97    char *db_name;
98    int len;
99    struct stat statbuf;
100
101    P(mutex);
102    if (mdb->connected) {
103       V(mutex);
104       return 1;
105    }
106    mdb->connected = FALSE;
107 #ifdef needed
108    if (pthread_mutex_init(&mdb->mutex, NULL) != 0) {
109       Mmsg1(&mdb->errmsg, _("Unable to initialize DB mutex. ERR=%s\n"), strerror(errno));
110       V(mutex);
111       return 0;
112    }
113 #endif
114
115    if (rwl_init(&mdb->lock) != 0) {
116       Mmsg1(&mdb->errmsg, "Unable to initialize DB lock. ERR=%s\n", strerror(errno));
117       V(mutex);
118       return 0;
119    }
120
121    /* open the database */
122    len = strlen(working_directory) + strlen(mdb->db_name) + 5; 
123    db_name = (char *)malloc(len);
124    strcpy(db_name, working_directory);
125    strcat(db_name, "/");
126    strcat(db_name, mdb->db_name);
127    strcat(db_name, ".db");
128    if (stat(db_name, &statbuf) != 0) {
129       Mmsg1(&mdb->errmsg, _("Database %s does not exist, please create it.\n"), 
130          db_name);
131       free(db_name);
132       V(mutex);
133       return 0;
134    }
135    mdb->db = sqlite_open(
136         db_name,                      /* database name */
137         644,                          /* mode */
138         &mdb->sqlite_errmsg);         /* error message */
139
140    Dmsg0(50, "sqlite_open\n");
141   
142    if (mdb->db == NULL) {
143       Mmsg2(&mdb->errmsg, _("Unable to open Database=%s. ERR=%s\n"),
144          db_name, mdb->sqlite_errmsg ? mdb->sqlite_errmsg : _("unknown"));
145       free(db_name);
146       V(mutex);
147       return 0;
148    }
149    free(db_name);
150    if (!check_tables_version(mdb)) {
151       V(mutex);
152       return 0;
153    }
154
155    mdb->connected = TRUE;
156    V(mutex);
157    return 1;
158 }
159
160 void
161 db_close_database(B_DB *mdb)
162 {
163    P(mutex);
164    mdb->ref_count--;
165    if (mdb->ref_count == 0) {
166       qdchain(&mdb->bq);
167       if (mdb->connected && mdb->db) {
168          sqlite_close(mdb->db);
169       }
170 /*    pthread_mutex_destroy(&mdb->mutex); */
171       rwl_destroy(&mdb->lock);       
172       free_pool_memory(mdb->errmsg);
173       free_pool_memory(mdb->cmd);
174       if (mdb->db_name) {
175          free(mdb->db_name);
176       }
177       free(mdb);
178    }
179    V(mutex);
180 }
181
182 /*
183  * Return the next unique index (auto-increment) for
184  * the given table.  Return NULL on error.
185  */
186 char *db_next_index(B_DB *mdb, char *table)
187 {
188    SQL_ROW row;
189    static char id[20];
190
191    QUERY_DB(mdb, "BEGIN TRANSACTION");
192    sql_free_result(mdb);
193
194    Mmsg(&mdb->cmd,
195 "SELECT id FROM NextId WHERE TableName=\"%s\"", table);
196    if (!QUERY_DB(mdb, mdb->cmd)) {
197       Mmsg(&mdb->errmsg, _("next_index query error: ERR=%s\n"), sql_strerror(mdb));
198       QUERY_DB(mdb, "ROLLBACK");
199       return NULL;
200    }
201    if ((row = sql_fetch_row(mdb)) == NULL) {
202       Mmsg(&mdb->errmsg, _("Error fetching index: ERR=%s\n"), sql_strerror(mdb));
203       QUERY_DB(mdb, "ROLLBACK");
204       return NULL;
205    }
206    strncpy(id, row[0], sizeof(id));
207    id[sizeof(id)-1] = 0;
208    sql_free_result(mdb);
209
210    Mmsg(&mdb->cmd,
211 "UPDATE NextId SET id=id+1 WHERE TableName=\"%s\"", table);
212    if (!QUERY_DB(mdb, mdb->cmd)) {
213       Mmsg(&mdb->errmsg, _("next_index update error: ERR=%s\n"), sql_strerror(mdb));
214       QUERY_DB(mdb, "ROLLBACK");
215       return NULL;
216    }
217    sql_free_result(mdb);
218
219    QUERY_DB(mdb, "COMMIT");
220    sql_free_result(mdb);
221    return id;
222 }   
223
224
225
226 void
227 db_escape_string(char *snew, char *old, int len)
228 {
229    char *n, *o;
230
231    n = snew;
232    o = old;
233    while (len--) {
234       switch (*o) {
235       case '\'':
236          *n++ = '\\';
237          *n++ = '\'';
238          o++;
239          break;
240       case '"':
241          *n++ = '\\';
242          *n++ = '"';
243          o++;
244          break;
245       case 0:
246          *n++ = '\\';
247          *n++ = 0;
248          o++;
249          break;
250       default:
251          *n++ = *o++;
252          break;
253       }
254    }
255    *n = 0;
256 }
257
258 struct rh_data {
259    DB_RESULT_HANDLER *result_handler;
260    void *ctx;
261 };
262
263 /*  
264  * Convert SQLite's callback into Bacula DB callback  
265  */
266 static int sqlite_result(void *arh_data, int num_fields, char **rows, char **col_names)
267 {
268    struct rh_data *rh_data = (struct rh_data *)arh_data;   
269
270    if (rh_data->result_handler) {
271       (*(rh_data->result_handler))(rh_data->ctx, num_fields, rows);
272    }
273    return 0;
274 }
275
276 /*
277  * Submit a general SQL command (cmd), and for each row returned,
278  *  the sqlite_handler is called with the ctx.
279  */
280 int db_sql_query(B_DB *mdb, char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
281 {
282    struct rh_data rh_data;
283    int stat;
284
285    db_lock(mdb);
286    if (mdb->sqlite_errmsg) {
287       actuallyfree(mdb->sqlite_errmsg);
288       mdb->sqlite_errmsg = NULL;
289    }
290    rh_data.result_handler = result_handler;
291    rh_data.ctx = ctx;
292    stat = sqlite_exec(mdb->db, query, sqlite_result, (void *)&rh_data, &mdb->sqlite_errmsg);
293    if (stat != 0) {
294       Mmsg(&mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
295       db_unlock(mdb);
296       return 0;
297    }
298    db_unlock(mdb);
299    return 1;
300 }
301
302 /*
303  * Submit a sqlite query and retrieve all the data
304  */
305 int my_sqlite_query(B_DB *mdb, char *cmd) 
306 {
307    int stat;
308
309    if (mdb->sqlite_errmsg) {
310       actuallyfree(mdb->sqlite_errmsg);
311       mdb->sqlite_errmsg = NULL;
312    }
313    stat = sqlite_get_table(mdb->db, cmd, &mdb->result, &mdb->nrow, &mdb->ncolumn,
314             &mdb->sqlite_errmsg);
315    mdb->row = 0;                      /* row fetched */
316    return stat;
317 }
318
319 /* Fetch one row at a time */
320 SQL_ROW my_sqlite_fetch_row(B_DB *mdb)
321 {
322    if (mdb->row >= mdb->nrow) {
323       return NULL;
324    }
325    mdb->row++;
326    return &mdb->result[mdb->ncolumn * mdb->row];
327 }
328
329 void my_sqlite_free_table(B_DB *mdb)
330 {
331    unsigned int i;
332
333    if (mdb->fields_defined) {
334       for (i=0; i < sql_num_fields(mdb); i++) {
335          free(mdb->fields[i]);
336       }
337       free(mdb->fields);
338       mdb->fields_defined = FALSE;
339    }
340    sqlite_free_table(mdb->result);
341    mdb->nrow = mdb->ncolumn = 0; 
342 }
343
344 void my_sqlite_field_seek(B_DB *mdb, int field)
345 {
346    unsigned int i, j;
347    if (mdb->result == NULL) {
348       return;
349    }
350    /* On first call, set up the fields */
351    if (!mdb->fields_defined && sql_num_fields(mdb) > 0) {
352       mdb->fields = (SQL_FIELD **)malloc(sizeof(SQL_FIELD) * mdb->ncolumn);
353       for (i=0; i < sql_num_fields(mdb); i++) {
354          mdb->fields[i] = (SQL_FIELD *)malloc(sizeof(SQL_FIELD));
355          mdb->fields[i]->name = mdb->result[i];
356          mdb->fields[i]->length = strlen(mdb->fields[i]->name);
357          mdb->fields[i]->max_length = mdb->fields[i]->length;
358          for (j=1; j <= (unsigned)mdb->nrow; j++) {
359             uint32_t len;
360             if (mdb->result[i + mdb->ncolumn *j]) {
361                len = (uint32_t)strlen(mdb->result[i + mdb->ncolumn * j]);
362             } else {
363                len = 0;
364             }
365             if (len > mdb->fields[i]->max_length) {
366                mdb->fields[i]->max_length = len;
367             }
368          }
369          mdb->fields[i]->type = 0;
370          mdb->fields[i]->flags = 1;        /* not null */
371       }
372       mdb->fields_defined = TRUE;
373    }
374    if (field > (int)sql_num_fields(mdb)) {
375       field = (int)sql_num_fields(mdb);
376     }
377     mdb->field = field;
378
379 }
380
381 SQL_FIELD *my_sqlite_fetch_field(B_DB *mdb)
382 {
383    return mdb->fields[mdb->field++];
384 }
385
386 static void
387 list_dashes(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
388 {
389    SQL_FIELD *field;
390    unsigned int i, j;
391
392    sql_field_seek(mdb, 0);
393    send(ctx, "+");
394    for (i = 0; i < sql_num_fields(mdb); i++) {
395       field = sql_fetch_field(mdb);
396       for (j = 0; j < field->max_length + 2; j++)
397               send(ctx, "-");
398       send(ctx, "+");
399    }
400    send(ctx, "\n");
401 }
402
403 void
404 list_result(B_DB *mdb, DB_LIST_HANDLER *send, void *ctx)
405 {
406    SQL_FIELD *field;
407    SQL_ROW row;
408    unsigned int i, col_len;
409    char buf[2000], ewc[30];
410
411    if (mdb->result == NULL || mdb->nrow == 0) {
412       return;
413    }
414    /* determine column display widths */
415    sql_field_seek(mdb, 0);
416    for (i = 0; i < sql_num_fields(mdb); i++) {
417       field = sql_fetch_field(mdb);
418       if (IS_NUM(field->type) && field->max_length > 0) { /* fixup for commas */
419          field->max_length += (field->max_length - 1) / 3;
420       }
421       col_len = strlen(field->name);
422       if (col_len < field->max_length)
423               col_len = field->max_length;
424       if (col_len < 4 && !IS_NOT_NULL(field->flags))
425               col_len = 4;    /* 4 = length of the word "NULL" */
426       field->max_length = col_len;    /* reset column info */
427    }
428
429    list_dashes(mdb, send, ctx);
430    send(ctx, "|");
431    sql_field_seek(mdb, 0);
432    for (i = 0; i < sql_num_fields(mdb); i++) {
433       field = sql_fetch_field(mdb);
434       sprintf(buf, " %-*s |", field->max_length, field->name);
435       send(ctx, buf);
436    }
437    send(ctx, "\n");
438    list_dashes(mdb, send, ctx);
439
440    while ((row = sql_fetch_row(mdb)) != NULL) {
441       sql_field_seek(mdb, 0);
442       send(ctx, "|");
443       for (i = 0; i < sql_num_fields(mdb); i++) {
444          field = sql_fetch_field(mdb);
445          if (row[i] == NULL) {
446             sprintf(buf, " %-*s |", field->max_length, "NULL");
447          } else if (IS_NUM(field->type)) {
448             sprintf(buf, " %*s |", field->max_length,       
449                add_commas(row[i], ewc));
450          } else {
451             sprintf(buf, " %-*s |", field->max_length, row[i]);
452          }
453          send(ctx, buf);
454       }
455       send(ctx, "\n");
456    }
457    list_dashes(mdb, send, ctx);
458 }
459
460
461 #endif /* HAVE_SQLITE */