]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/cats/postgresql.c
Fix open of SQLite3 db where user does not have write permission
[bacula/bacula] / bacula / src / cats / postgresql.c
1 /*
2  * Bacula Catalog Database routines specific to PostgreSQL
3  *   These are PostgreSQL specific routines
4  *
5  *    Dan Langille, December 2003
6  *    based upon work done by Kern Sibbald, March 2000
7  *
8  *    Version $Id$
9  */
10 /*
11    Bacula® - The Network Backup Solution
12
13    Copyright (C) 2003-2006 Free Software Foundation Europe e.V.
14
15    The main author of Bacula is Kern Sibbald, with contributions from
16    many others, a complete list can be found in the file AUTHORS.
17    This program is Free Software; you can redistribute it and/or
18    modify it under the terms of version two of the GNU General Public
19    License as published by the Free Software Foundation plus additions
20    that are listed in the file LICENSE.
21
22    This program is distributed in the hope that it will be useful, but
23    WITHOUT ANY WARRANTY; without even the implied warranty of
24    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25    General Public License for more details.
26
27    You should have received a copy of the GNU General Public License
28    along with this program; if not, write to the Free Software
29    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30    02110-1301, USA.
31
32    Bacula® is a registered trademark of John Walker.
33    The licensor of Bacula is the Free Software Foundation Europe
34    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
35    Switzerland, email:ftf@fsfeurope.org.
36 */
37
38
39 /* The following is necessary so that we do not include
40  * the dummy external definition of DB.
41  */
42 #define __SQL_C                       /* indicate that this is sql.c */
43
44 #include "bacula.h"
45 #include "cats.h"
46
47 #ifdef HAVE_POSTGRESQL
48
49 #include "postgres_ext.h"       /* needed for NAMEDATALEN */
50
51 /* -----------------------------------------------------------------------
52  *
53  *   PostgreSQL dependent defines and subroutines
54  *
55  * -----------------------------------------------------------------------
56  */
57
58 /* List of open databases */
59 static BQUEUE db_list = {&db_list, &db_list};
60
61 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
62
63 /*
64  * Retrieve database type
65  */
66 const char *
67 db_get_type(void)
68 {
69    return "PostgreSQL";
70
71 }
72
73 /*
74  * Initialize database data structure. In principal this should
75  * never have errors, or it is really fatal.
76  */
77 B_DB *
78 db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char *db_password,
79                  const char *db_address, int db_port, const char *db_socket,
80                  int mult_db_connections)
81 {
82    B_DB *mdb;
83
84    if (!db_user) {
85       Jmsg(jcr, M_FATAL, 0, _("A user name for PostgreSQL must be supplied.\n"));
86       return NULL;
87    }
88    P(mutex);                          /* lock DB queue */
89    if (!mult_db_connections) {
90       /* Look to see if DB already open */
91       for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
92          if (bstrcmp(mdb->db_name, db_name) &&
93              bstrcmp(mdb->db_address, db_address) &&
94              mdb->db_port == db_port) {
95             Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
96             mdb->ref_count++;
97             V(mutex);
98             return mdb;                  /* already open */
99          }
100       }
101    }
102    Dmsg0(100, "db_open first time\n");
103    mdb = (B_DB *)malloc(sizeof(B_DB));
104    memset(mdb, 0, sizeof(B_DB));
105    mdb->db_name = bstrdup(db_name);
106    mdb->db_user = bstrdup(db_user);
107    if (db_password) {
108       mdb->db_password = bstrdup(db_password);
109    }
110    if (db_address) {
111       mdb->db_address  = bstrdup(db_address);
112    }
113    if (db_socket) {
114       mdb->db_socket   = bstrdup(db_socket);
115    }
116    mdb->db_port        = db_port;
117    mdb->have_insert_id = TRUE;
118    mdb->errmsg         = get_pool_memory(PM_EMSG); /* get error message buffer */
119    *mdb->errmsg        = 0;
120    mdb->cmd            = get_pool_memory(PM_EMSG); /* get command buffer */
121    mdb->cached_path    = get_pool_memory(PM_FNAME);
122    mdb->cached_path_id = 0;
123    mdb->ref_count      = 1;
124    mdb->fname          = get_pool_memory(PM_FNAME);
125    mdb->path           = get_pool_memory(PM_FNAME);
126    mdb->esc_name       = get_pool_memory(PM_FNAME);
127    mdb->allow_transactions = mult_db_connections;
128    qinsert(&db_list, &mdb->bq);            /* put db in list */
129    V(mutex);
130    return mdb;
131 }
132
133 /*
134  * Now actually open the database.  This can generate errors,
135  *   which are returned in the errmsg
136  *
137  * DO NOT close the database or free(mdb) here !!!!
138  */
139 int
140 db_open_database(JCR *jcr, B_DB *mdb)
141 {
142    int errstat;
143    char buf[10], *port;
144
145    P(mutex);
146    if (mdb->connected) {
147       V(mutex);
148       return 1;
149    }
150    mdb->connected = false;
151
152    if ((errstat=rwl_init(&mdb->lock)) != 0) {
153       Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
154             strerror(errstat));
155       V(mutex);
156       return 0;
157    }
158
159    if (mdb->db_port) {
160       bsnprintf(buf, sizeof(buf), "%d", mdb->db_port);
161       port = buf;
162    } else {
163       port = NULL;
164    }
165
166    /* If connection fails, try at 5 sec intervals for 30 seconds. */
167    for (int retry=0; retry < 6; retry++) {
168       /* connect to the database */
169       mdb->db = PQsetdbLogin(
170            mdb->db_address,           /* default = localhost */
171            port,                      /* default port */
172            NULL,                      /* pg options */
173            NULL,                      /* tty, ignored */
174            mdb->db_name,              /* database name */
175            mdb->db_user,              /* login name */
176            mdb->db_password);         /* password */
177
178       /* If no connect, try once more in case it is a timing problem */
179       if (PQstatus(mdb->db) == CONNECTION_OK) {
180          break;
181       }
182       bmicrosleep(5, 0);
183    }
184
185    Dmsg0(50, "pg_real_connect done\n");
186    Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n", mdb->db_user, mdb->db_name,
187             mdb->db_password==NULL?"(NULL)":mdb->db_password);
188
189    if (PQstatus(mdb->db) != CONNECTION_OK) {
190       Mmsg2(&mdb->errmsg, _("Unable to connect to PostgreSQL server.\n"
191             "Database=%s User=%s\n"
192             "It is probably not running or your password is incorrect.\n"),
193              mdb->db_name, mdb->db_user);
194       V(mutex);
195       return 0;
196    }
197
198    if (!check_tables_version(jcr, mdb)) {
199       V(mutex);
200       return 0;
201    }
202
203    sql_query(mdb, "SET datestyle TO 'ISO, YMD'");
204
205    mdb->connected = true;
206    V(mutex);
207    return 1;
208 }
209
210 void
211 db_close_database(JCR *jcr, B_DB *mdb)
212 {
213    if (!mdb) {
214       return;
215    }
216    db_end_transaction(jcr, mdb);
217    P(mutex);
218    mdb->ref_count--;
219    if (mdb->ref_count == 0) {
220       qdchain(&mdb->bq);
221       if (mdb->connected && mdb->db) {
222          sql_close(mdb);
223       }
224       rwl_destroy(&mdb->lock);
225       free_pool_memory(mdb->errmsg);
226       free_pool_memory(mdb->cmd);
227       free_pool_memory(mdb->cached_path);
228       free_pool_memory(mdb->fname);
229       free_pool_memory(mdb->path);
230       free_pool_memory(mdb->esc_name);
231       if (mdb->db_name) {
232          free(mdb->db_name);
233       }
234       if (mdb->db_user) {
235          free(mdb->db_user);
236       }
237       if (mdb->db_password) {
238          free(mdb->db_password);
239       }
240       if (mdb->db_address) {
241          free(mdb->db_address);
242       }
243       if (mdb->db_socket) {
244          free(mdb->db_socket);
245       }
246       my_postgresql_free_result(mdb);
247       free(mdb);
248    }
249    V(mutex);
250 }
251
252 /*
253  * Return the next unique index (auto-increment) for
254  * the given table.  Return NULL on error.
255  *
256  * For PostgreSQL, NULL causes the auto-increment value
257  *  to be updated.
258  */
259 int db_next_index(JCR *jcr, B_DB *mdb, char *table, char *index)
260 {
261    strcpy(index, "NULL");
262    return 1;
263 }
264
265
266 /*
267  * Escape strings so that PostgreSQL is happy
268  *
269  *   NOTE! len is the length of the old string. Your new
270  *         string must be long enough (max 2*old+1) to hold
271  *         the escaped output.
272  */
273 void
274 db_escape_string(char *snew, char *old, int len)
275 {
276    PQescapeString(snew, old, len);
277 }
278
279 /*
280  * Submit a general SQL command (cmd), and for each row returned,
281  *  the sqlite_handler is called with the ctx.
282  */
283 int db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
284 {
285    SQL_ROW row;
286
287    Dmsg0(500, "db_sql_query started\n");
288
289    db_lock(mdb);
290    if (sql_query(mdb, query) != 0) {
291       Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
292       db_unlock(mdb);
293       Dmsg0(500, "db_sql_query failed\n");
294       return 0;
295    }
296    Dmsg0(500, "db_sql_query succeeded. checking handler\n");
297
298    if (result_handler != NULL) {
299       Dmsg0(500, "db_sql_query invoking handler\n");
300       if ((mdb->result = sql_store_result(mdb)) != NULL) {
301          int num_fields = sql_num_fields(mdb);
302
303          Dmsg0(500, "db_sql_query sql_store_result suceeded\n");
304          while ((row = sql_fetch_row(mdb)) != NULL) {
305
306             Dmsg0(500, "db_sql_query sql_fetch_row worked\n");
307             if (result_handler(ctx, num_fields, row))
308                break;
309          }
310
311         sql_free_result(mdb);
312       }
313    }
314    db_unlock(mdb);
315
316    Dmsg0(500, "db_sql_query finished\n");
317
318    return 1;
319 }
320
321
322
323 POSTGRESQL_ROW my_postgresql_fetch_row(B_DB *mdb)
324 {
325    int j;
326    POSTGRESQL_ROW row = NULL; // by default, return NULL
327
328    Dmsg0(500, "my_postgresql_fetch_row start\n");
329
330    if (mdb->row_number == -1 || mdb->row == NULL) {
331       Dmsg1(500, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
332
333       if (mdb->row != NULL) {
334          Dmsg0(500, "my_postgresql_fetch_row freeing space\n");
335          free(mdb->row);
336          mdb->row = NULL;
337       }
338
339       mdb->row = (POSTGRESQL_ROW) malloc(sizeof(char *) * mdb->num_fields);
340
341       // now reset the row_number now that we have the space allocated
342       mdb->row_number = 0;
343    }
344
345    // if still within the result set
346    if (mdb->row_number < mdb->num_rows) {
347       Dmsg2(500, "my_postgresql_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
348       // get each value from this row
349       for (j = 0; j < mdb->num_fields; j++) {
350          mdb->row[j] = PQgetvalue(mdb->result, mdb->row_number, j);
351          Dmsg2(500, "my_postgresql_fetch_row field '%d' has value '%s'\n", j, mdb->row[j]);
352       }
353       // increment the row number for the next call
354       mdb->row_number++;
355
356       row = mdb->row;
357    } else {
358       Dmsg2(500, "my_postgresql_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
359    }
360
361    Dmsg1(500, "my_postgresql_fetch_row finishes returning %x\n", row);
362
363    return row;
364 }
365
366 int my_postgresql_max_length(B_DB *mdb, int field_num) {
367    //
368    // for a given column, find the max length
369    //
370    int max_length;
371    int i;
372    int this_length;
373
374    max_length = 0;
375    for (i = 0; i < mdb->num_rows; i++) {
376       if (PQgetisnull(mdb->result, i, field_num)) {
377           this_length = 4;        // "NULL"
378       } else {
379           this_length = cstrlen(PQgetvalue(mdb->result, i, field_num));
380       }
381
382       if (max_length < this_length) {
383           max_length = this_length;
384       }
385    }
386
387    return max_length;
388 }
389
390 POSTGRESQL_FIELD * my_postgresql_fetch_field(B_DB *mdb)
391 {
392    int     i;
393
394    Dmsg0(500, "my_postgresql_fetch_field starts\n");
395    if (mdb->fields == NULL) {
396       Dmsg1(500, "allocating space for %d fields\n", mdb->num_fields);
397       mdb->fields = (POSTGRESQL_FIELD *)malloc(sizeof(POSTGRESQL_FIELD) * mdb->num_fields);
398
399       for (i = 0; i < mdb->num_fields; i++) {
400          Dmsg1(500, "filling field %d\n", i);
401          mdb->fields[i].name           = PQfname(mdb->result, i);
402          mdb->fields[i].max_length = my_postgresql_max_length(mdb, i);
403          mdb->fields[i].type       = PQftype(mdb->result, i);
404          mdb->fields[i].flags      = 0;
405
406          Dmsg4(500, "my_postgresql_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
407             mdb->fields[i].name, mdb->fields[i].max_length, mdb->fields[i].type,
408             mdb->fields[i].flags);
409       } // end for
410    } // end if
411
412    // increment field number for the next time around
413
414    Dmsg0(500, "my_postgresql_fetch_field finishes\n");
415    return &mdb->fields[mdb->field_number++];
416 }
417
418 void my_postgresql_data_seek(B_DB *mdb, int row)
419 {
420    // set the row number to be returned on the next call
421    // to my_postgresql_fetch_row
422    mdb->row_number = row;
423 }
424
425 void my_postgresql_field_seek(B_DB *mdb, int field)
426 {
427    mdb->field_number = field;
428 }
429
430 /*
431  * Note, if this routine returns 1 (failure), Bacula expects
432  *  that no result has been stored.
433  */
434 int my_postgresql_query(B_DB *mdb, const char *query) {
435    Dmsg0(500, "my_postgresql_query started\n");
436    // We are starting a new query.  reset everything.
437    mdb->num_rows     = -1;
438    mdb->row_number   = -1;
439    mdb->field_number = -1;
440
441    if (mdb->result != NULL) {
442       PQclear(mdb->result);  /* hmm, someone forgot to free?? */
443    }
444
445    Dmsg1(500, "my_postgresql_query starts with '%s'\n", query);
446    mdb->result = PQexec(mdb->db, query);
447    mdb->status = PQresultStatus(mdb->result);
448    if (mdb->status == PGRES_TUPLES_OK || mdb->status == PGRES_COMMAND_OK) {
449       Dmsg1(500, "we have a result\n", query);
450
451       // how many fields in the set?
452       mdb->num_fields = (int) PQnfields(mdb->result);
453       Dmsg1(500, "we have %d fields\n", mdb->num_fields);
454
455       mdb->num_rows   = PQntuples(mdb->result);
456       Dmsg1(500, "we have %d rows\n", mdb->num_rows);
457
458       mdb->status = 0;
459    } else {
460       Dmsg1(500, "we failed\n", query);
461       mdb->status = 1;
462    }
463
464    Dmsg0(500, "my_postgresql_query finishing\n");
465
466    return mdb->status;
467 }
468
469 void my_postgresql_free_result (B_DB *mdb)
470 {
471    if (mdb->result) {
472       PQclear(mdb->result);
473       mdb->result = NULL;
474    }
475
476    if (mdb->row) {
477       free(mdb->row);
478       mdb->row = NULL;
479    }
480
481    if (mdb->fields) {
482       free(mdb->fields);
483       mdb->fields = NULL;
484    }
485 }
486
487 int my_postgresql_currval(B_DB *mdb, char *table_name)
488 {
489    // Obtain the current value of the sequence that
490    // provides the serial value for primary key of the table.
491
492    // currval is local to our session.  It is not affected by
493    // other transactions.
494
495    // Determine the name of the sequence.
496    // PostgreSQL automatically creates a sequence using
497    // <table>_<column>_seq.
498    // At the time of writing, all tables used this format for
499    // for their primary key: <table>id
500    // Except for basefiles which has a primary key on baseid.
501    // Therefore, we need to special case that one table.
502
503    // everything else can use the PostgreSQL formula.
504
505    char      sequence[NAMEDATALEN-1];
506    char      query   [NAMEDATALEN+50];
507    PGresult *result;
508    int       id = 0;
509
510    if (strcasecmp(table_name, "basefiles") == 0) {
511       bstrncpy(sequence, "basefiles_baseid", sizeof(sequence));
512    } else {
513       bstrncpy(sequence, table_name, sizeof(sequence));
514       bstrncat(sequence, "_",        sizeof(sequence));
515       bstrncat(sequence, table_name, sizeof(sequence));
516       bstrncat(sequence, "id",       sizeof(sequence));
517    }
518
519    bstrncat(sequence, "_seq", sizeof(sequence));
520    bsnprintf(query, sizeof(query), "SELECT currval('%s')", sequence);
521
522 // Mmsg(query, "SELECT currval('%s')", sequence);
523    Dmsg1(500, "my_postgresql_currval invoked with '%s'\n", query);
524    result = PQexec(mdb->db, query);
525
526    Dmsg0(500, "exec done");
527
528    if (PQresultStatus(result) == PGRES_TUPLES_OK) {
529       Dmsg0(500, "getting value");
530       id = atoi(PQgetvalue(result, 0, 0));
531       Dmsg2(500, "got value '%s' which became %d\n", PQgetvalue(result, 0, 0), id);
532    } else {
533       Mmsg1(&mdb->errmsg, _("error fetching currval: %s\n"), PQerrorMessage(mdb->db));
534    }
535
536    PQclear(result);
537
538    return id;
539 }
540
541
542 #endif /* HAVE_POSTGRESQL */