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