2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 Bacula® is a registered trademark of Kern Sibbald.
17 * Bacula Catalog Database routines specific to PostgreSQL
18 * These are PostgreSQL specific routines
20 * Dan Langille, December 2003
21 * based upon work done by Kern Sibbald, March 2000
23 * Class wrapper by Marco van Wieringen, January 2010
28 #ifdef HAVE_POSTGRESQL
33 #include "postgres_ext.h" /* needed for NAMEDATALEN */
34 #include "pg_config_manual.h" /* get NAMEDATALEN on version 8.3 or later */
35 #include "bdb_postgresql.h"
37 /* -----------------------------------------------------------------------
39 * PostgreSQL dependent defines and subroutines
41 * -----------------------------------------------------------------------
45 * List of open databases
47 static dlist *db_list = NULL;
49 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
51 B_DB_POSTGRESQL::B_DB_POSTGRESQL(JCR *jcr,
52 const char *db_driver,
55 const char *db_password,
56 const char *db_address,
58 const char *db_socket,
59 bool mult_db_connections,
60 bool disable_batch_insert)
63 * Initialize the parent class members.
65 m_db_interface_type = SQL_INTERFACE_TYPE_POSTGRESQL;
66 m_db_type = SQL_TYPE_POSTGRESQL;
67 m_db_driver = bstrdup("PostgreSQL");
68 m_db_name = bstrdup(db_name);
69 m_db_user = bstrdup(db_user);
71 m_db_password = bstrdup(db_password);
74 m_db_address = bstrdup(db_address);
77 m_db_socket = bstrdup(db_socket);
80 if (disable_batch_insert) {
81 m_disabled_batch_insert = true;
82 m_have_batch_insert = false;
84 m_disabled_batch_insert = false;
85 #if defined(USE_BATCH_FILE_INSERT)
86 #if defined(HAVE_POSTGRESQL_BATCH_FILE_INSERT) || defined(HAVE_PQISTHREADSAFE)
87 #ifdef HAVE_PQISTHREADSAFE
88 m_have_batch_insert = PQisthreadsafe();
90 m_have_batch_insert = true;
91 #endif /* HAVE_PQISTHREADSAFE */
93 m_have_batch_insert = true;
94 #endif /* HAVE_POSTGRESQL_BATCH_FILE_INSERT || HAVE_PQISTHREADSAFE */
96 m_have_batch_insert = false;
97 #endif /* USE_BATCH_FILE_INSERT */
99 errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */
101 cmd = get_pool_memory(PM_EMSG); /* get command buffer */
102 cached_path = get_pool_memory(PM_FNAME);
105 fname = get_pool_memory(PM_FNAME);
106 path = get_pool_memory(PM_FNAME);
107 esc_name = get_pool_memory(PM_FNAME);
108 esc_path = get_pool_memory(PM_FNAME);
109 esc_obj = get_pool_memory(PM_FNAME);
110 m_buf = get_pool_memory(PM_FNAME);
111 m_allow_transactions = mult_db_connections;
113 /* At this time, when mult_db_connections == true, this is for
114 * specific console command such as bvfs or batch mode, and we don't
115 * want to share a batch mode or bvfs. In the future, we can change
116 * the creation function to add this parameter.
118 m_dedicated = mult_db_connections;
121 * Initialize the private members.
127 * Put the db in the list.
129 if (db_list == NULL) {
130 db_list = New(dlist(this, &this->m_link));
132 db_list->append(this);
135 B_DB_POSTGRESQL::~B_DB_POSTGRESQL()
140 * Check that the database correspond to the encoding we want
142 static bool pgsql_check_database_encoding(JCR *jcr, B_DB_POSTGRESQL *mdb)
147 if (!mdb->sql_query("SELECT getdatabaseencoding()", QF_STORE_RESULT)) {
148 Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
152 if ((row = mdb->sql_fetch_row()) == NULL) {
153 Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), mdb->sql_strerror());
154 Jmsg(jcr, M_ERROR, 0, "Can't check database encoding %s", mdb->errmsg);
156 ret = bstrcmp(row[0], "SQL_ASCII");
160 * If we are in SQL_ASCII, we can force the client_encoding to SQL_ASCII too
162 mdb->sql_query("SET client_encoding TO 'SQL_ASCII'");
166 * Something is wrong with database encoding
169 _("Encoding error for database \"%s\". Wanted SQL_ASCII, got %s\n"),
170 mdb->get_db_name(), row[0]);
171 Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
172 Dmsg1(50, "%s", mdb->errmsg);
179 * Now actually open the database. This can generate errors,
180 * which are returned in the errmsg
182 * DO NOT close the database or delete mdb here !!!!
184 bool B_DB_POSTGRESQL::db_open_database(JCR *jcr)
196 if ((errstat=rwl_init(&m_lock)) != 0) {
198 Mmsg1(&errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
199 be.bstrerror(errstat));
204 bsnprintf(buf, sizeof(buf), "%d", m_db_port);
210 /* If connection fails, try at 5 sec intervals for 30 seconds. */
211 for (int retry=0; retry < 6; retry++) {
212 /* connect to the database */
213 m_db_handle = PQsetdbLogin(
214 m_db_address, /* default = localhost */
215 port, /* default port */
216 NULL, /* pg options */
217 NULL, /* tty, ignored */
218 m_db_name, /* database name */
219 m_db_user, /* login name */
220 m_db_password); /* password */
222 /* If no connect, try once more in case it is a timing problem */
223 if (PQstatus(m_db_handle) == CONNECTION_OK) {
229 Dmsg0(50, "pg_real_connect done\n");
230 Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n", m_db_user, m_db_name,
231 (m_db_password == NULL) ? "(NULL)" : m_db_password);
233 if (PQstatus(m_db_handle) != CONNECTION_OK) {
234 Mmsg2(&errmsg, _("Unable to connect to PostgreSQL server. Database=%s User=%s\n"
235 "Possible causes: SQL server not running; password incorrect; max_connections exceeded.\n"),
236 m_db_name, m_db_user);
241 if (!check_tables_version(jcr, this)) {
245 sql_query("SET datestyle TO 'ISO, YMD'");
246 sql_query("SET cursor_tuple_fraction=1");
249 * Tell PostgreSQL we are using standard conforming strings
250 * and avoid warnings such as:
251 * WARNING: nonstandard use of \\ in a string literal
253 sql_query("SET standard_conforming_strings=on");
256 * Check that encoding is SQL_ASCII
258 pgsql_check_database_encoding(jcr, this);
267 void B_DB_POSTGRESQL::db_close_database(JCR *jcr)
270 db_end_transaction(jcr);
274 if (m_ref_count == 0) {
278 db_list->remove(this);
279 if (m_connected && m_db_handle) {
280 PQfinish(m_db_handle);
282 if (rwl_is_init(&m_lock)) {
283 rwl_destroy(&m_lock);
285 free_pool_memory(errmsg);
286 free_pool_memory(cmd);
287 free_pool_memory(cached_path);
288 free_pool_memory(fname);
289 free_pool_memory(path);
290 free_pool_memory(esc_name);
291 free_pool_memory(esc_path);
292 free_pool_memory(esc_obj);
293 free_pool_memory(m_buf);
313 if (db_list->size() == 0) {
321 void B_DB_POSTGRESQL::db_thread_cleanup(void)
326 * Escape strings so that PostgreSQL is happy
328 * NOTE! len is the length of the old string. Your new
329 * string must be long enough (max 2*old+1) to hold
330 * the escaped output.
332 void B_DB_POSTGRESQL::db_escape_string(JCR *jcr, char *snew, char *old, int len)
336 PQescapeStringConn(m_db_handle, snew, old, len, &error);
338 Jmsg(jcr, M_FATAL, 0, _("PQescapeStringConn returned non-zero.\n"));
339 /* error on encoding, probably invalid multibyte encoding in the source string
340 see PQescapeStringConn documentation for details. */
341 Dmsg0(500, "PQescapeStringConn failed\n");
346 * Escape binary so that PostgreSQL is happy
349 char *B_DB_POSTGRESQL::db_escape_object(JCR *jcr, char *old, int len)
354 obj = PQescapeByteaConn(m_db_handle, (unsigned const char *)old, len, &new_len);
356 Jmsg(jcr, M_FATAL, 0, _("PQescapeByteaConn returned NULL.\n"));
359 esc_obj = check_pool_memory_size(esc_obj, new_len+1);
360 memcpy(esc_obj, obj, new_len);
365 return (char *)esc_obj;
369 * Unescape binary object so that PostgreSQL is happy
372 void B_DB_POSTGRESQL::db_unescape_object(JCR *jcr, char *from, int32_t expected_len,
373 POOLMEM **dest, int32_t *dest_len)
384 obj = PQunescapeBytea((unsigned const char *)from, &new_len);
387 Jmsg(jcr, M_FATAL, 0, _("PQunescapeByteaConn returned NULL.\n"));
391 *dest = check_pool_memory_size(*dest, new_len+1);
392 memcpy(*dest, obj, new_len);
397 Dmsg1(010, "obj size: %d\n", *dest_len);
401 * Start a transaction. This groups inserts and makes things
402 * much more efficient. Usually started when inserting
405 void B_DB_POSTGRESQL::db_start_transaction(JCR *jcr)
408 jcr->attr = get_pool_memory(PM_FNAME);
411 jcr->ar = (ATTR_DBR *)malloc(sizeof(ATTR_DBR));
415 * This is turned off because transactions break
416 * if multiple simultaneous jobs are run.
418 if (!m_allow_transactions) {
424 * Allow only 25,000 changes per transaction
426 if (m_transaction && changes > 25000) {
427 db_end_transaction(jcr);
429 if (!m_transaction) {
430 sql_query("BEGIN"); /* begin transaction */
431 Dmsg0(400, "Start PosgreSQL transaction\n");
432 m_transaction = true;
437 void B_DB_POSTGRESQL::db_end_transaction(JCR *jcr)
439 if (jcr && jcr->cached_attribute) {
440 Dmsg0(400, "Flush last cached attribute.\n");
441 if (!db_create_attributes_record(jcr, this, jcr->ar)) {
442 Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db));
444 jcr->cached_attribute = false;
447 if (!m_allow_transactions) {
453 sql_query("COMMIT"); /* end transaction */
454 m_transaction = false;
455 Dmsg1(400, "End PostgreSQL transaction changes=%d\n", changes);
463 * Submit a general SQL command (cmd), and for each row returned,
464 * the result_handler is called with the ctx.
466 bool B_DB_POSTGRESQL::db_big_sql_query(const char *query,
467 DB_RESULT_HANDLER *result_handler,
472 bool in_transaction = m_transaction;
474 Dmsg1(500, "db_sql_query starts with '%s'\n", query);
476 /* This code handles only SELECT queries */
477 if (strncasecmp(query, "SELECT", 6) != 0) {
478 return db_sql_query(query, result_handler, ctx);
481 if (!result_handler) { /* no need of big_query without handler */
487 if (!in_transaction) { /* CURSOR needs transaction */
491 Mmsg(m_buf, "DECLARE _bac_cursor CURSOR FOR %s", query);
493 if (!sql_query(m_buf)) {
494 Mmsg(errmsg, _("Query failed: %s: ERR=%s\n"), m_buf, sql_strerror());
495 Dmsg0(50, "db_sql_query failed\n");
500 if (!sql_query("FETCH 100 FROM _bac_cursor")) {
503 while ((row = sql_fetch_row()) != NULL) {
504 Dmsg1(500, "Fetching %d rows\n", m_num_rows);
505 if (result_handler(ctx, m_num_fields, row))
511 } while (m_num_rows > 0); /* TODO: Can probably test against 100 */
513 sql_query("CLOSE _bac_cursor");
515 Dmsg0(500, "db_big_sql_query finished\n");
520 if (!in_transaction) {
521 sql_query("COMMIT"); /* end transaction */
529 * Submit a general SQL command (cmd), and for each row returned,
530 * the result_handler is called with the ctx.
532 bool B_DB_POSTGRESQL::db_sql_query(const char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
537 Dmsg1(500, "db_sql_query starts with '%s'\n", query);
540 if (!sql_query(query, QF_STORE_RESULT)) {
541 Mmsg(errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror());
542 Dmsg0(500, "db_sql_query failed\n");
547 Dmsg0(500, "db_sql_query succeeded. checking handler\n");
549 if (result_handler != NULL) {
550 Dmsg0(500, "db_sql_query invoking handler\n");
551 while ((row = sql_fetch_row()) != NULL) {
552 Dmsg0(500, "db_sql_query sql_fetch_row worked\n");
553 if (result_handler(ctx, m_num_fields, row))
559 Dmsg0(500, "db_sql_query finished\n");
567 * Note, if this routine returns false (failure), Bacula expects
568 * that no result has been stored.
569 * This is where QUERY_DB comes with Postgresql.
571 * Returns: true on success
575 bool B_DB_POSTGRESQL::sql_query(const char *query, int flags)
580 Dmsg1(500, "sql_query starts with '%s'\n", query);
582 * We are starting a new query. reset everything.
589 PQclear(m_result); /* hmm, someone forgot to free?? */
593 for (i = 0; i < 10; i++) {
594 m_result = PQexec(m_db_handle, query);
601 Dmsg1(50, "Query failed: %s\n", query);
605 m_status = PQresultStatus(m_result);
606 if (m_status == PGRES_TUPLES_OK || m_status == PGRES_COMMAND_OK) {
607 Dmsg0(500, "we have a result\n");
610 * How many fields in the set?
612 m_num_fields = (int)PQnfields(m_result);
613 Dmsg1(500, "we have %d fields\n", m_num_fields);
615 m_num_rows = PQntuples(m_result);
616 Dmsg1(500, "we have %d rows\n", m_num_rows);
618 m_row_number = 0; /* we can start to fetch something */
619 m_status = 0; /* succeed */
622 Dmsg1(50, "Result status failed: %s\n", query);
626 Dmsg0(500, "sql_query finishing\n");
630 Dmsg0(500, "we failed\n");
633 m_status = 1; /* failed */
639 void B_DB_POSTGRESQL::sql_free_result(void)
654 m_num_rows = m_num_fields = 0;
658 SQL_ROW B_DB_POSTGRESQL::sql_fetch_row(void)
661 SQL_ROW row = NULL; /* by default, return NULL */
663 Dmsg0(500, "sql_fetch_row start\n");
665 if (m_num_fields == 0) { /* No field, no row */
666 Dmsg0(500, "sql_fetch_row finishes returning NULL, no fields\n");
670 if (!m_rows || m_rows_size < m_num_fields) {
672 Dmsg0(500, "sql_fetch_row freeing space\n");
675 Dmsg1(500, "we need space for %d bytes\n", sizeof(char *) * m_num_fields);
676 m_rows = (SQL_ROW)malloc(sizeof(char *) * m_num_fields);
677 m_rows_size = m_num_fields;
680 * Now reset the row_number now that we have the space allocated
686 * If still within the result set
688 if (m_row_number >= 0 && m_row_number < m_num_rows) {
689 Dmsg2(500, "sql_fetch_row row number '%d' is acceptable (0..%d)\n", m_row_number, m_num_rows);
691 * Get each value from this row
693 for (j = 0; j < m_num_fields; j++) {
694 m_rows[j] = PQgetvalue(m_result, m_row_number, j);
695 Dmsg2(500, "sql_fetch_row field '%d' has value '%s'\n", j, m_rows[j]);
698 * Increment the row number for the next call
703 Dmsg2(500, "sql_fetch_row row number '%d' is NOT acceptable (0..%d)\n", m_row_number, m_num_rows);
706 Dmsg1(500, "sql_fetch_row finishes returning %p\n", row);
711 const char *B_DB_POSTGRESQL::sql_strerror(void)
713 return PQerrorMessage(m_db_handle);
716 void B_DB_POSTGRESQL::sql_data_seek(int row)
719 * Set the row number to be returned on the next call to sql_fetch_row
724 int B_DB_POSTGRESQL::sql_affected_rows(void)
726 return (unsigned) str_to_int32(PQcmdTuples(m_result));
729 uint64_t B_DB_POSTGRESQL::sql_insert_autokey_record(const char *query, const char *table_name)
733 char sequence[NAMEDATALEN-1];
734 char getkeyval_query[NAMEDATALEN+50];
738 * First execute the insert query and then retrieve the currval.
740 if (!sql_query(query)) {
744 m_num_rows = sql_affected_rows();
745 if (m_num_rows != 1) {
752 * Obtain the current value of the sequence that
753 * provides the serial value for primary key of the table.
755 * currval is local to our session. It is not affected by
756 * other transactions.
758 * Determine the name of the sequence.
759 * PostgreSQL automatically creates a sequence using
760 * <table>_<column>_seq.
761 * At the time of writing, all tables used this format for
762 * for their primary key: <table>id
763 * Except for basefiles which has a primary key on baseid.
764 * Therefore, we need to special case that one table.
766 * everything else can use the PostgreSQL formula.
768 if (strcasecmp(table_name, "basefiles") == 0) {
769 bstrncpy(sequence, "basefiles_baseid", sizeof(sequence));
771 bstrncpy(sequence, table_name, sizeof(sequence));
772 bstrncat(sequence, "_", sizeof(sequence));
773 bstrncat(sequence, table_name, sizeof(sequence));
774 bstrncat(sequence, "id", sizeof(sequence));
777 bstrncat(sequence, "_seq", sizeof(sequence));
778 bsnprintf(getkeyval_query, sizeof(getkeyval_query), "SELECT currval('%s')", sequence);
780 Dmsg1(500, "sql_insert_autokey_record executing query '%s'\n", getkeyval_query);
781 for (i = 0; i < 10; i++) {
782 pg_result = PQexec(m_db_handle, getkeyval_query);
789 Dmsg1(50, "Query failed: %s\n", getkeyval_query);
793 Dmsg0(500, "exec done");
795 if (PQresultStatus(pg_result) == PGRES_TUPLES_OK) {
796 Dmsg0(500, "getting value");
797 id = str_to_uint64(PQgetvalue(pg_result, 0, 0));
798 Dmsg2(500, "got value '%s' which became %d\n", PQgetvalue(pg_result, 0, 0), id);
800 Dmsg1(50, "Result status failed: %s\n", getkeyval_query);
801 Mmsg1(&errmsg, _("error fetching currval: %s\n"), PQerrorMessage(m_db_handle));
810 SQL_FIELD *B_DB_POSTGRESQL::sql_fetch_field(void)
816 Dmsg0(500, "sql_fetch_field starts\n");
818 if (!m_fields || m_fields_size < m_num_fields) {
823 Dmsg1(500, "allocating space for %d fields\n", m_num_fields);
824 m_fields = (SQL_FIELD *)malloc(sizeof(SQL_FIELD) * m_num_fields);
825 m_fields_size = m_num_fields;
827 for (i = 0; i < m_num_fields; i++) {
828 Dmsg1(500, "filling field %d\n", i);
829 m_fields[i].name = PQfname(m_result, i);
830 m_fields[i].type = PQftype(m_result, i);
831 m_fields[i].flags = 0;
834 * For a given column, find the max length.
837 for (j = 0; j < m_num_rows; j++) {
838 if (PQgetisnull(m_result, j, i)) {
839 this_length = 4; /* "NULL" */
841 this_length = cstrlen(PQgetvalue(m_result, j, i));
844 if (max_length < this_length) {
845 max_length = this_length;
848 m_fields[i].max_length = max_length;
850 Dmsg4(500, "sql_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
851 m_fields[i].name, m_fields[i].max_length, m_fields[i].type, m_fields[i].flags);
856 * Increment field number for the next time around
858 return &m_fields[m_field_number++];
861 bool B_DB_POSTGRESQL::sql_field_is_not_null(int field_type)
863 switch (field_type) {
871 bool B_DB_POSTGRESQL::sql_field_is_numeric(int field_type)
874 * TEMP: the following is taken from select OID, typname from pg_type;
876 switch (field_type) {
889 * Escape strings so that PostgreSQL is happy on COPY
891 * NOTE! len is the length of the old string. Your new
892 * string must be long enough (max 2*old+1) to hold
893 * the escaped output.
895 static char *pgsql_copy_escape(char *dest, char *src, size_t len)
897 /* we have to escape \t, \n, \r, \ */
900 while (len > 0 && *src) {
935 bool B_DB_POSTGRESQL::sql_batch_start(JCR *jcr)
937 const char *query = "COPY batch FROM STDIN";
939 Dmsg0(500, "sql_batch_start started\n");
941 if (!sql_query("CREATE TEMPORARY TABLE batch ("
948 "DeltaSeq smallint)")) {
949 Dmsg0(500, "sql_batch_start failed\n");
954 * We are starting a new query. reset everything.
962 for (int i=0; i < 10; i++) {
963 m_result = PQexec(m_db_handle, query);
970 Dmsg1(50, "Query failed: %s\n", query);
974 m_status = PQresultStatus(m_result);
975 if (m_status == PGRES_COPY_IN) {
977 * How many fields in the set?
979 m_num_fields = (int) PQnfields(m_result);
983 Dmsg1(50, "Result status failed: %s\n", query);
987 Dmsg0(500, "sql_batch_start finishing\n");
992 Mmsg1(&errmsg, _("error starting batch mode: %s"), PQerrorMessage(m_db_handle));
1000 * Set error to something to abort operation
1002 bool B_DB_POSTGRESQL::sql_batch_end(JCR *jcr, const char *error)
1006 PGresult *pg_result;
1008 Dmsg0(500, "sql_batch_end started\n");
1011 res = PQputCopyEnd(m_db_handle, error);
1012 } while (res == 0 && --count > 0);
1020 Dmsg0(500, "we failed\n");
1022 Mmsg1(&errmsg, _("error ending batch mode: %s"), PQerrorMessage(m_db_handle));
1023 Dmsg1(500, "failure %s\n", errmsg);
1026 /* Check command status and return to normal libpq state */
1027 pg_result = PQgetResult(m_db_handle);
1028 if (PQresultStatus(pg_result) != PGRES_COMMAND_OK) {
1029 Mmsg1(&errmsg, _("error ending batch mode: %s"), PQerrorMessage(m_db_handle));
1033 /* Get some statistics to compute the best plan */
1034 sql_query("ANALYZE batch");
1038 Dmsg0(500, "sql_batch_end finishing\n");
1042 bool B_DB_POSTGRESQL::sql_batch_insert(JCR *jcr, ATTR_DBR *ar)
1050 esc_name = check_pool_memory_size(esc_name, fnl*2+1);
1051 pgsql_copy_escape(esc_name, fname, fnl);
1053 esc_path = check_pool_memory_size(esc_path, pnl*2+1);
1054 pgsql_copy_escape(esc_path, path, pnl);
1056 if (ar->Digest == NULL || ar->Digest[0] == 0) {
1059 digest = ar->Digest;
1062 len = Mmsg(cmd, "%u\t%s\t%s\t%s\t%s\t%s\t%u\n",
1063 ar->FileIndex, edit_int64(ar->JobId, ed1), esc_path,
1064 esc_name, ar->attr, digest, ar->DeltaSeq);
1067 res = PQputCopyData(m_db_handle, cmd, len);
1068 } while (res == 0 && --count > 0);
1077 Dmsg0(500, "we failed\n");
1079 Mmsg1(&errmsg, _("error copying in batch mode: %s"), PQerrorMessage(m_db_handle));
1080 Dmsg1(500, "failure %s\n", errmsg);
1083 Dmsg0(500, "sql_batch_insert finishing\n");
1089 * Initialize database data structure. In principal this should
1090 * never have errors, or it is really fatal.
1092 B_DB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name,
1093 const char *db_user, const char *db_password,
1094 const char *db_address, int db_port,
1095 const char *db_socket, bool mult_db_connections,
1096 bool disable_batch_insert)
1098 B_DB_POSTGRESQL *mdb = NULL;
1101 Jmsg(jcr, M_FATAL, 0, _("A user name for PostgreSQL must be supplied.\n"));
1104 P(mutex); /* lock DB queue */
1105 if (db_list && !mult_db_connections) {
1107 * Look to see if DB already open
1109 foreach_dlist(mdb, db_list) {
1110 if (mdb->db_match_database(db_driver, db_name, db_address, db_port)) {
1111 Dmsg1(100, "DB REopen %s\n", db_name);
1112 mdb->increment_refcount();
1117 Dmsg0(100, "db_init_database first time\n");
1118 mdb = New(B_DB_POSTGRESQL(jcr, db_driver, db_name, db_user, db_password,
1119 db_address, db_port, db_socket,
1120 mult_db_connections, disable_batch_insert));
1127 #endif /* HAVE_POSTGRESQL */