This repository has been archived on 2024-07-15. You can view files and clone it, but cannot push or open issues or pull requests.
hedera/db/db-conn.c

1082 lines
24 KiB
C

/*
* Copyright (C) 2012 - Juan Ferrer Toribio
*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include "db-conn.h"
#include <glib/gstdio.h>
#include <gmodule.h>
#define IS_OPEN(obj) (obj->status & DB_CONN_OPEN)
#define IS_CLOSING(obj) (obj->status & DB_CONN_CLOSING)
#define IS_OPENING(obj) (obj->status & DB_CONN_OPENING)
#define IS_TRANSACTION(obj) (obj->status & DB_CONN_TRANSACTION)
#define IS_LOST(obj) (obj->status & DB_CONN_LOST)
typedef struct
{
DbConn * obj;
gpointer data;
}
IdleData;
enum {
STATUS_CHANGED
,ERROR
,LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = {0};
/**
* SECTION: db-conn
* @Short_description: connection managing and wrapping class.
* @Title: DbConn
* @See_also: #DbPg
*
* This class manages a connection to any kind of database (as long as it has
* a plugin to acces to it). It uses the plugin set on the configuration
* parameters (not yet implemented) to connect, query and disconnect.
*
* To do this use the methods db_conn_open(), db_conn_query() and
* db_conn_close() respectively.
*
* It is also possible to parse a SQL query and get an #SqlStmt object using the
* db_conn_parse() method.
*
* This class is thread safe.
**/
G_DEFINE_TYPE (DbConn, db_conn, G_TYPE_OBJECT);
/**
* db_conn_new:
*
* Creates a new connection.
*
* Return value: the #DbConn
**/
DbConn * db_conn_new ()
{
return g_object_new (DB_TYPE_CONN, NULL);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Private
/*
* Frees the #IdleData struct.
*/
static void idle_data_free (IdleData * idle_data)
{
g_object_unref (idle_data->obj);
g_free (idle_data);
}
/*
* Notifies that an error happened.
*/
static gboolean db_conn_idle_error (IdleData * idle_data)
{
GError * error = idle_data->data;
g_signal_emit (idle_data->obj, signals[ERROR], 0, error);
g_error_free (error);
return G_SOURCE_REMOVE;
}
/*
* Sets and error.
*/
static void db_conn_set_error (DbConn * obj, const GError * error)
{
if (error)
{
IdleData * idle_data = g_new (IdleData, 1);
idle_data->obj = g_object_ref (obj);
idle_data->data = g_error_copy (error);
g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) db_conn_idle_error, idle_data, (GDestroyNotify) idle_data_free);
}
}
/*
* Notifies that connection status has changed.
*/
static gboolean db_conn_idle_status (IdleData * idle_data)
{
DbConnStatus status = GPOINTER_TO_INT (idle_data->data);
g_signal_emit (idle_data->obj, signals[STATUS_CHANGED], 0, status);
return G_SOURCE_REMOVE;
}
/*
* Sets the status of the connection.
*/
static void db_conn_set_status (DbConn * obj, DbConnStatus status)
{
IdleData * idle_data;
if (obj->status != status)
{
idle_data = g_new (IdleData, 1);
idle_data->obj = g_object_ref (obj);
idle_data->data = GINT_TO_POINTER (status);
g_idle_add_full (G_PRIORITY_DEFAULT,
(GSourceFunc) db_conn_idle_status, idle_data, (GDestroyNotify) idle_data_free);
obj->status = status;
}
}
/*
* Cancels all outstanding requests.
*/
static void db_conn_cancel_requests (DbConn * obj)
{
DbRequest * request;
while ((request = g_queue_pop_head (obj->requests)))
{
db_request_cancel (request);
db_request_complete (request);
}
db_plugin_kill_query (obj->plugin);
}
/*
* Executes asynchronous requests.
*/
static void db_conn_thread (DbConn * obj)
{
gboolean exit = FALSE;
gboolean exec_success;
DbRequest * request;
g_mutex_lock (obj->mutex);
while (!exit)
{
if (IS_OPEN (obj) && !IS_TRANSACTION (obj))
{
db_conn_set_status (obj, obj->status | DB_CONN_LOADING);
while (TRUE)
{
if (!(request = g_queue_pop_head (obj->requests)))
break;
g_mutex_unlock (obj->mutex);
exec_success = db_request_exec (request, NULL);
g_mutex_lock (obj->mutex);
if (!exec_success && IS_LOST (obj))
{
g_queue_push_head (obj->requests, request);
}
else
{
db_request_complete (request);
g_object_unref (request);
}
if (IS_LOST (obj))
break;
}
db_conn_set_status (obj, obj->status & ~DB_CONN_LOADING);
}
if (!IS_CLOSING (obj))
g_cond_wait (obj->thread_cond, obj->mutex);
else
exit = TRUE;
}
g_mutex_unlock (obj->mutex);
}
/*
* Adds a request to the queue.
*/
static void db_conn_add_request (DbConn * obj, DbRequest * request)
{
g_mutex_lock (obj->mutex);
if ((IS_OPEN (obj) || IS_LOST (obj)) && !IS_CLOSING (obj))
{
g_queue_push_tail (obj->requests, g_object_ref (request));
if (!IS_TRANSACTION (obj))
g_cond_signal (obj->thread_cond);
}
else
{
db_request_cancel (request);
db_request_complete (request);
}
g_mutex_unlock (obj->mutex);
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Public
/**
* db_conn_load_plugin:
* @obj: a #DbConn
* @plugin: the plugin name
* @err: return address of a #GError or #NULL
*
* Tries to load a plugin.
*
* Return vale: %TRUE if plugin was loaded successfully, %FALSE ortherwise
**/
gboolean db_conn_load_plugin (DbConn * obj, const gchar * plugin, GError ** err)
{
gchar * aux;
gchar * path;
gchar * plugin_name;
GModule * module;
DbPluginGetTypeFunc symbol;
gboolean ret = FALSE;
g_return_val_if_fail (DB_IS_CONN (obj), FALSE);
g_return_val_if_fail (plugin, FALSE);
g_mutex_lock (obj->mutex);
if (!obj->plugin)
{
aux = g_strdup_printf (_PLUGIN_DIR, plugin);
plugin_name = g_strdup_printf ("db%s", plugin);
path = g_module_build_path (aux, plugin_name);
g_free (aux);
if ((module = g_module_open (path, 0)))
g_module_make_resident (module);
aux = g_strdup_printf ("db_%s_get_type", plugin);
if (module && g_module_symbol (module, aux, (gpointer) &symbol))
{
obj->plugin_name = g_strdup (plugin);
obj->plugin = g_object_new (symbol (), NULL);
ret = TRUE;
}
else if (err)
g_set_error (err
,DB_CONN_LOG_DOMAIN
,DB_CONN_ERROR_PLUGIN
,_("Can't load DbPlugin '%s': %s")
,plugin
,g_module_error ()
);
else
g_warning (_("Can't load DbPlugin '%s': %s")
,plugin
,g_module_error ()
);
g_free (plugin_name);
g_free (path);
g_free (aux);
}
else if (err)
g_set_error (err
,DB_CONN_LOG_DOMAIN
,DB_CONN_ERROR_PLUGIN
,_("Plugin can't be loaded")
);
g_mutex_unlock (obj->mutex);
return ret;
}
/**
* db_conn_set_query_path:
* @obj: a #DbConn
* @path: the path
*
* Sets the query search path.
**/
void db_conn_set_query_path (DbConn * obj, const gchar * path)
{
g_return_if_fail (DB_IS_CONN (obj));
g_mutex_lock (obj->settings_mutex);
g_free (obj->query_path);
g_strfreev (obj->query_dirs);
obj->query_path = g_strdup (path);
obj->query_dirs = g_strsplit (obj->query_path, G_SEARCHPATH_SEPARATOR_S, 0);
g_mutex_unlock (obj->settings_mutex);
}
/**
* db_conn_get_query_path:
* @obj: a #DbConn
*
* Sets the query search path.
*
* Return value: the path, should be freed with g_free()
**/
gchar * db_conn_get_query_path (DbConn * obj)
{
gchar * path;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_mutex_lock (obj->settings_mutex);
path = g_strdup (obj->query_path);
g_mutex_unlock (obj->settings_mutex);
return path;
}
/**
* db_conn_open:
* @obj: a #DbConn
* @host: Host name
* @schema: Database name
* @user: User name
* @pass: Password
*
* Opens a new connection to the database and creates the thread that handles
* all requests made to it asincronously.
*
* Return value: %TRUE if the connection was successfully open, %FALSE otherwise
**/
gboolean db_conn_open (DbConn * obj, const gchar * host, const gchar * schema,
const gchar * user, const gchar * pass, GError ** err)
{
gboolean opened = FALSE;
g_return_val_if_fail (DB_IS_CONN (obj), FALSE);
g_mutex_lock (obj->mutex);
if (!IS_OPEN (obj) && !IS_OPENING (obj) && !IS_CLOSING (obj))
{
DbConnStatus last_status = obj->status;
db_conn_set_status (obj, obj->status | DB_CONN_OPENING | DB_CONN_LOADING);
g_mutex_unlock (obj->mutex);
opened = db_plugin_open (obj->plugin
,host
,schema
,user
,pass
,err
);
g_mutex_lock (obj->mutex);
if (opened)
{
g_mutex_lock (obj->settings_mutex);
g_free (obj->host);
g_free (obj->schema);
g_free (obj->user);
g_free (obj->pass);
obj->host = g_strdup (host);
obj->schema = g_strdup (schema);
obj->user = g_strdup (user);
obj->pass = g_strdup (pass);
g_mutex_unlock (obj->settings_mutex);
db_conn_set_status (obj, DB_CONN_OPEN);
if (last_status & DB_CONN_LOST)
g_cond_signal (obj->thread_cond);
else
obj->thread = g_thread_new ("DbConn",
(GThreadFunc) db_conn_thread, obj);
}
else
db_conn_set_status (obj, last_status);
}
else
g_set_error (err
,DB_CONN_LOG_DOMAIN
,DB_CONN_ERROR_OPENING
,_("Can't open a new connection, it's already open.")
);
g_mutex_unlock (obj->mutex);
return opened;
}
void db_conn_set_ssl (DbConn * obj, const gchar * ca)
{
g_return_if_fail (DB_IS_CONN (obj));
db_plugin_set_ssl (obj->plugin, ca);
}
/**
* db_conn_reconnect:
* @obj: a #DbConn
*
* Tries to reconnect to database.
**/
gboolean db_conn_reconnect (DbConn * obj, GError ** err)
{
gboolean opened;
gchar * host;
gchar * schema;
gchar * user;
gchar * pass;
g_return_val_if_fail (DB_IS_CONN (obj), FALSE);
g_mutex_lock (obj->settings_mutex);
host = g_strdup (obj->host);
schema = g_strdup (obj->schema);
user = g_strdup (obj->user);
pass = g_strdup (obj->pass);
g_mutex_unlock (obj->settings_mutex);
opened = db_conn_open (obj, host, schema, user, pass, err);
g_free (host);
g_free (schema);
g_free (user);
g_free (pass);
return opened;
}
/**
* db_conn_close:
* @obj: a #DbConn
* @wait: specifies whether to wait for pending requests before close the connection
*
* Closes the current connection to the database and the associated thread.
**/
void db_conn_close (DbConn * obj, gboolean wait)
{
g_return_if_fail (DB_IS_CONN (obj));
g_mutex_lock (obj->mutex);
if ((IS_OPEN (obj) || (IS_LOST (obj) && !IS_OPENING (obj))) && !IS_CLOSING (obj))
{
db_conn_set_status (obj, obj->status | DB_CONN_CLOSING | DB_CONN_LOADING);
if (!wait)
db_conn_cancel_requests (obj);
g_cond_signal (obj->thread_cond);
g_mutex_unlock (obj->mutex);
g_thread_join (obj->thread);
obj->thread = NULL;
db_plugin_close (obj->plugin);
g_mutex_lock (obj->mutex);
db_conn_set_status (obj, DB_CONN_CLOSED);
g_mutex_lock (obj->settings_mutex);
g_free (obj->host);
g_free (obj->schema);
g_free (obj->user);
g_free (obj->pass);
obj->host = NULL;
obj->schema = NULL;
obj->user = NULL;
obj->pass = NULL;
g_mutex_unlock (obj->settings_mutex);
}
g_mutex_unlock (obj->mutex);
}
/**
* db_conn_exec:
* @obj: a #DbConn
* @sql: the SQL statement
* @err: (out) (allow-none): return location for a #GError or %NULL
*
* Sends a query to the database and waits for the resultset. The user is
* responsible for releasing the result with db_result_set_free().
*
* Return value: (transfer full) (allow-none): the #DbResultSet on success, %NULL on failure
**/
DbResultSet * db_conn_exec (DbConn * obj, const gchar * sql, GError ** err)
{
GError * query_error = NULL;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
if (sql && g_strcmp0 (sql, ""))
{
DbResultSet * set;
// XXX: Only for debug purposes.
g_message ("DbConn: Query sent: %s", sql);
set = db_plugin_query (obj->plugin, sql, &query_error);
if (!set && query_error)
{
if (query_error->code == DB_CONN_ERROR_LOST)
{
g_mutex_lock (obj->mutex);
if (IS_OPEN (obj) && !IS_CLOSING (obj))
db_conn_set_status (obj, DB_CONN_CLOSED | DB_CONN_LOST);
g_mutex_unlock (obj->mutex);
}
db_conn_set_error (obj, query_error);
g_propagate_error (err, query_error);
}
return set;
}
else
{
query_error = g_error_new (
DB_CONN_LOG_DOMAIN
,DB_CONN_ERROR_QUERY_EMPTY
,_("The query is empty.")
);
db_conn_set_error (obj, query_error);
g_propagate_error (err, query_error);
}
return NULL;
}
/**
* db_conn_query:
* @obj: the #DbConn
* @sql: the SQL statement
*
* Sends a query to the database and waits for the result.
*
* Return value: (transfer full): the new #DbRequest
**/
DbRequest * db_conn_query (DbConn * obj, const gchar * sql, SqlBatch * batch)
{
SqlObject * string;
DbRequest * request;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
string = sql_string_new (sql);
request = db_request_new_with_stmt (obj, SQL_STMT (string), batch);
db_request_exec (request, NULL);
return request;
}
/**
* db_conn_query_with_stmt:
* @obj: the #DbConn
* @stmt: the #SqlStmt
*
* Sends a stmt to the database and waits for the result.
*
* Return value: (transfer full): the new #DbRequest
**/
DbRequest * db_conn_query_with_stmt (DbConn * obj, SqlStmt * stmt, SqlBatch * batch)
{
DbRequest * request;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
request = db_request_new_with_stmt (obj, stmt, batch);
db_request_exec (request, NULL);
return request;
}
/**
* db_conn_query_async:
* @obj: the #DbConn
* @sql: the SQL statement
* @callback:
* @user_data:
* @notify:
*
* Return value: (transfer full): the new #DbRequest
**/
DbRequest * db_conn_query_async (DbConn * obj, const gchar * sql, SqlBatch * batch,
DbRequestDoneCallback callback, gpointer user_data, GDestroyNotify notify)
{
SqlObject * string;
DbRequest * request;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
string = sql_string_new (sql);
request = db_request_new_with_stmt (obj, SQL_STMT (string), batch);
db_request_set_callback (request, callback, user_data, notify);
db_conn_add_request (obj, request);
return request;
}
/**
* db_conn_query_with_stmt_async:
* @obj: the #DbConn
* @stmt: the #SqlStmt
* @callback:
* @user_data:
* @notify:
*
* Return value: (transfer full): the new #DbRequest
**/
DbRequest * db_conn_query_with_stmt_async (DbConn * obj, SqlStmt * stmt, SqlBatch * batch,
DbRequestDoneCallback callback, gpointer user_data, GDestroyNotify notify)
{
DbRequest * request;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
request = db_request_new_with_stmt (obj, stmt, batch);
db_request_set_callback (request, callback, user_data, notify);
db_conn_add_request (obj, request);
return request;
}
/**
* db_conn_query_value:
* @obj: a #DbConn
* @sql: a SQL statement
* @value: (out): return location for a #GValue
* @err: (out) (allow-none): return location for a #GError or %NULL
*
* Sends a sql to the database and takes the first row value of the result.
*
* Return value: %TRUE on success, %FALSE on failure
**/
gboolean db_conn_query_value (DbConn * obj, const gchar * sql, SqlBatch * batch, GValue * value, GError ** err)
{
gboolean success;
DbRequest * request;
g_return_val_if_fail (DB_IS_CONN (obj), FALSE);
request = db_conn_query (obj, sql, batch);
success = db_request_fetch_value (request, value, err);
g_object_unref (request);
return success;
}
/**
* db_conn_kill_query:
* @obj: a #DbConn
*
* Attempts to kill the query that is running, if any.
**/
void db_conn_kill_query (DbConn * obj)
{
g_return_if_fail (DB_IS_CONN (obj));
db_plugin_kill_query (obj->plugin);
}
/**
* db_conn_retry:
* @obj: a #DbConn
*
* Tries rerunning pending requests.
**/
void db_conn_retry (DbConn * obj)
{
g_return_if_fail (DB_IS_CONN (obj));
g_cond_signal (obj->thread_cond);
}
/**
* db_conn_parse:
* @obj: a #DbConn
* @sql: an SQL string
*
* Return value: (transfer full): a #SqlStmt
**/
SqlStmt * db_conn_parse (DbConn * obj, gchar * sql)
{
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
return db_plugin_parse (obj->plugin, sql);
}
/**
* db_conn_render:
* @obj: a #DbConn.
* @object: the #GObject to render
* @err: (out) (allow-none): the return location for #GError
*
* Renders a #GObject object as a SQL string to send it in a database
* query. It takes the connection to know the codification in wich to escape
* the data.
*
* Return value: (transfer full): the rendered string, or %NULL if error.
**/
gchar * db_conn_render (DbConn * obj, gpointer object, SqlBatch * batch, GError ** err)
{
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_return_val_if_fail (G_IS_OBJECT (object), NULL);
g_return_val_if_fail (SQL_IS_BATCH (batch) || !batch, NULL);
return db_plugin_render (obj->plugin, object, batch, err);
}
/**
* db_conn_start_transaction:
* @obj: a #DbConn
*
* Enter the transaction state, all requests made are retained until you call
* the method db_conn_comit.
**/
void db_conn_start_transaction (DbConn * obj)
{
g_return_if_fail (DB_IS_CONN (obj));
g_mutex_lock (obj->mutex);
if (IS_OPEN (obj) && !IS_CLOSING (obj))
{
obj->transaction++;
db_conn_set_status (obj, obj->status | DB_CONN_TRANSACTION);
}
g_mutex_unlock (obj->mutex);
}
/**
* db_conn_commit:
* @obj: a #DbConn
*
* Commits the current transaction. If transaction arrives to 0, all
* outstanding requests in the queue are sent.
**/
void db_conn_commit (DbConn * obj)
{
g_return_if_fail (DB_IS_CONN (obj));
g_mutex_lock (obj->mutex);
if (IS_TRANSACTION (obj))
{
obj->transaction--;
if (!obj->transaction)
{
db_conn_set_status (obj, obj->status & ~DB_CONN_TRANSACTION);
g_mutex_unlock (obj->mutex);
db_conn_retry (obj);
return;
}
}
g_mutex_unlock (obj->mutex);
}
/**
* db_conn_rollback:
* @obj: a #DbConn
*
* Deletes all pending requests from the input queue and rollbacks the current
* transactions, if any.
**/
void db_conn_rollback (DbConn * obj)
{
g_return_if_fail (DB_IS_CONN (obj));
g_mutex_lock (obj->mutex);
if (IS_TRANSACTION (obj))
{
db_conn_cancel_requests (obj);
obj->transaction = 0;
db_conn_set_status (obj, obj->status & ~DB_CONN_TRANSACTION);
}
g_mutex_unlock (obj->mutex);
}
/**
* db_conn_get_user:
* @obj: a #DbConn
*
* Gets the connection user.
*
* Return value: the user, should be freed using g_free()
**/
gchar * db_conn_get_user (DbConn * obj)
{
gchar * user;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_mutex_lock (obj->settings_mutex);
user = g_strdup (obj->user);
g_mutex_unlock (obj->settings_mutex);
return user;
}
/**
* db_conn_get_host:
* @obj: a #DbConn
*
* Gets the connection host.
*
* Return value: the host, should be freed using g_free()
**/
gchar * db_conn_get_host (DbConn * obj)
{
gchar * host;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_mutex_lock (obj->settings_mutex);
host = g_strdup (obj->host);
g_mutex_unlock (obj->settings_mutex);
return host;
}
/**
* db_conn_get_schema:
* @obj: a #DbConn
*
* Gets the connection schema.
*
* Return value: the schema, should be freed using g_free()
**/
gchar * db_conn_get_schema (DbConn * obj)
{
gchar * schema;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_mutex_lock (obj->settings_mutex);
schema = g_strdup (obj->schema);
g_mutex_unlock (obj->settings_mutex);
return schema;
}
/**
* db_conn_create_stmt_from_file:
* @obj: a #DbConn
* @query_file: path to a file containing SQL statement
*
* Reads an SQL query from the specified query_file and creates a new
* #SqlString. The file path must be relative to any path in the "query-path"
* property.
*
* Return value: (transfer full): an #SqlString
**/
SqlObject * db_conn_create_stmt_from_file (DbConn * obj, const gchar * query_file)
{
gint i;
gchar * file;
SqlObject * stmt = NULL;
g_return_val_if_fail (DB_IS_CONN (obj), NULL);
g_return_val_if_fail (query_file, NULL);
if (g_str_has_suffix (query_file, ".sql"))
file = g_strdup (query_file);
else
file = g_strconcat (query_file, ".sql", NULL);
if (obj->query_dirs)
for (i = 0; obj->query_dirs[i] != NULL/* && !stmt*/; i++)
{
gchar * buffer;
gchar * path = g_build_filename (obj->query_dirs[i], file, NULL);
if (g_file_get_contents (path, &buffer, NULL, NULL))
{
stmt = sql_string_new (buffer);
g_free (buffer);
}
g_free (path);
}
if (!stmt)
g_warning ("DbConn: Can't create statement from file: %s", file);
g_free (file);
return stmt;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties
enum
{
PROP_PLUGIN = 1
,PROP_QUERY_PATH
,PROP_HOST
,PROP_USER
,PROP_DB
};
static void db_conn_set_property (DbConn * obj, guint id,
const GValue * value, GParamSpec * pspec)
{
switch (id)
{
case PROP_PLUGIN:
db_conn_load_plugin (obj, g_value_get_string (value), NULL);
break;
case PROP_QUERY_PATH:
db_conn_set_query_path (obj, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
}
}
static void db_conn_get_property (DbConn * obj, guint id,
GValue * value, GParamSpec * pspec)
{
switch (id)
{
case PROP_PLUGIN:
g_value_set_string (value, obj->plugin_name);
break;
case PROP_QUERY_PATH:
g_value_set_string (value, db_conn_get_query_path (obj));
break;
case PROP_HOST:
g_value_take_string (value, db_conn_get_host (obj));
break;
case PROP_USER:
g_value_take_string (value, db_conn_get_user (obj));
break;
case PROP_DB:
g_value_take_string (value, db_conn_get_schema (obj));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec);
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class
static void db_conn_init (DbConn * obj)
{
obj->plugin = NULL;
obj->plugin_name = NULL;
obj->query_path = NULL;
obj->query_dirs = NULL;
obj->schema = NULL;
obj->host = NULL;
obj->user = NULL;
obj->pass = NULL;
obj->thread = NULL;
obj->thread_cond = g_new (GCond, 1);
obj->transaction = 0;
obj->status = DB_CONN_CLOSED;
obj->requests = g_queue_new ();
obj->mutex = g_new (GMutex, 1);
obj->settings_mutex = g_new (GMutex, 1);
g_mutex_init (obj->mutex);
g_mutex_init (obj->settings_mutex);
g_cond_init (obj->thread_cond);
}
static void db_conn_finalize (DbConn * obj)
{
db_conn_close (obj, FALSE);
if (obj->plugin)
g_free (obj->plugin_name);
g_mutex_clear (obj->settings_mutex);
g_mutex_clear (obj->mutex);
g_cond_clear (obj->thread_cond);
g_free (obj->query_path);
g_strfreev (obj->query_dirs);
g_free (obj->settings_mutex);
g_free (obj->mutex);
g_free (obj->thread_cond);
g_free (obj->host);
g_free (obj->user);
g_free (obj->pass);
g_free (obj->schema);
g_queue_free_full (obj->requests, (GDestroyNotify) g_object_unref);
G_OBJECT_CLASS (db_conn_parent_class)->finalize (G_OBJECT (obj));
}
static void db_conn_class_init (DbConnClass * k)
{
GObjectClass * klass = G_OBJECT_CLASS (k);
klass->set_property = (GObjectSetPropertyFunc) db_conn_set_property;
klass->get_property = (GObjectGetPropertyFunc) db_conn_get_property;
klass->finalize = (GObjectFinalizeFunc) db_conn_finalize;
signals[STATUS_CHANGED] = g_signal_new ("status-changed",
DB_TYPE_CONN, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT
);
signals[ERROR] = g_signal_new ("error",
DB_TYPE_CONN, G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1, G_TYPE_POINTER
);
g_object_class_install_property (klass, PROP_PLUGIN,
g_param_spec_string ("plugin"
,_("Plugin")
,_("The name of the plugin")
,NULL
,G_PARAM_READWRITE
));
g_object_class_install_property (klass, PROP_QUERY_PATH,
g_param_spec_string ("query-path"
,_("Query path")
,_("The path where query files are located")
,NULL
,G_PARAM_READWRITE
));
g_object_class_install_property (klass, PROP_HOST,
g_param_spec_string ("host"
,_("Host")
,_("The host name to connect to")
,NULL
,G_PARAM_READABLE
));
g_object_class_install_property (klass, PROP_USER,
g_param_spec_string ("user"
,_("User")
,_("The user name")
,NULL
,G_PARAM_READABLE
));
g_object_class_install_property (klass, PROP_DB,
g_param_spec_string ("db"
,_("DB name")
,_("The default schema")
,NULL
,G_PARAM_READABLE
));
}