/*------------------------------------------------------------------------- * Copyright (c) 1999-2004 Kenneth W. Sodemann (stuffle@mac.com) *------------------------------------------------------------------------- * db_utils * * $Id: db_utils.c,v 1.16 2004/11/25 23:44:07 stuffle Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * 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 * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * *------------------------------------------------------------------------- */ #ifdef HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include "db_utils.h" #include "defs.h" #include "error_chks.h" #define DEF_DB_NAME "myprs" #define DEF_HOST "localhost" #define DEF_PORT "5432" #define USER_STR "user='" #define PASSWORD_STR "password='" #define DATABASE_STR "dbname='" #define HOST_STR "host='" #define PORT_STR "port='" #define END_STR "' " /* * get_db_access_lvl * * Determine the access that the current user has. */ gint get_db_access_lvl (PGconn *conn) { PGresult *res; gint rtn; res = PQexec (conn, "select access_flag from person where login_id = getpgusername()"); if (!chk_sql_error (res, "Getting user access info.")) { g_assert_not_reached (); } if (PQntuples (res) == 0) { return -1; } g_assert (PQntuples (res) == 1); rtn = atoi (PQgetvalue (res, 0, 0)); PQclear (res); /* * If we got anything other than 0 or 1, the data in the database is * not valid. Don't let invalid data mess this up. Just return a * zero or a one... */ return ((rtn == 1) ? 1 : 0); } /* * destroy_db_name_list * * Destroy the db_name_list of the passed in DbLoginData structure. */ static void destroy_db_name_list (DbLoginData *data) { GList *list_iter = NULL; /* * Only bother to do something if there is a list. */ if (data->db_name_list) { for (list_iter = g_list_first (data->db_name_list); list_iter != NULL; list_iter = list_iter->next) { g_free (list_iter->data); } g_list_free (data->db_name_list); } } /* * get_db_names * * Creates a GList of the known database names. * * The caller should g_free each item in this list before * disposing of the list itself. */ static GList* get_db_names (GConfClient *client) { GList *tmp_list = NULL; GString *config_str = g_string_new (""); gchar *tmp_name; gint num, i; GError *error = NULL; g_string_printf (config_str, "%s/%s/%s", BASE_KEY, DBINFO_SEC, COUNT); num = gconf_client_get_int (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; num = 0; } for (i = 0; i < num; i++) { g_string_printf (config_str, DB_NAME_KEY, BASE_KEY, DBINFO_SEC, i); tmp_name = gconf_client_get_string (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; } if (tmp_name == NULL || tmp_name[0] == '\000') { syslog (LOG_ERR, "Missing name for database %d", i); if (tmp_name != NULL) { g_free (tmp_name); } } else { /* * This will be free'ed when the list is destroyed... */ tmp_list = g_list_append (tmp_list, tmp_name); } } g_string_free (config_str, TRUE); return tmp_list; } /* * get_def_username * * Get the default user name for this database. NULL if there is * not one defined. * * This function will either g_string_new a new string, or return * NULL. It is the caller's responsibility to g_string_free the * new string. */ static GString* get_def_username (GConfClient *client, const gchar *db_name) { GString *rtn_str = NULL; GString *config_str; gchar *tmp_ptr; GError *error = NULL; config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_name, DB_USERNAME); tmp_ptr = gconf_client_get_string (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; } if (tmp_ptr != NULL && tmp_ptr[0] != '\000') { rtn_str = g_string_new (tmp_ptr); } g_string_free (config_str, TRUE); if (tmp_ptr != NULL) { g_free (tmp_ptr); } return rtn_str; } /* * get_def_host * * Get the default host for this database. * * This function will g_string_new a new string. It is the caller's * responsibility to g_string_free the new string. */ static GString* get_def_host (GConfClient *client, const gchar *db_name) { GString *rtn_str = NULL; GString *config_str; gchar *tmp_ptr; GError *error = NULL; config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_name, DB_HOST); tmp_ptr = gconf_client_get_string (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; } if (tmp_ptr != NULL && tmp_ptr[0] != '\000') { rtn_str = g_string_new (tmp_ptr); } g_string_free (config_str, TRUE); if (tmp_ptr != NULL) { g_free (tmp_ptr); } return rtn_str; } /* * get_def_port * * Get the default port for this database. * * This function will g_string_new a new string (or NULL). It is the * caller's responsibility to g_string_free the new string. */ static GString* get_def_port (GConfClient *client, const gchar *db_name) { GString *rtn_str = NULL; GString *config_str; gchar *tmp_ptr; GError *error = NULL; config_str = g_string_new (""); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_name, DB_PORT); tmp_ptr = gconf_client_get_string (client, config_str->str, &error); if (error != NULL) { g_warning (error->message); g_error_free (error); error = NULL; } if (tmp_ptr != NULL && tmp_ptr[0] != '\000') { rtn_str = g_string_new (tmp_ptr); } g_string_free (config_str, TRUE); if (tmp_ptr != NULL) { g_free (tmp_ptr); } return rtn_str; } void init_db_data (GConfClient *client, DbLoginData *db_data) { /* * First null them all out so the "clear" functions (called by the * "set" functions) know we are empty. */ db_data->db_name_list = get_db_names (client); db_data->username = NULL; db_data->password = NULL; db_data->db_name = NULL; db_data->host = NULL; db_data->port = NULL; if (db_data->db_name_list) { set_db_name (client, db_data, g_list_first (db_data->db_name_list)->data, TRUE); } else { set_db_name (client, db_data, DEF_DB_NAME, TRUE); } } void commit_db_data (GConfClient *client, const DbLoginData *db_data) { GList *list_iter; GString *config_str; gint db_count; /* * This function should only be called if we are connected * to a database. Therefore, a valid database name should * exist. */ assert (db_data->db_name); /* * Write of the information for the current database. Put the * database name in as "name0", and completely update the section * for this database. */ config_str = g_string_new (""); g_string_printf (config_str, DB_NAME_KEY, BASE_KEY, DBINFO_SEC, 0); gconf_client_set_string (client, config_str->str, db_data->db_name->str, NULL); g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_data->db_name->str, DB_USERNAME); if (db_data->username) { gconf_client_set_string (client, config_str->str, db_data->username->str, NULL); } else { gconf_client_unset (client, config_str->str, NULL); } g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_data->db_name->str, DB_HOST); if (db_data->host) { gconf_client_set_string (client, config_str->str, db_data->host->str, NULL); } else { gconf_client_unset (client, config_str->str, NULL); } g_string_printf (config_str, "%s/%s/%s/%s", BASE_KEY, DBINFO_SEC, db_data->db_name->str, DB_PORT); if (db_data->port) { gconf_client_set_string (client, config_str->str, db_data->port->str, NULL); } else { gconf_client_unset (client, config_str->str, NULL); } /* * Write out the rest of the valid database names that we know * of. Keep track of how many so we can output the count. * Remember that we already have one written out. Do not * write that one out a second time. */ db_count = 1; for (list_iter = g_list_first (db_data->db_name_list); list_iter != NULL; list_iter = list_iter->next) { if (strcmp (list_iter->data, db_data->db_name->str) != 0) { g_string_printf (config_str, DB_NAME_KEY, BASE_KEY, DBINFO_SEC, db_count); gconf_client_set_string (client, config_str->str, list_iter->data, NULL); db_count++; } } g_string_printf (config_str, "%s/%s/%s", BASE_KEY, DBINFO_SEC, COUNT); gconf_client_set_int (client, config_str->str, db_count, NULL); /* * Clean up. */ g_string_free (config_str, TRUE); } void set_db_username (DbLoginData *db_data, const char *username) { clear_db_username (db_data); if (username && (strlen (username) > 0)) { db_data->username = g_string_new (username); } } void set_db_password (DbLoginData *db_data, const char *password) { clear_db_password (db_data); if (password && (strlen (password) > 0)) { db_data->password = g_string_new (password); } } void set_db_name (GConfClient *client, DbLoginData *db_data, const char *db_name, gboolean default_others) { GString *new_str; /* store the new info here so we can free the old information before the assignment. */ clear_db_name (db_data); if (db_name && (strlen (db_name) > 0)) { db_data->db_name = g_string_new (db_name); /* * If we are supposed to default the other data based on * the username, do it. */ if (default_others) { new_str = get_def_username (client, db_name); clear_db_username (db_data); db_data->username = new_str; new_str = get_def_host (client, db_name); clear_db_host (db_data); db_data->host = new_str; new_str = get_def_port (client, db_name); clear_db_port (db_data); db_data->port = new_str; } } } void set_db_host (DbLoginData *db_data, const char *host) { clear_db_host (db_data); if (host && (strlen (host) > 0)) { db_data->host = g_string_new (host); } } void set_db_port (DbLoginData *db_data, const char *port) { clear_db_port (db_data); if (port && (strlen (port) > 0)) { db_data->port = g_string_new (port); } } void clear_db_username (DbLoginData *db_data) { if (db_data->username) { g_string_free (db_data->username, TRUE); db_data->username = NULL; } } void clear_db_password (DbLoginData *db_data) { if (db_data->password) { g_string_free (db_data->password, TRUE); db_data->password = NULL; } } void clear_db_name (DbLoginData *db_data) { if (db_data->db_name) { g_string_free (db_data->db_name, TRUE); db_data->db_name = NULL; } } void clear_db_host (DbLoginData *db_data) { if (db_data->host) { g_string_free (db_data->host, TRUE); db_data->host = NULL; } } void clear_db_port (DbLoginData *db_data) { if (db_data->port) { g_string_free (db_data->port, TRUE); db_data->port = NULL; } } void clear_db_data (DbLoginData *db_data) { clear_db_username (db_data); clear_db_password (db_data); clear_db_name (db_data); clear_db_host (db_data); clear_db_port (db_data); destroy_db_name_list (db_data); } PGconn * db_login (const DbLoginData* db_data) { PGconn *conn; GString *conn_str; /* * Build the connect string. * Only add the items that were not NULL. */ conn_str = g_string_new (""); if (db_data->username) { conn_str = g_string_append (conn_str, USER_STR); conn_str = g_string_append (conn_str, db_data->username->str); conn_str = g_string_append (conn_str, END_STR); } if (db_data->password) { conn_str = g_string_append (conn_str, PASSWORD_STR); conn_str = g_string_append (conn_str, db_data->password->str); conn_str = g_string_append (conn_str, END_STR); } if (db_data->db_name) { conn_str = g_string_append (conn_str, DATABASE_STR); conn_str = g_string_append (conn_str, db_data->db_name->str); conn_str = g_string_append (conn_str, END_STR); } if (db_data->host) { conn_str = g_string_append (conn_str, HOST_STR); conn_str = g_string_append (conn_str, db_data->host->str); conn_str = g_string_append (conn_str, END_STR); } if (db_data->port) { conn_str = g_string_append (conn_str, PORT_STR); conn_str = g_string_append (conn_str, db_data->port->str); conn_str = g_string_append (conn_str, END_STR); } conn = PQconnectdb (conn_str->str); g_string_free (conn_str, TRUE); return conn; } void db_shutdown (PGconn *conn) { PQfinish (conn); return; } const char *db_stat_string (ExecStatusType stat) { switch (stat) { case PGRES_EMPTY_QUERY: return "Empty Query"; case PGRES_COMMAND_OK: return "Command OK"; case PGRES_TUPLES_OK: return "Tuples OK"; case PGRES_COPY_OUT: return "Copy Out"; case PGRES_COPY_IN: return "Copy In"; case PGRES_BAD_RESPONSE: return "Bad Response"; case PGRES_NONFATAL_ERROR: return "Nonfatal Error"; case PGRES_FATAL_ERROR: return "Fatal Error"; default: return "Unknown Error"; } } gboolean finalize_transaction (PGconn *conn, PGresult *res) { gboolean sql_ok; sql_ok = sql_result_ok (res); if (sql_ok) { COMMIT (conn); } else { ROLLBACK (conn); } return sql_ok; }