INCLUDE_FILES = bdb.h cats.h protos.h sql_cmds.h
LIBBACSQL_SRCS = mysql.c bdb.c dbi.c \
- sql.c sql_cmds.c sql_create.c sql_delete.c sql_find.c \
- sql_get.c sql_list.c sql_update.c sqlite.c \
- postgresql.c bvfs.c
+ sql.c sql_cmds.c sql_create.c sql_delete.c sql_find.c \
+ sql_get.c sql_list.c sql_update.c sqlite.c \
+ postgresql.c ingres.c myingres.c \
+ bvfs.c
LIBBACSQL_OBJS = $(LIBBACSQL_SRCS:.c=.o)
LIBBACSQL_LOBJS = $(LIBBACSQL_SRCS:.c=.lo)
.c.lo:
@echo "Compiling $<"
$(NO_ECHO)$(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(SQL_INC) $(DINCLUDE) $(CFLAGS) $<
+
#-------------------------------------------------------------------------
all: Makefile libbacsql$(DEFAULT_ARCHIVE_TYPE)
@echo "==== Make of sqllib is good ===="
@echo " "
+# SRE: embeddedSQL precompiler run
+esql:
+ $(II_SYSTEM)/ingres/bin/esqlc -omyingres.c myingres.sc
+ $(II_SYSTEM)/ingres/bin/esqlc -omyingres.h myingres.sh
+
libbacsql.a: $(LIBBACSQL_OBJS)
@echo "Making $@ ..."
$(AR) rc $@ $(LIBBACSQL_OBJS)
$(RMF) create_postgresql_database update_postgresql_tables make_postgresql_tables
$(RMF) grant_postgresql_privileges drop_postgresql_tables drop_postgresql_database
+ $(RMF) create_ingres_database update_ingres_tables make_ingres_tables
+ $(RMF) grant_ingres_privileges drop_ingres_tables drop_ingres_database
+
$(RMF) create_sqlite_database update_sqlite_tables make_sqlite_tables
$(RMF) grant_sqlite_privileges drop_sqlite_tables drop_sqlite_database
$(RMF) create_sqlite3_database update_sqlite3_tables make_sqlite3_tables
$(RMF) grant_sqlite3_privileges drop_sqlite3_tables drop_sqlite3_database
- $(RMF) mysql sqlite postgresql
+ $(RMF) mysql sqlite postgresql ingres
$(RMF) make_catalog_backup delete_catalog_backup
distclean: realclean
# and it also includes system headers.
# `semi'-automatic since dependencies are generated at distribution time.
-depend:
+#depend: esql <- SRE: if generating from 'real' ingres source
+depend:
@$(MV) Makefile Makefile.bak
@$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile
@$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile
* for the external world. This is control with
* the define __SQL_C, which is defined only in sql.c
*
- * Version $Id$
+ * Version $Id: cats.h 8478 2009-02-18 20:11:55Z kerns $
*/
/*
SQL_TYPE_MYSQL = 0,
SQL_TYPE_POSTGRESQL = 1,
SQL_TYPE_SQLITE = 2,
+ SQL_TYPE_INGRES = 3,
SQL_TYPE_SQLITE3
};
#else
+#ifdef HAVE_INGRES
+
+#include "myingres.h"
+
+#define BDB_VERSION 11
+
+/* TEMP: the following is taken from select OID, typname from pg_type; */ /*SRE: huh? */
+#define IS_NUM(x) ((x) == 20 || (x) == 21 || (x) == 23 || (x) == 700 || (x) == 701)
+#define IS_NOT_NULL(x) ((x) == 1)
+
+typedef char **INGRES_ROW;
+
+/*
+ * This is the "real" definition that should only be
+ * used inside sql.c and associated database interface
+ * subroutines.
+ *
+ * I N G R E S
+ */
+struct B_DB {
+ BQUEUE bq; /* queue control */
+ brwlock_t lock; /* transaction lock */
+ INGconn *db;
+ INGresult *result;
+ int status;
+ INGRES_ROW row;
+ INGRES_FIELD *fields;
+ int num_rows;
+ int row_size; /* size of malloced rows */
+ int num_fields;
+ int fields_size; /* size of malloced fields */
+ int row_number; /* row number from my_ingres_data_seek */
+ int field_number; /* field number from my_ingres_field_seek */
+ int ref_count;
+ char *db_name;
+ char *db_user;
+ char *db_password;
+ char *db_address; /* host address */
+ char *db_socket; /* socket for local access */
+ int db_port; /* port of host address */
+ int have_insert_id; /* do have insert_id() */
+ bool connected;
+ POOLMEM *errmsg; /* nicely edited error message */
+ POOLMEM *cmd; /* SQL command string */
+ POOLMEM *cached_path;
+ int cached_path_len; /* length of cached path */
+ uint32_t cached_path_id;
+ bool allow_transactions; /* transactions allowed */
+ bool transaction; /* transaction started */
+ int changes; /* changes made to db */
+ POOLMEM *fname; /* Filename only */
+ POOLMEM *path; /* Path only */
+ POOLMEM *esc_name; /* Escaped file name */
+ POOLMEM *esc_path; /* Escaped path name */
+ int fnl; /* file name length */
+ int pnl; /* path name length */
+};
+
+void my_ingres_free_result(B_DB *mdb);
+INGRES_ROW my_ingres_fetch_row (B_DB *mdb);
+int my_ingres_query (B_DB *mdb, const char *query);
+void my_ingres_data_seek (B_DB *mdb, int row);
+int my_ingres_currval (B_DB *mdb, const char *table_name);
+void my_ingres_field_seek (B_DB *mdb, int row);
+INGRES_FIELD * my_ingres_fetch_field(B_DB *mdb);
+void my_ingres_close (B_DB *mdb);
+
+int my_ingres_batch_start(JCR *jcr, B_DB *mdb);
+int my_ingres_batch_end(JCR *jcr, B_DB *mdb, const char *error);
+typedef struct ATTR_DBR ATTR_DBR;
+int my_ingres_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar);
+char *my_ingres_copy_escape(char *dest, char *src, size_t len);
+
+extern const char* my_ingres_batch_lock_path_query;
+extern const char* my_ingres_batch_lock_filename_query;
+extern const char* my_ingres_batch_unlock_tables_query;
+extern const char* my_ingres_batch_fill_filename_query;
+extern const char* my_ingres_batch_fill_path_query;
+
+/* "Generic" names for easier conversion */
+#define sql_store_result(x) ((x)->result)
+#define sql_free_result(x) my_ingres_free_result(x)
+#define sql_fetch_row(x) my_ingres_fetch_row(x)
+#define sql_query(x, y) my_ingres_query((x), (y))
+#define sql_close(x) my_ingres_close(x)
+#define sql_strerror(x) INGerrorMessage((x)->db)
+#define sql_num_rows(x) ((unsigned) INGntuples((x)->result))
+#define sql_data_seek(x, i) my_ingres_data_seek((x), (i))
+#define sql_affected_rows(x) ((unsigned) atoi(INGcmdTuples((x)->result)))
+#define sql_insert_id(x,y) my_ingres_currval((x), (y))
+#define sql_field_seek(x, y) my_ingres_field_seek((x), (y))
+#define sql_fetch_field(x) my_ingres_fetch_field(x)
+#define sql_num_fields(x) ((x)->num_fields)
+
+#define sql_batch_start(x,y) my_ingres_batch_start(x,y)
+#define sql_batch_end(x,y,z) my_ingres_batch_end(x,y,z)
+#define sql_batch_insert(x,y,z) my_ingres_batch_insert(x,y,z)
+#define sql_batch_lock_path_query my_ingres_batch_lock_path_query
+#define sql_batch_lock_filename_query my_ingres_batch_lock_filename_query
+#define sql_batch_unlock_tables_query my_ingres_batch_unlock_tables_query
+#define sql_batch_fill_filename_query my_ingres_batch_fill_filename_query
+#define sql_batch_fill_path_query my_ingres_batch_fill_path_query
+
+#define SQL_ROW INGRES_ROW
+#define SQL_FIELD INGRES_FIELD
+
+#else
+
#ifdef HAVE_DBI
#define BDB_VERSION 11
#endif /* HAVE_MYSQL */
#endif /* HAVE_SQLITE */
#endif /* HAVE_POSTGRESQL */
+#endif /* HAVE_INGRES */
#endif /* HAVE_DBI */
#endif
#!/bin/sh
#
# This routine creates the Bacula database
-# using PostgreSQL, MySQL, or SQLite.
+# using PostgreSQL, Ingres, MySQL, or SQLite.
#
if test xsqlite3 = x@DB_TYPE@ ; then
echo "Creating SQLite database"
if test xmysql = x@DB_TYPE@ ; then
echo "Creating MySQL database"
@scriptdir@/create_mysql_database $*
+ elif test xingres = x@DB_TYPE@ ; then
+ echo "Creating Ingres database"
+ @scriptdir@/create_ingres_database $*
else
echo "Creating PostgreSQL database"
@scriptdir@/create_postgresql_database $*
--- /dev/null
+#!/bin/sh
+#
+# shell script to create Bacula database(s)
+#
+
+bindir=@SQL_BINDIR@
+db_name=@db_name@
+
+# use SQL_ASCII to be able to put any filename into
+# the database even those created with unusual character sets
+ENCODING="ENCODING 'SQL_ASCII'"
+
+# use UTF8 if you are using standard Unix/Linux LANG specifications
+# that use UTF8 -- this is normally the default and *should* be
+# your standard. Bacula works correctly *only* with correct UTF8.
+#
+# Note, with this encoding, if you have any "weird" filenames on
+# your system (names generated from Win32 or Mac OS), you may
+# get Bacula batch insert failures.
+#
+#ENCODING="ENCODING 'UTF8'"
+
+if createdb $* ${db_name}
+then
+ echo "Creation of ${db_name} database succeeded."
+else
+ echo "Creation of ${db_name} database failed."
+fi
+exit 0
#!/bin/sh
#
# Drop Bacula database -- works for whatever is configured,
-# MySQL, SQLite, PostgreSQL
+# MySQL, SQLite, PostgreSQL, Ingres
#
if test xsqlite3 = x@DB_TYPE@ ; then
@scriptdir@/drop_@DB_TYPE@_database $*
if test xmysql = x@DB_TYPE@ ; then
echo "Making MySQL database"
@scriptdir@/drop_mysql_database $*
+ elif test xingres = x@DB_TYPE@ ; then
+ echo "Dropping Ingres database"
+ @scriptdir@/drop_ingres_database $*
else
@scriptdir@/drop_postgresql_database $*
fi
#!/bin/sh
#
# Drop Bacula tables -- works for whatever is configured,
-# MySQL, SQLite, or PostgreSQL
+# MySQL, SQLite, Ingres, or PostgreSQL
#
if test xsqlite3 = x@DB_TYPE@ ; then
@scriptdir@/drop_@DB_TYPE@_tables $*
echo "Making MySQL tables"
@scriptdir@/drop_mysql_tables $*
echo "Dropped MySQL tables"
+ elif test xingres = x@DB_TYPE@ ; then
+ echo "Dropping Ingres tables"
+ @scriptdir@/drop_ingres_tables $*
+ echo "Dropped Ingres tables"
else
# hardcoded database name - should be a parameter
@scriptdir@/drop_postgresql_tables $*
--- /dev/null
+#!/bin/sh
+#
+# shell script to drop Bacula database(s)
+#
+
+bindir=@SQL_BINDIR@
+db_name=@db_name@
+
+if destroydb ${db_name}
+then
+ echo "Drop of ${db_name} database succeeded."
+else
+ echo "Drop of ${db_name} database failed."
+fi
+exit 0
--- /dev/null
+#!/bin/sh
+#
+# shell script to delete Bacula tables for PostgreSQL
+
+bindir=@SQL_BINDIR@
+db_name=@db_name@
+
+sql -u${db_user} ${db_name} $* <<END-OF-DATA
+drop table unsavedfiles;
+drop table basefiles;
+drop table jobmedia;
+drop table file;
+drop table job;
+drop table jobhisto;
+drop table media;
+drop table client;
+drop table pool;
+drop table fileset;
+drop table path;
+drop table filename;
+drop table counters;
+drop table version;
+drop table CDImages;
+drop table Device;
+drop table Storage;
+drop table MediaType;
+drop table Status;
+drop table MAC;
+drop table log;
+drop table Location;
+drop table locationlog;
+END-OF-DATA
+pstat=$?
+if test $pstat = 0;
+then
+ echo "Deletion of Bacula Ingres tables succeeded."
+else
+ echo "Deletion of Bacula Ingres tables failed."
+fi
+exit $pstat
if test xpostgresql = x@DB_TYPE@ ; then
echo "Granting PostgreSQL privileges"
@scriptdir@/grant_postgresql_privileges $*
+ elif test xingres = x@DB_TYPE@ ; then
+ echo "Granting Ingres privileges"
+ @scriptdir@/grant_ingres_privileges $*
else
if test xsqlite3 = x@DB_TYPE@ ; then
echo "Granting SQLite privileges"
--- /dev/null
+#!/bin/sh
+#
+# shell script to grant privileges to the bacula database
+#
+db_user=${db_user:-@db_user@}
+bindir=@SQL_BINDIR@
+db_name=${db_name:-@db_name@}
+
+if sql ${db_name} $* <<END-OF-DATA
+
+create user ${db_user};
+
+-- for tables
+grant all on unsavedfiles to ${db_user};
+grant all on basefiles to ${db_user};
+grant all on jobmedia to ${db_user};
+grant all on file to ${db_user};
+grant all on job to ${db_user};
+grant all on media to ${db_user};
+grant all on client to ${db_user};
+grant all on pool to ${db_user};
+grant all on fileset to ${db_user};
+grant all on path to ${db_user};
+grant all on filename to ${db_user};
+grant all on counters to ${db_user};
+grant all on version to ${db_user};
+grant all on cdimages to ${db_user};
+grant all on mediatype to ${db_user};
+grant all on storage to ${db_user};
+grant all on device to ${db_user};
+grant all on status to ${db_user};
+grant all on location to ${db_user};
+grant all on locationlog to ${db_user};
+grant all on log to ${db_user};
+grant all on jobhisto to ${db_user};
+
+-- for sequences on those tables
+
+grant select, update on filename_filenameid_seq to ${db_user};
+grant select, update on path_pathid_seq to ${db_user};
+grant select, update on fileset_filesetid_seq to ${db_user};
+grant select, update on pool_poolid_seq to ${db_user};
+grant select, update on client_clientid_seq to ${db_user};
+grant select, update on media_mediaid_seq to ${db_user};
+grant select, update on job_jobid_seq to ${db_user};
+grant select, update on file_fileid_seq to ${db_user};
+grant select, update on jobmedia_jobmediaid_seq to ${db_user};
+grant select, update on basefiles_baseid_seq to ${db_user};
+grant select, update on storage_storageid_seq to ${db_user};
+grant select, update on mediatype_mediatypeid_seq to ${db_user};
+grant select, update on device_deviceid_seq to ${db_user};
+grant select, update on location_locationid_seq to ${db_user};
+grant select, update on locationlog_loclogid_seq to ${db_user};
+grant select, update on log_logid_seq to ${db_user};
+
+END-OF-DATA
+then
+ echo "Privileges for ${db_user} granted on ${db_name}."
+ exit 0
+else
+ echo "Error creating privileges."
+ exit 1
+fi
--- /dev/null
+/*
+ Bacula® - The Network Backup Solution
+
+ Copyright (C) 2003-2007 Free Software Foundation Europe e.V.
+
+ The main author of Bacula is Kern Sibbald, with contributions from
+ many others, a complete list can be found in the file AUTHORS.
+ This program is Free Software; you can redistribute it and/or
+ modify it under the terms of version two of the GNU General Public
+ License as published by the Free Software Foundation and included
+ in the file LICENSE.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+
+ Bacula® is a registered trademark of Kern Sibbald.
+ The licensor of Bacula is the Free Software Foundation Europe
+ (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+ Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * Bacula Catalog Database routines specific to Ingres
+ * These are Ingres specific routines
+ *
+ * Stefan Reddig, June 2009
+ * based uopn work done
+ * by Dan Langille, December 2003 and
+ * by Kern Sibbald, March 2000
+ *
+ */
+
+
+/* The following is necessary so that we do not include
+ * the dummy external definition of DB.
+ */
+#define __SQL_C /* indicate that this is sql.c */
+
+#include "bacula.h"
+#include "cats.h"
+
+#ifdef HAVE_INGRES
+
+#include "myingres.h"
+
+/* -----------------------------------------------------------------------
+ *
+ * Ingres dependent defines and subroutines
+ *
+ * -----------------------------------------------------------------------
+ */
+
+/* List of open databases */ /* SRE: needed for ingres? */
+static BQUEUE db_list = {&db_list, &db_list};
+
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/*
+ * Retrieve database type
+ */
+const char *
+db_get_type(void)
+{
+ return "Ingres";
+}
+
+/*
+ * Initialize database data structure. In principal this should
+ * never have errors, or it is really fatal.
+ */
+B_DB *
+db_init_database(JCR *jcr, const char *db_name, const char *db_user, const char *db_password,
+ const char *db_address, int db_port, const char *db_socket,
+ int mult_db_connections)
+{
+ B_DB *mdb;
+
+ if (!db_user) {
+ Jmsg(jcr, M_FATAL, 0, _("A user name for Ingres must be supplied.\n"));
+ return NULL;
+ }
+ P(mutex); /* lock DB queue */
+ if (!mult_db_connections) {
+ /* Look to see if DB already open */
+ for (mdb=NULL; (mdb=(B_DB *)qnext(&db_list, &mdb->bq)); ) {
+ if (bstrcmp(mdb->db_name, db_name) &&
+ bstrcmp(mdb->db_address, db_address) &&
+ mdb->db_port == db_port) {
+ Dmsg2(100, "DB REopen %d %s\n", mdb->ref_count, db_name);
+ mdb->ref_count++;
+ V(mutex);
+ return mdb; /* already open */
+ }
+ }
+ }
+ Dmsg0(100, "db_open first time\n");
+ mdb = (B_DB *)malloc(sizeof(B_DB));
+ memset(mdb, 0, sizeof(B_DB));
+ mdb->db_name = bstrdup(db_name);
+ mdb->db_user = bstrdup(db_user);
+ if (db_password) {
+ mdb->db_password = bstrdup(db_password);
+ }
+ if (db_address) {
+ mdb->db_address = bstrdup(db_address);
+ }
+ if (db_socket) {
+ mdb->db_socket = bstrdup(db_socket);
+ }
+ mdb->db_port = db_port;
+ mdb->have_insert_id = TRUE;
+ mdb->errmsg = get_pool_memory(PM_EMSG); /* get error message buffer */
+ *mdb->errmsg = 0;
+ mdb->cmd = get_pool_memory(PM_EMSG); /* get command buffer */
+ mdb->cached_path = get_pool_memory(PM_FNAME);
+ mdb->cached_path_id = 0;
+ mdb->ref_count = 1;
+ mdb->fname = get_pool_memory(PM_FNAME);
+ mdb->path = get_pool_memory(PM_FNAME);
+ mdb->esc_name = get_pool_memory(PM_FNAME);
+ mdb->esc_path = get_pool_memory(PM_FNAME);
+ mdb->allow_transactions = mult_db_connections;
+ qinsert(&db_list, &mdb->bq); /* put db in list */
+ V(mutex);
+ return mdb;
+}
+
+/* Check that the database correspond to the encoding we want */
+static bool check_database_encoding(JCR *jcr, B_DB *mdb)
+{
+/* SRE: TODO! Needed?
+ SQL_ROW row;
+ int ret=false;
+
+ if (!db_sql_query(mdb, "SELECT getdatabaseencoding()", NULL, NULL)) {
+ Jmsg(jcr, M_ERROR, 0, "%s", mdb->errmsg);
+ return false;
+ }
+
+ if ((row = sql_fetch_row(mdb)) == NULL) {
+ Mmsg1(mdb->errmsg, _("error fetching row: %s\n"), sql_strerror(mdb));
+ Jmsg(jcr, M_ERROR, 0, "Can't check database encoding %s", mdb->errmsg);
+ } else {
+ ret = bstrcmp(row[0], "SQL_ASCII");
+ if (!ret) {
+ Mmsg(mdb->errmsg,
+ _("Encoding error for database \"%s\". Wanted SQL_ASCII, got %s\n"),
+ mdb->db_name, row[0]);
+ Jmsg(jcr, M_WARNING, 0, "%s", mdb->errmsg);
+ Dmsg1(50, "%s", mdb->errmsg);
+ }
+ }
+ return ret;
+*/
+ return true;
+}
+
+/*
+ * Check for errors in DBMS work
+ */
+static int sql_check(B_DB *mdb)
+{
+ return INGcheck();
+}
+
+/*
+ * Now actually open the database. This can generate errors,
+ * which are returned in the errmsg
+ *
+ * DO NOT close the database or free(mdb) here !!!!
+ */
+int
+db_open_database(JCR *jcr, B_DB *mdb)
+{
+ int errstat;
+ char buf[10], *port;
+
+ P(mutex);
+ if (mdb->connected) {
+ V(mutex);
+ return 1;
+ }
+ mdb->connected = false;
+
+ if ((errstat=rwl_init(&mdb->lock)) != 0) {
+ berrno be;
+ Mmsg1(&mdb->errmsg, _("Unable to initialize DB lock. ERR=%s\n"),
+ be.bstrerror(errstat));
+ V(mutex);
+ return 0;
+ }
+
+ if (mdb->db_port) {
+ bsnprintf(buf, sizeof(buf), "%d", mdb->db_port);
+ port = buf;
+ } else {
+ port = NULL;
+ }
+
+ mdb->db = INGconnectDB(mdb->db_name, mdb->db_user, mdb->db_password);
+
+ Dmsg0(50, "Ingres real CONNECT done\n");
+ Dmsg3(50, "db_user=%s db_name=%s db_password=%s\n", mdb->db_user, mdb->db_name,
+ mdb->db_password==NULL?"(NULL)":mdb->db_password);
+
+ if (sql_check(mdb)) {
+ Mmsg2(&mdb->errmsg, _("Unable to connect to Ingres server.\n"
+ "Database=%s User=%s\n"
+ "It is probably not running or your password is incorrect.\n"),
+ mdb->db_name, mdb->db_user);
+ V(mutex);
+ return 0;
+ }
+
+ mdb->connected = true;
+
+ if (!check_tables_version(jcr, mdb)) {
+ V(mutex);
+ return 0;
+ }
+
+ //sql_query(mdb, "SET datestyle TO 'ISO, YMD'");
+
+ /* check that encoding is SQL_ASCII */
+ check_database_encoding(jcr, mdb);
+
+ V(mutex);
+ return 1;
+}
+
+void
+db_close_database(JCR *jcr, B_DB *mdb)
+{
+ if (!mdb) {
+ return;
+ }
+ db_end_transaction(jcr, mdb);
+ P(mutex);
+ sql_free_result(mdb);
+ mdb->ref_count--;
+ if (mdb->ref_count == 0) {
+ qdchain(&mdb->bq);
+ if (mdb->connected && mdb->db) {
+ sql_close(mdb);
+ }
+ rwl_destroy(&mdb->lock);
+ free_pool_memory(mdb->errmsg);
+ free_pool_memory(mdb->cmd);
+ free_pool_memory(mdb->cached_path);
+ free_pool_memory(mdb->fname);
+ free_pool_memory(mdb->path);
+ free_pool_memory(mdb->esc_name);
+ free_pool_memory(mdb->esc_path);
+ if (mdb->db_name) {
+ free(mdb->db_name);
+ }
+ if (mdb->db_user) {
+ free(mdb->db_user);
+ }
+ if (mdb->db_password) {
+ free(mdb->db_password);
+ }
+ if (mdb->db_address) {
+ free(mdb->db_address);
+ }
+ if (mdb->db_socket) {
+ free(mdb->db_socket);
+ }
+ free(mdb);
+ }
+ V(mutex);
+}
+
+void db_thread_cleanup()
+{ }
+
+/*
+ * Return the next unique index (auto-increment) for
+ * the given table. Return NULL on error.
+ *
+ * For Ingres, NULL causes the auto-increment value SRE: true?
+ * to be updated.
+ */
+int db_next_index(JCR *jcr, B_DB *mdb, char *table, char *index)
+{
+ strcpy(index, "NULL");
+ return 1;
+}
+
+
+/*
+ * Escape strings so that Ingres is happy
+ *
+ * NOTE! len is the length of the old string. Your new
+ * string must be long enough (max 2*old+1) to hold
+ * the escaped output.
+ * SRE: TODO!
+ */
+void
+db_escape_string(JCR *jcr, B_DB *mdb, char *snew, char *old, int len)
+{
+/*
+ int error;
+
+ PQescapeStringConn(mdb->db, snew, old, len, &error);
+ if (error) {
+ Jmsg(jcr, M_FATAL, 0, _("PQescapeStringConn returned non-zero.\n"));*/
+ /* error on encoding, probably invalid multibyte encoding in the source string
+ see PQescapeStringConn documentation for details. */
+/* Dmsg0(500, "PQescapeStringConn failed\n");
+ }*/
+}
+
+/*
+ * Submit a general SQL command (cmd), and for each row returned,
+ * the sqlite_handler is called with the ctx.
+ */
+bool db_sql_query(B_DB *mdb, const char *query, DB_RESULT_HANDLER *result_handler, void *ctx)
+{
+ SQL_ROW row;
+
+ Dmsg0(500, "db_sql_query started\n");
+
+ db_lock(mdb);
+ if (sql_query(mdb, query) != 0) {
+ Mmsg(mdb->errmsg, _("Query failed: %s: ERR=%s\n"), query, sql_strerror(mdb));
+ db_unlock(mdb);
+ Dmsg0(500, "db_sql_query failed\n");
+ return false;
+ }
+ Dmsg0(500, "db_sql_query succeeded. checking handler\n");
+
+ if (result_handler != NULL) {
+ Dmsg0(500, "db_sql_query invoking handler\n");
+ if ((mdb->result = sql_store_result(mdb)) != NULL) {
+ int num_fields = sql_num_fields(mdb);
+
+ Dmsg0(500, "db_sql_query sql_store_result suceeded\n");
+ while ((row = sql_fetch_row(mdb)) != NULL) {
+
+ Dmsg0(500, "db_sql_query sql_fetch_row worked\n");
+ if (result_handler(ctx, num_fields, row))
+ break;
+ }
+
+ sql_free_result(mdb);
+ }
+ }
+ db_unlock(mdb);
+
+ Dmsg0(500, "db_sql_query finished\n");
+
+ return true;
+}
+
+/*
+ * Close database connection
+ */
+void my_ingres_close(B_DB *mdb)
+{
+ INGdisconnectDB(mdb->db);
+ //SRE: error handling?
+}
+
+INGRES_ROW my_ingres_fetch_row(B_DB *mdb)
+{
+ int j;
+ INGRES_ROW row = NULL; // by default, return NULL
+
+ Dmsg0(500, "my_ingres_fetch_row start\n");
+
+ if (!mdb->row || mdb->row_size < mdb->num_fields) {
+ int num_fields = mdb->num_fields;
+ Dmsg1(500, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
+
+ if (mdb->row) {
+ Dmsg0(500, "my_ingres_fetch_row freeing space\n");
+ free(mdb->row);
+ }
+ num_fields += 20; /* add a bit extra */
+ mdb->row = (INGRES_ROW)malloc(sizeof(char *) * num_fields);
+ mdb->row_size = num_fields;
+
+ // now reset the row_number now that we have the space allocated
+ mdb->row_number = 0;
+ }
+
+ // if still within the result set
+ if (mdb->row_number < mdb->num_rows) {
+ Dmsg2(500, "my_ingres_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+ // get each value from this row
+ for (j = 0; j < mdb->num_fields; j++) {
+ mdb->row[j] = INGgetvalue(mdb->result, mdb->row_number, j);
+ Dmsg2(500, "my_ingres_fetch_row field '%d' has value '%s'\n", j, mdb->row[j]);
+ }
+ // increment the row number for the next call
+ mdb->row_number++;
+
+ row = mdb->row;
+ } else {
+ Dmsg2(500, "my_ingres_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+ }
+
+ Dmsg1(500, "my_ingres_fetch_row finishes returning %p\n", row);
+
+ return row;
+}
+
+
+int my_ingres_max_length(B_DB *mdb, int field_num) {
+ //
+ // for a given column, find the max length
+ //
+ int max_length;
+ int i;
+ int this_length;
+
+ max_length = 0;
+ for (i = 0; i < mdb->num_rows; i++) {
+ if (INGgetisnull(mdb->result, i, field_num)) {
+ this_length = 4; // "NULL"
+ } else {
+ this_length = cstrlen(INGgetvalue(mdb->result, i, field_num));
+ }
+
+ if (max_length < this_length) {
+ max_length = this_length;
+ }
+ }
+
+ return max_length;
+}
+
+INGRES_FIELD * my_ingres_fetch_field(B_DB *mdb)
+{
+ int i;
+
+ Dmsg0(500, "my_ingres_fetch_field starts\n");
+
+ if (!mdb->fields || mdb->fields_size < mdb->num_fields) {
+ if (mdb->fields) {
+ free(mdb->fields);
+ }
+ Dmsg1(500, "allocating space for %d fields\n", mdb->num_fields);
+ mdb->fields = (INGRES_FIELD *)malloc(sizeof(INGRES_FIELD) * mdb->num_fields);
+ mdb->fields_size = mdb->num_fields;
+
+ for (i = 0; i < mdb->num_fields; i++) {
+ Dmsg1(500, "filling field %d\n", i);
+ strcpy(mdb->fields[i].name,INGfname(mdb->result, i));
+ mdb->fields[i].max_length = my_ingres_max_length(mdb, i);
+ mdb->fields[i].type = INGftype(mdb->result, i);
+ mdb->fields[i].flags = 0;
+
+ Dmsg4(500, "my_ingres_fetch_field finds field '%s' has length='%d' type='%d' and IsNull=%d\n",
+ mdb->fields[i].name, mdb->fields[i].max_length, mdb->fields[i].type,
+ mdb->fields[i].flags);
+ } // end for
+ } // end if
+
+ // increment field number for the next time around
+
+ Dmsg0(500, "my_ingres_fetch_field finishes\n");
+ return &mdb->fields[mdb->field_number++];
+}
+
+void my_ingres_data_seek(B_DB *mdb, int row)
+{
+ // set the row number to be returned on the next call
+ // to my_ingres_fetch_row
+ mdb->row_number = row;
+}
+
+void my_ingres_field_seek(B_DB *mdb, int field)
+{
+ mdb->field_number = field;
+}
+
+/*
+ * Note, if this routine returns 1 (failure), Bacula expects
+ * that no result has been stored.
+ * This is where QUERY_DB comes with Ingres. SRE: true?
+ *
+ * Returns: 0 on success
+ * 1 on failure
+ *
+ */
+int my_ingres_query(B_DB *mdb, const char *query)
+{
+ Dmsg0(500, "my_ingres_query started\n");
+ // We are starting a new query. reset everything.
+ mdb->num_rows = -1;
+ mdb->row_number = -1;
+ mdb->field_number = -1;
+
+ if (mdb->result) {
+ INGclear(mdb->result); /* hmm, someone forgot to free?? */
+ mdb->result = NULL;
+ }
+
+ Dmsg1(500, "my_ingres_query starts with '%s'\n", query);
+ mdb->result = INGexec(mdb->db, query);
+ if (!mdb->result) {
+ Dmsg1(50, "Query failed: %s\n", query);
+ goto bail_out;
+ }
+
+ mdb->status = INGresultStatus(mdb->result);
+ if (mdb->status == ING_COMMAND_OK) {
+ Dmsg1(500, "we have a result\n", query);
+
+ // how many fields in the set?
+ mdb->num_fields = (int)INGnfields(mdb->result);
+ Dmsg1(500, "we have %d fields\n", mdb->num_fields);
+
+ mdb->num_rows = INGntuples(mdb->result);
+ Dmsg1(500, "we have %d rows\n", mdb->num_rows);
+
+ mdb->status = 0; /* succeed */
+ } else {
+ Dmsg1(50, "Result status failed: %s\n", query);
+ goto bail_out;
+ }
+
+ Dmsg0(500, "my_ingres_query finishing\n");
+ return mdb->status;
+
+bail_out:
+ Dmsg1(500, "we failed\n", query);
+ INGclear(mdb->result);
+ mdb->result = NULL;
+ mdb->status = 1; /* failed */
+ return mdb->status;
+}
+
+void my_ingres_free_result(B_DB *mdb)
+{
+
+ db_lock(mdb);
+ if (mdb->result) {
+ INGclear(mdb->result);
+ mdb->result = NULL;
+ }
+
+ if (mdb->row) {
+ free(mdb->row);
+ mdb->row = NULL;
+ }
+
+ if (mdb->fields) {
+ free(mdb->fields);
+ mdb->fields = NULL;
+ }
+ db_unlock(mdb);
+}
+
+int my_ingres_currval(B_DB *mdb, const char *table_name)
+{
+ // TODO!
+ return -1;
+}
+
+#ifdef HAVE_BATCH_FILE_INSERT
+
+int my_ingres_batch_start(JCR *jcr, B_DB *mdb)
+{
+ //TODO!
+ return ING_ERROR;
+}
+
+/* set error to something to abort operation */
+int my_ingres_batch_end(JCR *jcr, B_DB *mdb, const char *error)
+{
+ //TODO!
+ return ING_ERROR;
+}
+
+int my_ingres_batch_insert(JCR *jcr, B_DB *mdb, ATTR_DBR *ar)
+{
+ //TODO!
+ return ING_ERROR;
+}
+
+#endif /* HAVE_BATCH_FILE_INSERT */
+
+/*
+ * Escape strings so that Ingres is happy on COPY
+ *
+ * NOTE! len is the length of the old string. Your new
+ * string must be long enough (max 2*old+1) to hold
+ * the escaped output.
+ */
+char *my_ingres_copy_escape(char *dest, char *src, size_t len)
+{
+ /* we have to escape \t, \n, \r, \ */
+ char c = '\0' ;
+
+ while (len > 0 && *src) {
+ switch (*src) {
+ case '\n':
+ c = 'n';
+ break;
+ case '\\':
+ c = '\\';
+ break;
+ case '\t':
+ c = 't';
+ break;
+ case '\r':
+ c = 'r';
+ break;
+ default:
+ c = '\0' ;
+ }
+
+ if (c) {
+ *dest = '\\';
+ dest++;
+ *dest = c;
+ } else {
+ *dest = *src;
+ }
+
+ len--;
+ src++;
+ dest++;
+ }
+
+ *dest = '\0';
+ return dest;
+}
+
+#ifdef HAVE_BATCH_FILE_INSERT
+const char *my_ingres_batch_lock_path_query =
+ "BEGIN; LOCK TABLE Path IN SHARE ROW EXCLUSIVE MODE";
+
+
+const char *my_ingres_batch_lock_filename_query =
+ "BEGIN; LOCK TABLE Filename IN SHARE ROW EXCLUSIVE MODE";
+
+const char *my_ingres_batch_unlock_tables_query = "COMMIT";
+
+const char *my_ingres_batch_fill_path_query =
+ "INSERT INTO Path (Path) "
+ "SELECT a.Path FROM "
+ "(SELECT DISTINCT Path FROM batch) AS a "
+ "WHERE NOT EXISTS (SELECT Path FROM Path WHERE Path = a.Path) ";
+
+
+const char *my_ingres_batch_fill_filename_query =
+ "INSERT INTO Filename (Name) "
+ "SELECT a.Name FROM "
+ "(SELECT DISTINCT Name FROM batch) as a "
+ "WHERE NOT EXISTS "
+ "(SELECT Name FROM Filename WHERE Name = a.Name)";
+#endif /* HAVE_BATCH_FILE_INSERT */
+
+#endif /* HAVE_INGRES */
--- /dev/null
+#!/bin/sh
+#
+# shell script to create Bacula PostgreSQL tables
+#
+bindir=@SQL_BINDIR@
+db_name=@db_name@
+
+sql $* ${db_name}
#!/bin/sh
#
# This routine makes the appropriately configured
-# Bacula tables for PostgreSQL, MySQL, or SQLite.
+# Bacula tables for PostgreSQL, Ingres, MySQL, or SQLite.
#
if test xsqlite3 = x@DB_TYPE@ ; then
echo "Making SQLite tables"
if test xmysql = x@DB_TYPE@ ; then
echo "Making MySQL tables"
@scriptdir@/make_mysql_tables $*
+ elif test xingres = x@DB_TYPE@ ; then
+ echo "Making Ingres tables"
+ @scriptdir@/make_ingres_tables $*
else
echo "Making PostgreSQL tables"
@scriptdir@/make_postgresql_tables $*
--- /dev/null
+#!/bin/sh
+#
+# shell script to create Bacula PostgreSQL tables
+#
+bindir=@SQL_BINDIR@
+db_name=${db_name:-@db_name@}
+
+sql $* ${db_name} <<END-OF-DATA
+
+SET AUTOCOMMIT ON\g
+
+CREATE SEQUENCE filename_seq;
+CREATE TABLE filename
+(
+ filenameid integer not null default filename_seq.nextval,
+ name text not null,
+ primary key (filenameid)
+);
+
+ALTER TABLE filename ALTER COLUMN name SET STATISTICS 1000;
+CREATE UNIQUE INDEX filename_name_idx on filename (name);
+
+CREATE SEQUENCE path_seq;
+CREATE TABLE path
+(
+ pathid integer not null default path_seq.nextval,
+ path text not null,
+ primary key (pathid)
+);
+
+ALTER TABLE path ALTER COLUMN path SET STATISTICS 1000;
+CREATE UNIQUE INDEX path_name_idx on path (path);
+
+CREATE SEQUENCE file_seq;
+CREATE TABLE file
+(
+ fileid integer8 not null default file_seq.nextval,
+ fileindex integer not null default 0,
+ jobid integer not null,
+ pathid integer not null,
+ filenameid integer not null,
+ markid integer not null default 0,
+ lstat text not null,
+ md5 text not null,
+ primary key (fileid)
+);
+
+CREATE INDEX file_jobid_idx on file (jobid);
+CREATE INDEX file_fp_idx on file (filenameid, pathid);
+
+--
+-- Add this if you have a good number of job
+-- that run at the same time
+-- ALTER SEQUENCE file_fileid_seq CACHE 1000;
+
+--
+-- Possibly add one or more of the following indexes
+-- if your Verifies are too slow.
+--
+-- CREATE INDEX file_pathid_idx on file(pathid);
+-- CREATE INDEX file_filenameid_idx on file(filenameid);
+-- CREATE INDEX file_jpfid_idx on file (jobid, pathid, filenameid);
+
+CREATE SEQUENCE job_seq;
+CREATE TABLE job
+(
+ jobid integer not null default job_seq.nextval,
+ job text not null,
+ name text not null,
+ type char(1) not null,
+ level char(1) not null,
+ clientid integer default 0,
+ jobstatus char(1) not null,
+ schedtime timestamp without time zone,
+ starttime timestamp without time zone,
+ endtime timestamp without time zone,
+ realendtime timestamp without time zone,
+ jobtdate bigint default 0,
+ volsessionid integer default 0,
+ volsessiontime integer default 0,
+ jobfiles integer default 0,
+ jobbytes bigint default 0,
+ readbytes bigint default 0,
+ joberrors integer default 0,
+ jobmissingfiles integer default 0,
+ poolid integer default 0,
+ filesetid integer default 0,
+ purgedfiles smallint default 0,
+ hasbase smallint default 0,
+ priorjobid integer default 0,
+ primary key (jobid)
+);
+
+CREATE INDEX job_name_idx on job (name);
+
+-- Create a table like Job for long term statistics
+CREATE TABLE JobHisto (LIKE Job);
+CREATE INDEX jobhisto_idx ON jobhisto ( starttime );
+
+
+CREATE SEQUENCE Location_seq;
+CREATE TABLE Location (
+ LocationId integer not null default Location_seq.nextval,
+ Location text not null,
+ Cost integer default 0,
+ Enabled smallint,
+ primary key (LocationId)
+);
+
+
+CREATE SEQUENCE fileset_seq;
+CREATE TABLE fileset
+(
+ filesetid integer not null default fileset_seq.nextval,
+ fileset text not null,
+ md5 text not null,
+ createtime timestamp without time zone not null,
+ primary key (filesetid)
+);
+
+CREATE INDEX fileset_name_idx on fileset (fileset);
+
+CREATE SEQUENCE jobmedia_seq;
+CREATE TABLE jobmedia
+(
+ jobmediaid integer not null default jobmedia_seq.nestval,
+ jobid integer not null,
+ mediaid integer not null,
+ firstindex integer default 0,
+ lastindex integer default 0,
+ startfile integer default 0,
+ endfile integer default 0,
+ startblock bigint default 0,
+ endblock bigint default 0,
+ volindex integer default 0,
+ copy integer default 0,
+ primary key (jobmediaid)
+);
+
+CREATE INDEX job_media_job_id_media_id_idx on jobmedia (jobid, mediaid);
+
+CREATE SEQUENCE media_seq;
+CREATE TABLE media
+(
+ mediaid integer not null default media_seq.nextval,
+ volumename text not null,
+ slot integer default 0,
+ poolid integer default 0,
+ mediatype text not null,
+ mediatypeid integer default 0,
+ labeltype integer default 0,
+ firstwritten timestamp without time zone,
+ lastwritten timestamp without time zone,
+ labeldate timestamp without time zone,
+ voljobs integer default 0,
+ volfiles integer default 0,
+ volblocks integer default 0,
+ volmounts integer default 0,
+ volbytes bigint default 0,
+ volparts integer default 0,
+ volerrors integer default 0,
+ volwrites integer default 0,
+ volcapacitybytes bigint default 0,
+ volstatus text not null
+ check (volstatus in ('Full','Archive','Append',
+ 'Recycle','Purged','Read-Only','Disabled',
+ 'Error','Busy','Used','Cleaning','Scratch')),
+ enabled smallint default 1,
+ recycle smallint default 0,
+ ActionOnPurge smallint default 0,
+ volretention bigint default 0,
+ voluseduration bigint default 0,
+ maxvoljobs integer default 0,
+ maxvolfiles integer default 0,
+ maxvolbytes bigint default 0,
+ inchanger smallint default 0,
+ StorageId integer default 0,
+ DeviceId integer default 0,
+ mediaaddressing smallint default 0,
+ volreadtime bigint default 0,
+ volwritetime bigint default 0,
+ endfile integer default 0,
+ endblock bigint default 0,
+ LocationId integer default 0,
+ recyclecount integer default 0,
+ initialwrite timestamp without time zone,
+ scratchpoolid integer default 0,
+ recyclepoolid integer default 0,
+ comment text,
+ primary key (mediaid)
+);
+
+create unique index media_volumename_id on media (volumename);
+
+
+CREATE SEQUENCE MediaType_seq;
+CREATE TABLE MediaType (
+ MediaTypeId INTEGER DEFAULT MediaType_seq.NEXTVAL,
+ MediaType TEXT NOT NULL,
+ ReadOnly INTEGER DEFAULT 0,
+ PRIMARY KEY(MediaTypeId)
+ );
+
+CREATE SEQUENCE Storage_seq;
+CREATE TABLE Storage (
+ StorageId INTEGER DEFAULT Storage_seq.NEXTVAL,
+ Name TEXT NOT NULL,
+ AutoChanger INTEGER DEFAULT 0,
+ PRIMARY KEY(StorageId)
+ );
+
+CREATE SEQUENCE Device_seq;
+CREATE TABLE Device (
+ DeviceId INTEGER DEFAULT Device_seq.NEXTVAL,
+ Name TEXT NOT NULL,
+ MediaTypeId INTEGER NOT NULL,
+ StorageId INTEGER NOT NULL,
+ DevMounts INTEGER NOT NULL DEFAULT 0,
+ DevReadBytes BIGINT NOT NULL DEFAULT 0,
+ DevWriteBytes BIGINT NOT NULL DEFAULT 0,
+ DevReadBytesSinceCleaning BIGINT NOT NULL DEFAULT 0,
+ DevWriteBytesSinceCleaning BIGINT NOT NULL DEFAULT 0,
+ DevReadTime BIGINT NOT NULL DEFAULT 0,
+ DevWriteTime BIGINT NOT NULL DEFAULT 0,
+ DevReadTimeSinceCleaning BIGINT NOT NULL DEFAULT 0,
+ DevWriteTimeSinceCleaning BIGINT NOT NULL DEFAULT 0,
+ CleaningDate timestamp without time zone,
+ CleaningPeriod BIGINT NOT NULL DEFAULT 0,
+ PRIMARY KEY(DeviceId)
+ );
+
+
+CREATE SEQUENCE pool_seq;
+CREATE TABLE pool
+(
+ poolid integer not null default pool_seq.nextval,
+ name text not null,
+ numvols integer default 0,
+ maxvols integer default 0,
+ useonce smallint default 0,
+ usecatalog smallint default 0,
+ acceptanyvolume smallint default 0,
+ volretention bigint default 0,
+ voluseduration bigint default 0,
+ maxvoljobs integer default 0,
+ maxvolfiles integer default 0,
+ maxvolbytes bigint default 0,
+ autoprune smallint default 0,
+ recycle smallint default 0,
+ ActionOnPurge smallint default 0,
+ pooltype text
+ check (pooltype in ('Backup','Copy','Cloned','Archive','Migration','Scratch')),
+ labeltype integer default 0,
+ labelformat text not null,
+ enabled smallint default 1,
+ scratchpoolid integer default 0,
+ recyclepoolid integer default 0,
+ NextPoolId integer default 0,
+ MigrationHighBytes BIGINT DEFAULT 0,
+ MigrationLowBytes BIGINT DEFAULT 0,
+ MigrationTime BIGINT DEFAULT 0,
+ primary key (poolid)
+);
+
+CREATE INDEX pool_name_idx on pool (name);
+
+CREATE SEQUENCE client_seq;
+CREATE TABLE client
+(
+ clientid integer not null default client_seq.nextval,
+ name text not null,
+ uname text not null,
+ autoprune smallint default 0,
+ fileretention bigint default 0,
+ jobretention bigint default 0,
+ primary key (clientid)
+);
+
+create unique index client_name_idx on client (name);
+
+CREATE SEQUENCE Log_seq;
+CREATE TABLE Log
+(
+ LogId integer not null default Log_seq.nextval,
+ JobId integer not null,
+ Time timestamp without time zone,
+ LogText text not null,
+ primary key (LogId)
+);
+create index log_name_idx on Log (JobId);
+
+CREATE SEQUENCE LocationLog_seq;
+CREATE TABLE LocationLog (
+ LocLogId INTEGER NOT NULL DEFAULT LocationLog_seq.NEXTVAL,
+ Date timestamp without time zone,
+ Comment TEXT NOT NULL,
+ MediaId INTEGER DEFAULT 0,
+ LocationId INTEGER DEFAULT 0,
+ newvolstatus text not null
+ check (newvolstatus in ('Full','Archive','Append',
+ 'Recycle','Purged','Read-Only','Disabled',
+ 'Error','Busy','Used','Cleaning','Scratch')),
+ newenabled smallint,
+ PRIMARY KEY(LocLogId)
+);
+
+
+
+CREATE TABLE counters
+(
+ counter text not null,
+ minvalue integer default 0,
+ maxvalue integer default 0,
+ currentvalue integer default 0,
+ wrapcounter text not null,
+ primary key (counter)
+);
+
+
+
+CREATE SEQUENCE basefiles_seq;
+CREATE TABLE basefiles
+(
+ baseid integer not null default basefiles_seq.nextval,
+ jobid integer not null,
+ fileid bigint not null,
+ fileindex integer ,
+ basejobid integer ,
+ primary key (baseid)
+);
+
+CREATE TABLE unsavedfiles
+(
+ UnsavedId integer not null,
+ jobid integer not null,
+ pathid integer not null,
+ filenameid integer not null,
+ primary key (UnsavedId)
+);
+
+CREATE TABLE CDImages
+(
+ MediaId integer not null,
+ LastBurn timestamp without time zone not null,
+ primary key (MediaId)
+);
+
+
+CREATE TABLE version
+(
+ versionid integer not null
+);
+
+CREATE TABLE Status (
+ JobStatus CHAR(1) NOT NULL,
+ JobStatusLong TEXT,
+ PRIMARY KEY (JobStatus)
+ );
+
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('C', 'Created, not yet running');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('R', 'Running');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('B', 'Blocked');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('T', 'Completed successfully');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('E', 'Terminated with errors');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('e', 'Non-fatal error');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('f', 'Fatal error');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('D', 'Verify found differences');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('A', 'Canceled by user');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('F', 'Waiting for Client');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('S', 'Waiting for Storage daemon');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('m', 'Waiting for new media');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('M', 'Waiting for media mount');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('s', 'Waiting for storage resource');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('j', 'Waiting for job resource');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('c', 'Waiting for client resource');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('d', 'Waiting on maximum jobs');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('t', 'Waiting on start time');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('p', 'Waiting on higher priority jobs');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('a', 'SD despooling attributes');
+INSERT INTO Status (JobStatus,JobStatusLong) VALUES
+ ('i', 'Doing batch insert file records');
+
+INSERT INTO Version (VersionId) VALUES (11);
+
+-- Make sure we have appropriate permissions
+\g
+
+END-OF-DATA
+pstat=$?
+if test $pstat = 0;
+then
+ echo "Creation of Bacula Ingres tables succeeded."
+else
+ echo "Creation of Bacula Ingres tables failed."
+fi
+exit $pstat
--- /dev/null
+# include "/opt/Ingres/IngresII/ingres/files/eqdefc.h"
+# include "/opt/Ingres/IngresII/ingres/files/eqsqlca.h"
+ extern IISQLCA sqlca; /* SQL Communications Area */
+# include "/opt/Ingres/IngresII/ingres/files/eqsqlda.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "myingres.h"
+#define INGRES_DEBUG 0
+#define DEBB(x) if (INGRES_DEBUG >= x) {
+#define DEBE }
+/* ---Implementations--- */
+int INGcheck()
+{
+ char errbuf[256];
+ if (sqlca.sqlcode < 0)
+ {
+/* # line 23 "myingres.sc" */ /* inquire_ingres */
+ {
+ IILQisInqSqlio((short *)0,1,32,255,errbuf,63);
+ }
+/* # line 24 "myingres.sc" */ /* host code */
+ printf("Ingres-DBMS-Fehler: %s\n", errbuf);
+ return sqlca.sqlcode;
+ }
+ else
+ return 0;
+}
+short INGgetCols(const char *stmt)
+{
+ short number = 1;
+ IISQLDA *sqlda;
+ sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
+ if (sqlda == (IISQLDA *)0)
+ { printf("Failure allocating %d SQLDA elements\n",number); }
+ sqlda->sqln = number;
+ char stmt_buffer[2000];
+ strcpy(stmt_buffer,stmt);
+/* # line 46 "myingres.sc" */ /* prepare */
+ {
+ IIsqInit(&sqlca);
+ IIsqPrepare(0,(char *)"s1",(char *)0,0,stmt_buffer);
+ }
+/* # line 47 "myingres.sc" */ /* describe */
+ {
+ IIsqInit(&sqlca);
+ IIsqDescribe(0,(char *)"s1",sqlda,0);
+ }
+/* # line 49 "myingres.sc" */ /* host code */
+ number = sqlda->sqld;
+ free(sqlda);
+ return number;
+}
+IISQLDA *INGgetDescriptor(short numCols, const char *stmt)
+{
+ IISQLDA *sqlda;
+ sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
+ if (sqlda == (IISQLDA *)0)
+ { printf("Failure allocating %d SQLDA elements\n",numCols); }
+ sqlda->sqln = numCols;
+ char stmt_buffer[2000];
+ strcpy(stmt_buffer,stmt);
+/* # line 69 "myingres.sc" */ /* prepare */
+ {
+ IIsqInit(&sqlca);
+ IIsqPrepare(0,(char *)"s2",sqlda,0,stmt_buffer);
+ }
+/* # line 71 "myingres.sc" */ /* host code */
+ int i;
+ for (i=0;i<sqlda->sqld;++i)
+ {
+ sqlda->sqlvar[i].sqldata =
+ (char *)malloc(sqlda->sqlvar[i].sqllen);
+ if (sqlda->sqlvar[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",sqlda->sqlvar[i].sqllen); }
+ sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
+ if (sqlda->sqlvar[i].sqlind == (short *)0)
+ { printf("Failure allocating sqlind\n"); }
+ }
+ return sqlda;
+}
+void INGfreeDescriptor(IISQLDA *sqlda)
+{
+ int i;
+ for ( i = 0 ; i < sqlda->sqld ; ++i )
+ {
+ free(sqlda->sqlvar[i].sqldata);
+ free(sqlda->sqlvar[i].sqlind);
+ }
+ free(sqlda);
+ sqlda = NULL;
+}
+int INGgetTypeSize(IISQLVAR *ingvar)
+{
+ int inglength = 0;
+ switch (ingvar->sqltype)
+ {
+ case IISQ_DTE_TYPE:
+ inglength = 25;
+ break;
+ case IISQ_MNY_TYPE:
+ inglength = 8;
+ break;
+ default:
+ inglength = ingvar->sqllen;
+ }
+ return inglength;
+}
+INGresult *INGgetINGresult(IISQLDA *sqlda)
+{
+ INGresult *result = NULL;
+ result = (INGresult *)calloc(1, sizeof(INGresult));
+ if (result == (INGresult *)0)
+ { printf("Failure allocating INGresult\n"); }
+ result->sqlda = sqlda;
+ result->num_fields = sqlda->sqld;
+ result->num_rows = 0;
+ result->first_row = NULL;
+ result->status = ING_EMPTY_RESULT;
+ result->act_row = NULL;
+ strcpy(result->numrowstring,"");
+ result->fields = (INGRES_FIELD *)calloc(1, sizeof(INGRES_FIELD) * result->num_fields);
+ if (result->fields == (INGRES_FIELD *)0)
+ { printf("Failure allocating %d INGRES_FIELD elements\n",result->num_fields); }
+ DEBB(2)
+ printf("INGgetINGresult, before loop over %d fields\n", result->num_fields);
+ DEBE
+ int i;
+ for (i=0;i<result->num_fields;++i)
+ {
+ memset(result->fields[i].name,'\0',34);
+ strncpy(result->fields[i].name,
+ sqlda->sqlvar[i].sqlname.sqlnamec,
+ sqlda->sqlvar[i].sqlname.sqlnamel);
+ result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
+ result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
+ result->fields[i].flags = (abs(sqlda->sqlvar[i].sqltype)<0) ? 1 : 0;
+ }
+ return result;
+}
+void INGfreeINGresult(INGresult *ing_res)
+{
+ /* TODO: free all rows and fields, then res, not descriptor! */
+ if( ing_res != NULL )
+ {
+ /* use of rows is a nasty workaround til I find the reason,
+ why aggregates like max() don't work
+ */
+ int rows = ing_res->num_rows;
+ ING_ROW *rowtemp;
+ ing_res->act_row = ing_res->first_row;
+ while (ing_res->act_row != NULL && rows > 0)
+ {
+ rowtemp = ing_res->act_row->next;
+ INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
+ ing_res->act_row = rowtemp;
+ --rows;
+ }
+ free(ing_res->fields);
+ }
+ free(ing_res);
+ ing_res = NULL;
+}
+ING_ROW *INGgetRowSpace(INGresult *ing_res)
+{
+ IISQLDA *sqlda = ing_res->sqlda;
+ ING_ROW *row = NULL;
+ IISQLVAR *vars = NULL;
+ row = (ING_ROW *)calloc(1,sizeof(ING_ROW));
+ if (row == (ING_ROW *)0)
+ { printf("Failure allocating ING_ROW\n"); }
+ vars = (IISQLVAR *)calloc(1,sizeof(IISQLVAR) * sqlda->sqld);
+ if (vars == (IISQLVAR *)0)
+ { printf("Failure allocating %d SQLVAR elements\n",sqlda->sqld); }
+ row->sqlvar = vars;
+ row->next = NULL;
+ int i;
+ unsigned short len; /* used for VARCHAR type length */
+ for (i=0;i<sqlda->sqld;++i)
+ {
+ /* make strings out of the data, then the space and assign
+ (why string? at least it seems that way, looking into the sources)
+ */
+ switch (abs(ing_res->fields[i].type))
+ {
+ case IISQ_VCH_TYPE:
+ len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
+ DEBB(2)
+ printf("length of varchar: %d\n", len);
+ DEBE
+ vars[i].sqldata = (char *)malloc(len+1);
+ if (vars[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",len+1); }
+ memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
+ vars[i].sqldata[len] = '\0';
+ break;
+ case IISQ_CHA_TYPE:
+ vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
+ if (vars[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",ing_res->fields[i].max_length); }
+ memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
+ vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
+ break;
+ case IISQ_INT_TYPE:
+ vars[i].sqldata = (char *)malloc(20);
+ memset(vars[i].sqldata,'\0',20);
+ sprintf(vars[i].sqldata,"%d",*(int*)sqlda->sqlvar[i].sqldata);
+ break;
+ }
+ vars[i].sqlind = (short *)malloc(sizeof(short));
+ if (sqlda->sqlvar[i].sqlind == (short *)0)
+ { printf("Failure allocating sqlind\n"); }
+ memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
+ DEBB(2)
+ printf("INGgetRowSpace, Field %d, type %d, length %d, name %s\n",
+ i, sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqllen, ing_res->fields[i].name);
+ DEBE
+ }
+ return row;
+}
+void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
+{
+ int i;
+ if (row == NULL || sqlda == NULL)
+ {
+ printf("INGfreeRowSpace: one argument is NULL!\n");
+ return;
+ }
+ for ( i = 0 ; i < sqlda->sqld ; ++i )
+ {
+ free(row->sqlvar[i].sqldata);
+ free(row->sqlvar[i].sqlind);
+ }
+ free(row->sqlvar);
+ free(row);
+}
+int INGfetchAll(const char *stmt, INGresult *ing_res)
+{
+ int linecount = 0;
+ ING_ROW *row;
+ IISQLDA *desc;
+ char stmt_buffer[2000];
+ strcpy(stmt_buffer,stmt);
+ desc = ing_res->sqlda;
+/* # line 275 "myingres.sc" */ /* host code */
+ INGcheck();
+/* # line 277 "myingres.sc" */ /* open */
+ {
+ IIsqInit(&sqlca);
+ IIcsOpen((char *)"c2",19215,16475);
+ IIwritio(0,(short *)0,1,32,0,(char *)"s2");
+ IIcsQuery((char *)"c2",19215,16475);
+ }
+/* # line 278 "myingres.sc" */ /* host code */
+ INGcheck();
+ /* for (linecount=0;sqlca.sqlcode==0;++linecount) */
+ while(sqlca.sqlcode==0)
+ {
+/* # line 283 "myingres.sc" */ /* fetch */
+ {
+ IIsqInit(&sqlca);
+ if (IIcsRetScroll((char *)"c2",19215,16475,-1,-1) != 0) {
+ IIcsDaGet(0,desc);
+ IIcsERetrieve();
+ } /* IIcsRetrieve */
+ }
+/* # line 284 "myingres.sc" */ /* host code */
+ INGcheck();
+ if (sqlca.sqlcode == 0)
+ {
+ row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
+ /* initialize list when encountered first time */
+ if (ing_res->first_row == 0)
+ {
+ ing_res->first_row = row; /* head of the list */
+ ing_res->first_row->next = NULL;
+ ing_res->act_row = ing_res->first_row;
+ }
+ ing_res->act_row->next = row; /* append row to old act_row */
+ ing_res->act_row = row; /* set row as act_row */
+ row->row_number = linecount;
+ ++linecount;
+ DEBB(2)
+ int i;
+ printf("Row %d ", linecount);
+ for (i=0;i<ing_res->num_fields;++i)
+ { printf("F%d:%s ",i,row->sqlvar[i].sqldata); }
+ printf("\n");
+ DEBE
+ }
+ }
+/* # line 313 "myingres.sc" */ /* close */
+ {
+ IIsqInit(&sqlca);
+ IIcsClose((char *)"c2",19215,16475);
+ }
+/* # line 315 "myingres.sc" */ /* host code */
+ ing_res->status = ING_COMMAND_OK;
+ ing_res->num_rows = linecount;
+ return linecount;
+}
+ING_STATUS INGresultStatus(INGresult *res)
+{
+ if (res == NULL) {return ING_NO_RESULT;}
+ return res->status;
+}
+void INGrowSeek(INGresult *res, int row_number)
+{
+ if (res->act_row->row_number == row_number) { return; }
+ /* TODO: real error handling */
+ if (row_number<0 || row_number>res->num_rows) { return;}
+ ING_ROW *trow = res->first_row;
+ while ( trow->row_number != row_number )
+ { trow = trow->next; }
+ res->act_row = trow;
+ /* note - can be null - if row_number not found, right? */
+}
+char *INGgetvalue(INGresult *res, int row_number, int column_number)
+{
+ if (row_number != res->act_row->row_number)
+ { INGrowSeek(res, row_number); }
+ return res->act_row->sqlvar[column_number].sqldata;
+}
+int INGgetisnull(INGresult *res, int row_number, int column_number)
+{
+ if (row_number != res->act_row->row_number)
+ { INGrowSeek(res, row_number); }
+ return (short)*res->act_row->sqlvar[column_number].sqlind;
+}
+int INGntuples(const INGresult *res)
+{
+ return res->num_rows;
+}
+int INGnfields(const INGresult *res)
+{
+ return res->num_fields;
+}
+char *INGfname(const INGresult *res, int column_number)
+{
+ if ( (column_number > res->num_fields) || (column_number < 0) )
+ { return NULL; }
+ else
+ { return res->fields[column_number].name; }
+}
+short INGftype(const INGresult *res, int column_number)
+{
+ return res->fields[column_number].type;
+}
+INGresult *INGexec(INGconn *conn, const char *query)
+{
+ /* TODO: error handling -> res->status? */
+ IISQLDA *desc = NULL;
+ INGresult *res = NULL;
+ int cols = -1;
+ char stmt[2000];
+ strncpy(stmt,query,strlen(query));
+ stmt[strlen(query)]='\0';
+ DEBB(1)
+ printf("INGexec: query is >>%s<<\n",stmt);
+ DEBE
+ if ((cols = INGgetCols(query)) == 0)
+ {
+ DEBB(1)
+ printf("INGexec: non-select\n");
+ DEBE
+ /* non-select statement - TODO: EXECUTE IMMEDIATE */
+/* # line 400 "myingres.sc" */ /* execute */
+ {
+ IIsqInit(&sqlca);
+ IIsqExImmed(stmt);
+ IIsyncup((char *)0,0);
+ }
+/* # line 401 "myingres.sc" */ /* host code */
+ }
+ else
+ {
+ DEBB(1)
+ printf("INGexec: select\n");
+ DEBE
+ /* select statement */
+ desc = INGgetDescriptor(cols, query);
+ res = INGgetINGresult(desc);
+ INGfetchAll(query, res);
+ }
+ return res;
+}
+void INGclear(INGresult *res)
+{
+ if (res == NULL) { return; }
+ IISQLDA *desc = res->sqlda;
+ INGfreeINGresult(res);
+ INGfreeDescriptor(desc);
+}
+INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
+{
+ if (dbname == NULL || strlen(dbname) == 0)
+ { return NULL; }
+ INGconn *dbconn = (INGconn *)calloc(1,sizeof(INGconn));
+ if (dbconn == (INGconn *)0)
+ { printf("Failure allocating INGconn\n"); }
+ char ingdbname[24];
+ char ingdbuser[32];
+ char ingdbpasw[32];
+ char conn_name[32];
+ int sess_id;
+ strcpy(ingdbname,dbname);
+ if ( user != NULL)
+ {
+ DEBB(1)
+ printf("Connection: with user/passwd\n");
+ DEBE
+ strcpy(ingdbuser,user);
+ if ( passwd != NULL)
+ { strcpy(ingdbpasw,passwd); }
+ else
+ { strcpy(ingdbpasw, ""); }
+/* # line 452 "myingres.sc" */ /* connect */
+ {
+ IIsqInit(&sqlca);
+ IIsqUser(ingdbuser);
+ IIsqConnect(0,ingdbname,(char *)"-dbms_password",ingdbpasw,(char *)0,
+ (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
+ (char *)0, (char *)0, (char *)0, (char *)0);
+ }
+/* # line 456 "myingres.sc" */ /* host code */
+ }
+ else
+ {
+ DEBB(1)
+ printf("Connection: w/ user/passwd\n");
+ DEBE
+/* # line 462 "myingres.sc" */ /* connect */
+ {
+ IIsqInit(&sqlca);
+ IIsqConnect(0,ingdbname,(char *)0, (char *)0, (char *)0, (char *)0,
+ (char *)0, (char *)0, (char *)0, (char *)0, (char *)0, (char *)0,
+ (char *)0, (char *)0, (char *)0);
+ }
+/* # line 463 "myingres.sc" */ /* host code */
+ }
+/* # line 465 "myingres.sc" */ /* inquire_sql */
+ {
+ IILQisInqSqlio((short *)0,1,32,31,conn_name,13);
+ }
+/* # line 466 "myingres.sc" */ /* inquire_sql */
+ {
+ IILQisInqSqlio((short *)0,1,30,sizeof(sess_id),&sess_id,11);
+ }
+/* # line 468 "myingres.sc" */ /* host code */
+ strcpy(dbconn->dbname,ingdbname);
+ strcpy(dbconn->user,ingdbuser);
+ strcpy(dbconn->password,ingdbpasw);
+ strcpy(dbconn->connection_name,conn_name);
+ dbconn->session_id = sess_id;
+ DEBB(1)
+ printf("Connected to '%s' with user/passwd %s/%s, sessID/name %i/%s\n",
+ dbconn->dbname,
+ dbconn->user,
+ dbconn->password,
+ dbconn->session_id,
+ dbconn->connection_name
+ );
+ DEBE
+ return dbconn;
+}
+void INGdisconnectDB(INGconn *dbconn)
+{
+ /* TODO: use of dbconn */
+/* # line 490 "myingres.sc" */ /* disconnect */
+ {
+ IIsqInit(&sqlca);
+ IIsqDisconnect();
+ }
+/* # line 491 "myingres.sc" */ /* host code */
+ free(dbconn);
+}
+char *INGerrorMessage(const INGconn *conn)
+{
+ return NULL;
+}
+char *INGcmdTuples(INGresult *res)
+{
+ return res->numrowstring;
+}
+/* TODO?
+char *INGerrorMessage(const INGconn *conn);
+int INGputCopyEnd(INGconn *conn, const char *errormsg);
+int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
+*/
--- /dev/null
+# include "/opt/Ingres/IngresII/ingres/files/eqdefc.h"
+#ifndef _MYINGRES_SH
+#define _MYINGRES_SH
+# include "/opt/Ingres/IngresII/ingres/files/eqsqlda.h"
+/* ---typedefs--- */
+typedef struct ing_field {
+ char name[34];
+ int max_length;
+ unsigned int type;
+ unsigned int flags; // 1 == not null
+} INGRES_FIELD;
+typedef struct ing_row {
+ IISQLVAR *sqlvar; /* ptr to sqlvar[sqld] for one row */
+ struct ing_row *next;
+ int row_number;
+} ING_ROW;
+typedef enum ing_status {
+ ING_COMMAND_OK,
+ ING_TUPLES_OK,
+ ING_NO_RESULT,
+ ING_NO_ROWS_PROCESSED,
+ ING_EMPTY_RESULT,
+ ING_ERROR
+} ING_STATUS;
+typedef struct ing_varchar {
+ short len;
+ char* value;
+} ING_VARCHAR;
+/* It seems, Bacula needs the complete query result stored in one data structure */
+typedef struct ing_result {
+ IISQLDA *sqlda; /* descriptor */
+ INGRES_FIELD *fields;
+ int num_rows;
+ int num_fields;
+ ING_STATUS status;
+ ING_ROW *first_row;
+ ING_ROW *act_row; /* just for iterating */
+ char numrowstring[10];
+} INGresult;
+typedef struct ing_conn {
+ char dbname[24];
+ char user[32];
+ char password[32];
+ char connection_name[32];
+ int session_id;
+} INGconn;
+/* ---Prototypes--- */
+int INGcheck();
+ING_STATUS INGresultStatus(INGresult *res);
+short INGgetCols(const char *stmt);
+IISQLDA *INGgetDescriptor(short numCols, const char *stmt);
+void INGfreeDescriptor(IISQLDA *sqlda);
+int INGgetTypeSize(IISQLVAR *ingvar);
+INGresult *INGgetINGresult(IISQLDA *sqlda);
+void INGfreeINGresult(INGresult *ing_res);
+ING_ROW *INGgetRowSpace(INGresult *ing_res);
+void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda);
+int INGfetchAll(const char *stmt, INGresult *ing_res);
+void INGrowSeek(INGresult *res, int row_number);
+char *INGgetvalue(INGresult *res, int row_number, int column_number);
+int INGgetisnull(INGresult *res, int row_number, int column_number);
+int INGntuples(const INGresult *res);
+int INGnfields(const INGresult *res);
+char *INGfname(const INGresult *res, int column_number);
+short INGftype(const INGresult *res, int column_number);
+INGresult *INGexec(INGconn *db, const char *query);
+void INGclear(INGresult *res);
+INGconn *INGconnectDB(char *dbname, char *user, char *passwd);
+void INGdisconnectDB(INGconn *dbconn);
+char *INGerrorMessage(const INGconn *conn);
+char *INGcmdTuples(INGresult *res);
+#endif /* _MYINGRES_SH */
--- /dev/null
+EXEC SQL INCLUDE SQLCA;
+EXEC SQL INCLUDE SQLDA;
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "myingres.h"
+
+#define INGRES_DEBUG 0
+#define DEBB(x) if (INGRES_DEBUG >= x) {
+#define DEBE }
+
+/* ---Implementations--- */
+int INGcheck()
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ char errbuf[256];
+ EXEC SQL END DECLARE SECTION;
+
+ if (sqlca.sqlcode < 0)
+ {
+ EXEC SQL INQUIRE_INGRES(:errbuf = ERRORTEXT);
+ printf("Ingres-DBMS-Fehler: %s\n", errbuf);
+ return sqlca.sqlcode;
+ }
+ else
+ return 0;
+}
+
+short INGgetCols(const char *stmt)
+{
+ short number = 1;
+ IISQLDA *sqlda;
+ sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (number * IISQDA_VAR_SIZE));
+ if (sqlda == (IISQLDA *)0)
+ { printf("Failure allocating %d SQLDA elements\n",number); }
+ sqlda->sqln = number;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char stmt_buffer[2000];
+ EXEC SQL END DECLARE SECTION;
+
+ strcpy(stmt_buffer,stmt);
+
+ EXEC SQL PREPARE s1 from :stmt_buffer;
+ EXEC SQL DESCRIBE s1 into :sqlda;
+
+ number = sqlda->sqld;
+ free(sqlda);
+ return number;
+}
+
+IISQLDA *INGgetDescriptor(short numCols, const char *stmt)
+{
+ IISQLDA *sqlda;
+ sqlda = (IISQLDA *)calloc(1,IISQDA_HEAD_SIZE + (numCols * IISQDA_VAR_SIZE));
+ if (sqlda == (IISQLDA *)0)
+ { printf("Failure allocating %d SQLDA elements\n",numCols); }
+
+ sqlda->sqln = numCols;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char stmt_buffer[2000];
+ EXEC SQL END DECLARE SECTION;
+
+ strcpy(stmt_buffer,stmt);
+
+ EXEC SQL PREPARE s2 INTO :sqlda FROM :stmt_buffer;
+
+ int i;
+ for (i=0;i<sqlda->sqld;++i)
+ {
+ sqlda->sqlvar[i].sqldata =
+ (char *)malloc(sqlda->sqlvar[i].sqllen);
+ if (sqlda->sqlvar[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",sqlda->sqlvar[i].sqllen); }
+
+ sqlda->sqlvar[i].sqlind = (short *)malloc(sizeof(short));
+ if (sqlda->sqlvar[i].sqlind == (short *)0)
+ { printf("Failure allocating sqlind\n"); }
+ }
+
+ return sqlda;
+}
+void INGfreeDescriptor(IISQLDA *sqlda)
+{
+ int i;
+ for ( i = 0 ; i < sqlda->sqld ; ++i )
+ {
+ free(sqlda->sqlvar[i].sqldata);
+ free(sqlda->sqlvar[i].sqlind);
+ }
+ free(sqlda);
+ sqlda = NULL;
+}
+
+int INGgetTypeSize(IISQLVAR *ingvar)
+{
+ int inglength = 0;
+
+ switch (ingvar->sqltype)
+ {
+ case IISQ_DTE_TYPE:
+ inglength = 25;
+ break;
+ case IISQ_MNY_TYPE:
+ inglength = 8;
+ break;
+ default:
+ inglength = ingvar->sqllen;
+ }
+
+ return inglength;
+}
+
+INGresult *INGgetINGresult(IISQLDA *sqlda)
+{
+ INGresult *result = NULL;
+
+ result = (INGresult *)calloc(1, sizeof(INGresult));
+ if (result == (INGresult *)0)
+ { printf("Failure allocating INGresult\n"); }
+
+ result->sqlda = sqlda;
+ result->num_fields = sqlda->sqld;
+ result->num_rows = 0;
+ result->first_row = NULL;
+ result->status = ING_EMPTY_RESULT;
+ result->act_row = NULL;
+ strcpy(result->numrowstring,"");
+
+ result->fields = (INGRES_FIELD *)calloc(1, sizeof(INGRES_FIELD) * result->num_fields);
+ if (result->fields == (INGRES_FIELD *)0)
+ { printf("Failure allocating %d INGRES_FIELD elements\n",result->num_fields); }
+
+ DEBB(2)
+ printf("INGgetINGresult, before loop over %d fields\n", result->num_fields);
+ DEBE
+
+ int i;
+ for (i=0;i<result->num_fields;++i)
+ {
+ memset(result->fields[i].name,'\0',34);
+ strncpy(result->fields[i].name,
+ sqlda->sqlvar[i].sqlname.sqlnamec,
+ sqlda->sqlvar[i].sqlname.sqlnamel);
+ result->fields[i].max_length = INGgetTypeSize(&sqlda->sqlvar[i]);
+ result->fields[i].type = abs(sqlda->sqlvar[i].sqltype);
+ result->fields[i].flags = (abs(sqlda->sqlvar[i].sqltype)<0) ? 1 : 0;
+ }
+
+ return result;
+}
+
+void INGfreeINGresult(INGresult *ing_res)
+{
+ /* TODO: free all rows and fields, then res, not descriptor! */
+ if( ing_res != NULL )
+ {
+ /* use of rows is a nasty workaround til I find the reason,
+ why aggregates like max() don't work
+ */
+ int rows = ing_res->num_rows;
+ ING_ROW *rowtemp;
+ ing_res->act_row = ing_res->first_row;
+ while (ing_res->act_row != NULL && rows > 0)
+ {
+ rowtemp = ing_res->act_row->next;
+ INGfreeRowSpace(ing_res->act_row, ing_res->sqlda);
+ ing_res->act_row = rowtemp;
+ --rows;
+ }
+ free(ing_res->fields);
+ }
+ free(ing_res);
+ ing_res = NULL;
+}
+
+ING_ROW *INGgetRowSpace(INGresult *ing_res)
+{
+ IISQLDA *sqlda = ing_res->sqlda;
+ ING_ROW *row = NULL;
+ IISQLVAR *vars = NULL;
+ row = (ING_ROW *)calloc(1,sizeof(ING_ROW));
+ if (row == (ING_ROW *)0)
+ { printf("Failure allocating ING_ROW\n"); }
+
+ vars = (IISQLVAR *)calloc(1,sizeof(IISQLVAR) * sqlda->sqld);
+ if (vars == (IISQLVAR *)0)
+ { printf("Failure allocating %d SQLVAR elements\n",sqlda->sqld); }
+
+ row->sqlvar = vars;
+ row->next = NULL;
+
+ int i;
+ unsigned short len; /* used for VARCHAR type length */
+ for (i=0;i<sqlda->sqld;++i)
+ {
+ /* make strings out of the data, then the space and assign
+ (why string? at least it seems that way, looking into the sources)
+ */
+ switch (abs(ing_res->fields[i].type))
+ {
+ case IISQ_VCH_TYPE:
+ len = ((ING_VARCHAR *)sqlda->sqlvar[i].sqldata)->len;
+ DEBB(2)
+ printf("length of varchar: %d\n", len);
+ DEBE
+ vars[i].sqldata = (char *)malloc(len+1);
+ if (vars[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",len+1); }
+ memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata+2,len);
+ vars[i].sqldata[len] = '\0';
+ break;
+ case IISQ_CHA_TYPE:
+ vars[i].sqldata = (char *)malloc(ing_res->fields[i].max_length+1);
+ if (vars[i].sqldata == (char *)0)
+ { printf("Failure allocating %d bytes for SQLVAR data\n",ing_res->fields[i].max_length); }
+ memcpy(vars[i].sqldata,sqlda->sqlvar[i].sqldata,sqlda->sqlvar[i].sqllen);
+ vars[i].sqldata[ing_res->fields[i].max_length] = '\0';
+ break;
+ case IISQ_INT_TYPE:
+ vars[i].sqldata = (char *)malloc(20);
+ memset(vars[i].sqldata,'\0',20);
+ sprintf(vars[i].sqldata,"%d",*(int*)sqlda->sqlvar[i].sqldata);
+ break;
+ }
+ vars[i].sqlind = (short *)malloc(sizeof(short));
+ if (sqlda->sqlvar[i].sqlind == (short *)0)
+ { printf("Failure allocating sqlind\n"); }
+ memcpy(vars[i].sqlind,sqlda->sqlvar[i].sqlind,sizeof(short));
+ DEBB(2)
+ printf("INGgetRowSpace, Field %d, type %d, length %d, name %s\n",
+ i, sqlda->sqlvar[i].sqltype, sqlda->sqlvar[i].sqllen, ing_res->fields[i].name);
+ DEBE
+ }
+
+ return row;
+}
+
+
+void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda)
+{
+ int i;
+ if (row == NULL || sqlda == NULL)
+ {
+ printf("INGfreeRowSpace: one argument is NULL!\n");
+ return;
+ }
+
+ for ( i = 0 ; i < sqlda->sqld ; ++i )
+ {
+ free(row->sqlvar[i].sqldata);
+ free(row->sqlvar[i].sqlind);
+ }
+ free(row->sqlvar);
+ free(row);
+}
+
+int INGfetchAll(const char *stmt, INGresult *ing_res)
+{
+ int linecount = 0;
+ ING_ROW *row;
+ IISQLDA *desc;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char stmt_buffer[2000];
+ EXEC SQL END DECLARE SECTION;
+
+ strcpy(stmt_buffer,stmt);
+ desc = ing_res->sqlda;
+
+ EXEC SQL DECLARE c2 CURSOR FOR s2;
+ INGcheck();
+
+ EXEC SQL OPEN c2;
+ INGcheck();
+
+ /* for (linecount=0;sqlca.sqlcode==0;++linecount) */
+ while(sqlca.sqlcode==0)
+ {
+ EXEC SQL FETCH c2 USING DESCRIPTOR :desc;
+ INGcheck();
+
+ if (sqlca.sqlcode == 0)
+ {
+ row = INGgetRowSpace(ing_res); /* alloc space for fetched row */
+
+ /* initialize list when encountered first time */
+ if (ing_res->first_row == 0)
+ {
+ ing_res->first_row = row; /* head of the list */
+ ing_res->first_row->next = NULL;
+ ing_res->act_row = ing_res->first_row;
+ }
+ ing_res->act_row->next = row; /* append row to old act_row */
+ ing_res->act_row = row; /* set row as act_row */
+ row->row_number = linecount;
+ ++linecount;
+
+ DEBB(2)
+ int i;
+ printf("Row %d ", linecount);
+ for (i=0;i<ing_res->num_fields;++i)
+ { printf("F%d:%s ",i,row->sqlvar[i].sqldata); }
+ printf("\n");
+ DEBE
+
+ }
+ }
+
+ EXEC SQL CLOSE c2;
+
+ ing_res->status = ING_COMMAND_OK;
+ ing_res->num_rows = linecount;
+ return linecount;
+}
+
+ING_STATUS INGresultStatus(INGresult *res)
+{
+ if (res == NULL) {return ING_NO_RESULT;}
+ return res->status;
+}
+
+void INGrowSeek(INGresult *res, int row_number)
+{
+ if (res->act_row->row_number == row_number) { return; }
+
+ /* TODO: real error handling */
+ if (row_number<0 || row_number>res->num_rows) { return;}
+
+ ING_ROW *trow = res->first_row;
+ while ( trow->row_number != row_number )
+ { trow = trow->next; }
+ res->act_row = trow;
+ /* note - can be null - if row_number not found, right? */
+}
+
+char *INGgetvalue(INGresult *res, int row_number, int column_number)
+{
+ if (row_number != res->act_row->row_number)
+ { INGrowSeek(res, row_number); }
+ return res->act_row->sqlvar[column_number].sqldata;
+}
+
+int INGgetisnull(INGresult *res, int row_number, int column_number)
+{
+ if (row_number != res->act_row->row_number)
+ { INGrowSeek(res, row_number); }
+ return (short)*res->act_row->sqlvar[column_number].sqlind;
+}
+
+int INGntuples(const INGresult *res)
+{
+ return res->num_rows;
+}
+
+int INGnfields(const INGresult *res)
+{
+ return res->num_fields;
+}
+
+char *INGfname(const INGresult *res, int column_number)
+{
+ if ( (column_number > res->num_fields) || (column_number < 0) )
+ { return NULL; }
+ else
+ { return res->fields[column_number].name; }
+}
+
+short INGftype(const INGresult *res, int column_number)
+{
+ return res->fields[column_number].type;
+}
+
+INGresult *INGexec(INGconn *conn, const char *query)
+{
+ /* TODO: error handling -> res->status? */
+ IISQLDA *desc = NULL;
+ INGresult *res = NULL;
+ int cols = -1;
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char stmt[2000];
+ EXEC SQL END DECLARE SECTION;
+ strncpy(stmt,query,strlen(query));
+ stmt[strlen(query)]='\0';
+
+ DEBB(1)
+ printf("INGexec: query is >>%s<<\n",stmt);
+ DEBE
+
+ if ((cols = INGgetCols(query)) == 0)
+ {
+ DEBB(1)
+ printf("INGexec: non-select\n");
+ DEBE
+ /* non-select statement - TODO: EXECUTE IMMEDIATE */
+ EXEC SQL EXECUTE IMMEDIATE :stmt;
+ }
+ else
+ {
+ DEBB(1)
+ printf("INGexec: select\n");
+ DEBE
+ /* select statement */
+ desc = INGgetDescriptor(cols, query);
+ res = INGgetINGresult(desc);
+ INGfetchAll(query, res);
+ }
+ return res;
+}
+
+void INGclear(INGresult *res)
+{
+ if (res == NULL) { return; }
+ IISQLDA *desc = res->sqlda;
+ INGfreeINGresult(res);
+ INGfreeDescriptor(desc);
+}
+
+INGconn *INGconnectDB(char *dbname, char *user, char *passwd)
+{
+ if (dbname == NULL || strlen(dbname) == 0)
+ { return NULL; }
+
+ INGconn *dbconn = (INGconn *)calloc(1,sizeof(INGconn));
+ if (dbconn == (INGconn *)0)
+ { printf("Failure allocating INGconn\n"); }
+
+ EXEC SQL BEGIN DECLARE SECTION;
+ char ingdbname[24];
+ char ingdbuser[32];
+ char ingdbpasw[32];
+ char conn_name[32];
+ int sess_id;
+ EXEC SQL END DECLARE SECTION;
+
+ strcpy(ingdbname,dbname);
+
+ if ( user != NULL)
+ {
+ DEBB(1)
+ printf("Connection: with user/passwd\n");
+ DEBE
+ strcpy(ingdbuser,user);
+ if ( passwd != NULL)
+ { strcpy(ingdbpasw,passwd); }
+ else
+ { strcpy(ingdbpasw, ""); }
+ EXEC SQL CONNECT
+ :ingdbname
+ identified by :ingdbuser
+ dbms_password = :ingdbpasw;
+ }
+ else
+ {
+ DEBB(1)
+ printf("Connection: w/ user/passwd\n");
+ DEBE
+ EXEC SQL CONNECT :ingdbname;
+ }
+
+ EXEC SQL INQUIRE_SQL(:conn_name = connection_name);
+ EXEC SQL INQUIRE_SQL(:sess_id = session);
+
+ strcpy(dbconn->dbname,ingdbname);
+ strcpy(dbconn->user,ingdbuser);
+ strcpy(dbconn->password,ingdbpasw);
+ strcpy(dbconn->connection_name,conn_name);
+ dbconn->session_id = sess_id;
+
+ DEBB(1)
+ printf("Connected to '%s' with user/passwd %s/%s, sessID/name %i/%s\n",
+ dbconn->dbname,
+ dbconn->user,
+ dbconn->password,
+ dbconn->session_id,
+ dbconn->connection_name
+ );
+ DEBE
+
+ return dbconn;
+}
+
+void INGdisconnectDB(INGconn *dbconn)
+{
+ /* TODO: use of dbconn */
+ EXEC SQL DISCONNECT;
+ free(dbconn);
+}
+
+char *INGerrorMessage(const INGconn *conn)
+{
+ return NULL;
+}
+
+char *INGcmdTuples(INGresult *res)
+{
+ return res->numrowstring;
+}
+
+
+/* TODO?
+char *INGerrorMessage(const INGconn *conn);
+int INGputCopyEnd(INGconn *conn, const char *errormsg);
+int INGputCopyData(INGconn *conn, const char *buffer, int nbytes);
+*/
--- /dev/null
+#ifndef _MYINGRES_SH
+#define _MYINGRES_SH
+
+EXEC SQL INCLUDE SQLDA;
+
+/* ---typedefs--- */
+
+typedef struct ing_field {
+ char name[34];
+ int max_length;
+ unsigned int type;
+ unsigned int flags; // 1 == not null
+} INGRES_FIELD;
+
+typedef struct ing_row {
+ IISQLVAR *sqlvar; /* ptr to sqlvar[sqld] for one row */
+ struct ing_row *next;
+ int row_number;
+} ING_ROW;
+
+typedef enum ing_status {
+ ING_COMMAND_OK,
+ ING_TUPLES_OK,
+ ING_NO_RESULT,
+ ING_NO_ROWS_PROCESSED,
+ ING_EMPTY_RESULT,
+ ING_ERROR
+} ING_STATUS;
+
+typedef struct ing_varchar {
+ short len;
+ char* value;
+} ING_VARCHAR;
+
+/* It seems, Bacula needs the complete query result stored in one data structure */
+typedef struct ing_result {
+ IISQLDA *sqlda; /* descriptor */
+ INGRES_FIELD *fields;
+ int num_rows;
+ int num_fields;
+ ING_STATUS status;
+ ING_ROW *first_row;
+ ING_ROW *act_row; /* just for iterating */
+ char numrowstring[10];
+
+} INGresult;
+
+typedef struct ing_conn {
+ char dbname[24];
+ char user[32];
+ char password[32];
+ char connection_name[32];
+ int session_id;
+} INGconn;
+
+
+/* ---Prototypes--- */
+int INGcheck();
+ING_STATUS INGresultStatus(INGresult *res);
+short INGgetCols(const char *stmt);
+IISQLDA *INGgetDescriptor(short numCols, const char *stmt);
+void INGfreeDescriptor(IISQLDA *sqlda);
+int INGgetTypeSize(IISQLVAR *ingvar);
+INGresult *INGgetINGresult(IISQLDA *sqlda);
+void INGfreeINGresult(INGresult *ing_res);
+ING_ROW *INGgetRowSpace(INGresult *ing_res);
+void INGfreeRowSpace(ING_ROW *row, IISQLDA *sqlda);
+int INGfetchAll(const char *stmt, INGresult *ing_res);
+void INGrowSeek(INGresult *res, int row_number);
+char *INGgetvalue(INGresult *res, int row_number, int column_number);
+int INGgetisnull(INGresult *res, int row_number, int column_number);
+int INGntuples(const INGresult *res);
+int INGnfields(const INGresult *res);
+char *INGfname(const INGresult *res, int column_number);
+short INGftype(const INGresult *res, int column_number);
+INGresult *INGexec(INGconn *db, const char *query);
+void INGclear(INGresult *res);
+INGconn *INGconnectDB(char *dbname, char *user, char *passwd);
+void INGdisconnectDB(INGconn *dbconn);
+char *INGerrorMessage(const INGconn *conn);
+char *INGcmdTuples(INGresult *res);
+
+#endif /* _MYINGRES_SH */
*
* Kern Sibbald, March 2000
*
- * Version $Id$
+ * Version $Id: sql.c 8034 2008-11-11 14:33:46Z ricozz $
*/
/* The following is necessary so that we do not include
#include "bacula.h"
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
uint32_t bacula_db_version = 0;
db_type = SQL_TYPE_MYSQL;
#elif HAVE_POSTGRESQL
db_type = SQL_TYPE_POSTGRESQL;
+#elif HAVE_INGRES
+ db_type = SQL_TYPE_INGRES;
#elif HAVE_SQLITE
db_type = SQL_TYPE_SQLITE;
#elif HAVE_SQLITE3
db_unlock(mdb);
#endif
+#ifdef HAVE_INGRES
+ if (!mdb->allow_transactions) {
+ return;
+ }
+ db_lock(mdb);
+ /* Allow only 25,000 changes per transaction */
+ if (mdb->transaction && mdb->changes > 25000) {
+ db_end_transaction(jcr, mdb);
+ }
+ if (!mdb->transaction) {
+ db_sql_query(mdb, "BEGIN", NULL, NULL); /* begin transaction */
+ Dmsg0(400, "Start Ingres transaction\n");
+ mdb->transaction = 1;
+ }
+ db_unlock(mdb);
+#endif
+
#ifdef HAVE_DBI
if (db_type == SQL_TYPE_SQLITE) {
if (!mdb->allow_transactions) {
db_unlock(mdb);
#endif
+
+
+#ifdef HAVE_INGRES
+ if (!mdb->allow_transactions) {
+ return;
+ }
+ db_lock(mdb);
+ if (mdb->transaction) {
+ db_sql_query(mdb, "COMMIT", NULL, NULL); /* end transaction */
+ mdb->transaction = 0;
+ Dmsg1(400, "End Ingres transaction changes=%d\n", mdb->changes);
+ }
+ mdb->changes = 0;
+ db_unlock(mdb);
+#endif
+
+
#ifdef HAVE_POSTGRESQL
if (!mdb->allow_transactions) {
return;
}
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES*/
*
* Kern Sibbald, March 2000
*
- * Version $Id$
+ * Version $Id: sql_create.c 8407 2009-01-28 10:47:21Z ricozz $
*/
/* The following is necessary so that we do not include
static const int dbglevel = 100;
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
return ret;
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */
*
* Kern Sibbald, December 2000
*
- * Version $Id$
+ * Version $Id: sql_delete.c 7380 2008-07-14 10:42:59Z kerns $
*/
/*
Bacula® - The Network Backup Solution
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
* Generic Routines (or almost generic)
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES */
*
* Kern Sibbald, December 2000
*
- * Version $Id$
+ * Version $Id: sql_find.c 8508 2009-03-07 20:59:46Z kerns $
*/
#include "bacula.h"
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
*
* Kern Sibbald, March 2000
*
- * Version $Id: sql_get.c 8918 2009-06-23 11:56:35Z ricozz $
*/
#include "bacula.h"
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
return ret;
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI */
*
* Kern Sibbald, March 2000
*
- * Version $Id$
+ * Version $Id: sql_list.c 8508 2009-03-07 20:59:46Z kerns $
*/
extern int db_type;
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES */
*
* Kern Sibbald, March 2000
*
- * Version $Id$
+ * Version $Id: sql_update.c 8478 2009-02-18 20:11:55Z kerns $
*/
/* The following is necessary so that we do not include
#include "bacula.h"
#include "cats.h"
-#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI
+#if HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES || HAVE_DBI
/* -----------------------------------------------------------------------
*
}
}
-#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL*/
+#endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_INGRES */
#!/bin/sh
#
# This routine alters the appropriately configured
-# Bacula tables for PostgreSQL, MySQL, or SQLite.
+# Bacula tables for PostgreSQL, Ingres, MySQL, or SQLite.
#
if test xsqlite3 = x@DB_TYPE@ ; then
echo "Altering SQLite tables"
echo "Altering MySQL tables"
@scriptdir@/update_mysql_tables $*
fi
+if test xingres = x@DB_TYPE@ ; then
+ echo "Altering Ingres tables"
+ @scriptdir@/update_ingres_tables $*
+fi
if test xpostgresql = x@DB_TYPE@ ; then
echo "Altering PostgreSQL tables"
@scriptdir@/update_postgresql_tables $*
--- /dev/null
+#!/bin/sh
+#
+# Shell script to update Ingres tables (without any function for now)
+#
+echo " "
+echo "This script will update a Bacula Ingres database (if needed)"
+echo " "
+bindir=@SQL_BINDIR@
+db_name=@db_name@
+
+echo "Update of Bacula Ingres tables succeeded. (nothing to do)"
+exit 0