Algunos bugs en DbModel solucionados.

This commit is contained in:
Juan Ferrer Toribio 2014-05-30 11:19:53 +02:00
parent 0d57e4570f
commit a48f4923f4
7 changed files with 156 additions and 217 deletions

View File

@ -90,7 +90,7 @@ typedef struct
}
Field;
#define remove_delimiters(str) (g_strstrip (g_strdelimit (str, "`\"", ' ')))
#define remove_delimiters(str) (g_strdup (g_strstrip (g_strdelimit (str, "`\"", ' '))))
static void field_parse (Field * field, const gchar * string)
{

View File

@ -51,34 +51,15 @@ struct _DbModelPrivate
SqlStmt * stmt;
gchar * sql;
gboolean use_file;
Table * main_table;
DbModelUpdateFlags update_flags;
SqlBatch * batch;
GPtrArray * data;
DbColumn * column;
GHashTable * column_index;
DbResult * result;
guint result_pos;
DbRequest * request;
DbModelStatus status;
DbModelMode mode;
gchar * user_main_table;
DbModelUpdateFlags user_update_flags;
guint result_pos;
GQueue * operation;
GHashTable * row_ops;
gint updated_col;
GValue * updated_value;
GHashTable * column_index;
GSList * pending_request;
GSList * join;
SqlObject * link_op;
SqlBatch * internal_batch;
GHashTable * column_defaults;
GHashTable * tables;
gboolean updatable_data_allocated;
gint stamp;
gboolean fresh;
@ -92,6 +73,23 @@ struct _DbModelPrivate
DbIterCompareFunc sort_func;
gpointer sort_data;
GDestroyNotify sort_destroy;
SqlObject * link_op;
SqlBatch * internal_batch;
GHashTable * column_defaults;
gboolean updatable_data_allocated;
DbModelUpdateFlags update_flags;
DbModelUpdateFlags user_update_flags;
Table * main_table;
gchar * user_main_table;
GHashTable * tables;
gint updated_col;
GQueue * operation;
GHashTable * row_ops;
GValue * updated_value;
GSList * pending_request;
GSList * join;
};
// Helper structures and methods
@ -212,62 +210,6 @@ static void db_model_alloc_link_data (DbModel * obj)
sql_operation_set_operands (SQL_OPERATION (priv->link_op), operators);
}
static void db_model_free_stmt_data (DbModel * obj)
{
if (obj->priv->tables)
g_hash_table_destroy (obj->priv->tables);
}
static void db_model_alloc_stmt_data (DbModel * obj)
{
gint i;
Table table;
TableData * table_data;
DbModelPrivate * priv = obj->priv;
if (!priv->updatable_data_allocated)
return;
db_model_free_stmt_data (obj);
priv->tables = g_hash_table_new_full (
(GHashFunc) table_hash,
(GEqualFunc) table_equal,
(GDestroyNotify) table_free,
(GDestroyNotify) table_data_free
);
for (i = 0; i < priv->result->ncols; i++)
if ((priv->column[i].info & DB_COLUMN_PRI_KEY))
{
table.name = priv->column[i].table;
table.schema = priv->column[i].schema;
table_data = g_hash_table_lookup (priv->tables, &table);
if (!table_data)
{
table_data = g_new0 (TableData, 1);
table_data->pkeys = NULL;
g_hash_table_insert (priv->tables, table_copy (&table), table_data);
}
table_data->pkeys = g_slist_prepend (table_data->pkeys, GINT_TO_POINTER (i));
g_hash_table_insert (priv->tables, table_copy (&table), table_data);
}
for (i = 0; i < priv->result->ncols; i++)
{
table.name = priv->column[i].table;
table.schema = priv->column[i].schema;
table_data = g_hash_table_lookup (priv->tables, &table);
if (table_data && table_data->pkeys)
gvn_param_spec_set_editable (priv->column[i].spec, TRUE);
}
}
// Signal Handlers
enum
@ -323,9 +265,64 @@ static void db_model_calculate_update_flags (DbModel * obj)
{
gint i;
Table table;
TableData * table_data;
DbModelPrivate * priv = obj->priv;
priv->main_table = NULL;
// Allocates aditional memory when the model is updatable
if (priv->user_update_flags && !priv->updatable_data_allocated)
{
priv->updatable_data_allocated = TRUE;
priv->operation = g_queue_new ();
priv->row_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->tables = g_hash_table_new_full (
(GHashFunc) table_hash,
(GEqualFunc) table_equal,
(GDestroyNotify) table_free,
(GDestroyNotify) table_data_free
);
}
if (priv->user_update_flags && priv->fresh && priv->result)
{
g_hash_table_remove_all (priv->tables);
for (i = 0; i < priv->result->ncols; i++)
if ((priv->column[i].info & DB_COLUMN_PRI_KEY))
{
table.name = priv->column[i].table;
table.schema = priv->column[i].schema;
table_data = g_hash_table_lookup (priv->tables, &table);
if (!table_data)
{
table_data = g_new0 (TableData, 1);
table_data->pkeys = NULL;
g_hash_table_insert (priv->tables, table_copy (&table), table_data);
}
table_data->pkeys = g_slist_prepend (table_data->pkeys, GINT_TO_POINTER (i));
}
}
if (priv->result)
{
for (i = 0; i < priv->result->ncols; i++)
{
table.name = priv->column[i].table;
table.schema = priv->column[i].schema;
table_data = g_hash_table_lookup (priv->tables, &table);
if (table_data && table_data->pkeys)
gvn_param_spec_set_editable (priv->column[i].spec, TRUE);
}
}
// Searchs for the main table
table.name = NULL;
if (priv->result)
{
@ -336,39 +333,29 @@ static void db_model_calculate_update_flags (DbModel * obj)
{
table.name = priv->column[i].table;
table.schema = priv->column[i].schema;
priv->main_table = g_hash_table_lookup (priv->tables, &table);
break;
}
}
else
{
table_parse (&table, priv->user_main_table);
priv->main_table = g_hash_table_lookup (priv->tables, &table);
}
if (!priv->main_table)
if (!table.name
|| !g_hash_table_lookup_extended (priv->tables, &table, (gpointer) &priv->main_table, NULL))
{
priv->main_table = NULL;
if (priv->user_main_table)
g_log (g_quark_to_string (DB_MODEL_LOG_DOMAIN), G_LOG_LEVEL_WARNING,
"Can't set '%s' as main table", table.name);
}
"Can't set '%s' as main table", priv->user_main_table);
}
// Sets the updatable flags
if (priv->main_table)
priv->update_flags = DB_MODEL_ALL & priv->user_update_flags;
else
priv->update_flags = 0;
if (!priv->updatable_data_allocated && priv->update_flags)
{
priv->updatable_data_allocated = TRUE;
priv->operation = g_queue_new ();
priv->row_ops = g_hash_table_new (g_direct_hash, g_direct_equal);
priv->column_defaults = g_hash_table_new_full (
(GHashFunc) field_hash,
(GEqualFunc) field_equal,
(GDestroyNotify) field_free,
(GDestroyNotify) column_def_free
);
}
}
static void db_model_on_data_ready (DbRequest * request, DbModel * obj)
@ -388,8 +375,6 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj)
if ((r = db_request_fetch_result (request, NULL)))
{
gint i;
priv->column = r->column;
priv->data = r->data;
@ -404,9 +389,6 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj)
if (priv->fresh)
{
db_model_calculate_update_flags (obj);
db_model_alloc_stmt_data (obj);
for (i = 0; i < priv->result->ncols; i++)
g_hash_table_insert (priv->column_index,
g_strdup (priv->column[i].alias), GINT_TO_POINTER (i));
@ -417,6 +399,9 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj)
db_model_set_sort_column_id (obj,
priv->old_sort_column_id, priv->old_order);
db_model_calculate_update_flags (obj);
priv->fresh = FALSE;
db_model_set_status (obj, DB_MODEL_STATUS_READY);
}
}
@ -445,32 +430,17 @@ static void db_model_process_insert (DbModel * obj, DbRequest * request, DbRow *
for (i = 0; i < result->ncols; i++)
for (j = 0; j < priv->result->ncols; j++)
if (!g_strcmp0 (priv->column[j].name, result->column[i].name)
&& !g_strcmp0 (priv->column[j].table, result->column[i].table))
&& !g_strcmp0 (priv->column[j].table, result->column[i].table)
&& !g_strcmp0 (priv->column[j].schema, result->column[i].schema))
{
GValue * v;
gboolean emit = TRUE;
GValue * new_value = &req_row->value[i];
if (!gvn_value_compare (new_value, DB_ROW_FIELD (row, j)))
{
priv->updated_value = g_new0 (GValue, 1);
g_value_init (priv->updated_value, G_VALUE_TYPE (new_value));
g_value_copy (new_value, priv->updated_value);
if ((v = &req_row->value[i]) && G_IS_VALUE (v)
&& !gvn_value_is_null (DB_ROW_FIELD (req_row, i))
&& gvn_value_is_null (DB_ROW_FIELD (row, j)))
{
g_value_init (priv->updated_value, G_VALUE_TYPE (v));
gvn_value_copy (v, priv->updated_value);
}
else if (gvn_value_is_null (DB_ROW_FIELD (row, j)))
{
g_value_init (priv->updated_value, GVN_TYPE_NULL);
}
else
{
emit = FALSE;
g_free (priv->updated_value);
}
if (emit)
{
priv->updated_col = j;
g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter);
}
@ -485,14 +455,12 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d
{
GList * l;
guint i = 0;
DbIter iter;
DbOperation * op;
GError * err = NULL;
DbModel * obj = data->obj;
DbModelPrivate * priv = obj->priv;
priv->pending_request =
g_slist_remove (priv->pending_request, request);
l = g_queue_peek_head_link (data->operations);
for (; l; l = l->next)
@ -507,7 +475,7 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d
continue;
}
if (db_request_fetch_non_select (request, &err) == -1)
if (!request || db_request_fetch_non_select (request, &err) == -1)
break;
g_hash_table_remove (priv->row_ops, op->row);
@ -525,7 +493,6 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d
{
guint j;
SqlList * list;
DbIter iter;
SqlObject * multi = sql_list_get (data->stmts, i);
g_object_get (multi, "stmts", &list, NULL);
@ -547,6 +514,13 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d
i++;
}
if (request)
{
priv->pending_request =
g_slist_remove (priv->pending_request, request);
g_object_unref (request);
}
if (!err)
{
while ((op = g_queue_pop_head (data->operations)))
@ -554,12 +528,11 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d
g_signal_emit (obj, db_model_signal[OPERATIONS_DONE], 0);
}
g_object_unref (request);
}
static void db_model_on_stmt_changed (SqlStmt * stmt, DbModel * obj)
{
obj->priv->fresh = TRUE;
db_model_refresh (obj);
}
@ -679,8 +652,6 @@ static void db_operation_add_updated (DbOperation * op, gint col)
u->column = col;
op->type |= DB_MODEL_ROW_OP_UPDATE;
op->updated = g_slist_prepend (op->updated, u);
return;
}
static gboolean db_model_set_row_operation (DbModel * obj,
@ -698,12 +669,7 @@ static gboolean db_model_set_row_operation (DbModel * obj,
if (type & DB_MODEL_ROW_OP_UPDATE)
db_operation_add_updated (new_op, col);
/* if (!db_operation_add_updated (new_op, col))
{
g_free (new_op);
return FALSE;
}
*/
g_hash_table_insert (obj->priv->row_ops, row, new_op);
g_queue_push_tail (obj->priv->operation, new_op);
}
@ -714,8 +680,6 @@ static gboolean db_model_set_row_operation (DbModel * obj,
if (type & DB_MODEL_ROW_OP_UPDATE)
db_operation_add_updated (op, col);
// if (!db_operation_add_updated (op, col))
// return FALSE;
}
else
return FALSE;
@ -1303,15 +1267,13 @@ static void db_model_clear (DbModel * obj)
priv->column = NULL;
priv->data = NULL;
g_free (priv->main_table);
priv->main_table = NULL;
priv->update_flags = 0;
priv->fresh = FALSE;
priv->old_order = priv->order;
priv->old_sort_column_id = priv->sort_column_id;
priv->sort_column_id = DB_MODEL_UNSORTED_SORT_COLUMN_ID;
priv->stamp = g_random_int ();
priv->main_table = NULL;
priv->update_flags = 0;
}
}
@ -2311,7 +2273,10 @@ gboolean db_model_has_pending_operations (DbModel * obj)
{
g_return_val_if_fail (DB_IS_MODEL (obj), FALSE);
if (obj->priv->row_ops)
return g_hash_table_size (obj->priv->row_ops) > 0;
return FALSE;
}
static SqlObject * db_model_create_where (DbModel * obj,
@ -2335,6 +2300,7 @@ static SqlObject * db_model_create_where (DbModel * obj,
for (l = table_data->pkeys; l; l = l->next)
{
GSList * n;
SqlObject * equal;
SqlList * operands;
gint col = GPOINTER_TO_INT (l->data);
@ -2343,7 +2309,7 @@ static SqlObject * db_model_create_where (DbModel * obj,
g_value = &row->value[col];
for (l = operation->updated; l && (u = l->data); l = l->next)
for (n = operation->updated; n && (u = n->data); n = n->next)
if (u->column == col)
{
g_value = u->value;
@ -2624,9 +2590,8 @@ void db_model_perform_operations (DbModel * obj, gboolean retry)
sql_list_add (stmts, stmt);
}
if (sql_list_length (stmts) > 0 && !error)
if (!error)
{
SqlObject * multi = g_object_new (SQL_TYPE_MULTI_STMT, "stmts", stmts, NULL);
GQueue * ops = g_queue_new ();
while ((op = g_queue_pop_head (priv->operation)))
@ -2637,6 +2602,11 @@ void db_model_perform_operations (DbModel * obj, gboolean retry)
data->operations = ops;
data->stmts = g_object_ref_sink (stmts);
if (sql_list_length (stmts) > 0)
{
SqlObject * multi = g_object_new (
SQL_TYPE_MULTI_STMT, "stmts", stmts, NULL);
request = db_conn_query_with_stmt_async (priv->conn
,SQL_STMT (multi)
,NULL
@ -2647,7 +2617,13 @@ void db_model_perform_operations (DbModel * obj, gboolean retry)
db_model_add_pending_request (obj, request);
}
else
g_warning ("DbModel: Error performing operations");
{
db_model_on_operations_done (NULL, data);
db_model_request_free (data);
}
}
else
g_warning ("DbModel: Error performing operations.");
g_object_unref (stmts);
}
@ -3054,13 +3030,18 @@ static void db_model_init (DbModel *obj)
priv->link_op = NULL;
priv->internal_batch = NULL;
priv->column_defaults = g_hash_table_new_full (
(GHashFunc) field_hash,
(GEqualFunc) field_equal,
(GDestroyNotify) field_free,
(GDestroyNotify) column_def_free
);
priv->updatable_data_allocated = FALSE;
priv->update_flags = 0;
priv->user_update_flags = DB_MODEL_ALL;
priv->main_table = NULL;
priv->user_main_table = NULL;
priv->column_defaults = NULL;
priv->operation = NULL;
priv->row_ops = NULL;
priv->join = NULL;
@ -3083,15 +3064,15 @@ static void db_model_finalize (DbModel * obj)
g_clear_object (&priv->link_op);
g_clear_object (&priv->internal_batch);
g_hash_table_destroy (priv->column_defaults);
if (priv->updatable_data_allocated)
{
g_free (priv->user_main_table);
g_hash_table_destroy (priv->column_defaults);
g_queue_free (priv->operation);
g_hash_table_destroy (priv->row_ops);
g_slist_free_full (priv->join, (GDestroyNotify) db_join_free);
db_model_free_stmt_data (obj);
g_hash_table_destroy (priv->tables);
}
parent->finalize (G_OBJECT (obj));

View File

@ -26,7 +26,7 @@ static void vn_customer_open (VnForm * obj, gpointer user_data)
DbIterator * info = vn_form_get (obj, "info");
DbIterator * homes = vn_form_get (obj, "homes");
db_iterator_link (homes, "user_id", info, "id");
db_iterator_link (homes, "user_address.user_id", info, "id");
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++ Class

View File

@ -229,6 +229,7 @@ static DbResultSet * db_mysql_query (DbMysql * obj, const gchar * sql, GError **
column->alias = g_strdup (field[i].name);
column->table = g_strdup (field[i].org_table);
column->table_alias = g_strdup (field[i].table);
column->schema = g_strdup (field[i].db);
switch (field[i].type)
{

View File

@ -628,6 +628,7 @@ static DbResultSet * __db_pg_query
r->column[j].info = 0;
r->column[j].name = NULL;
r->column[j].table = NULL;
r->column[j].schema = NULL;
if (GPOINTER_TO_INT (g_ptr_array_index (col_iter, j)) == 0)
{

View File

@ -261,45 +261,3 @@ SqlObject * sql_parser_parse (gchar * sql)
return object;
}
SqlField * sql_parser_parse_field (const gchar * field_str)
{
gchar ** split;
SqlObject * field = NULL;
if (!field_str || !g_strcmp0 (field_str, ""))
return NULL;
split = g_strsplit (field_str, ".", 0);
switch (g_strv_length (split))
{
case 3:
{
field = sql_field_new_with_target
(g_strstrip (g_strdelimit (split[2], "`\"", ' '))
,g_strstrip (g_strdelimit (split[1], "`\"", ' '))
,g_strstrip (g_strdelimit (split[0], "`\"", ' ')));
break;
}
case 2:
{
field = sql_field_new_with_target
(g_strstrip (g_strdelimit (split[1], "`\"", ' '))
,g_strstrip (g_strdelimit (split[0], "`\"", ' '))
,NULL);
break;
}
case 1:
{
field = sql_field_new_with_target
(g_strstrip (g_strdelimit (split[0], "`\"", ' '))
,NULL
,NULL);
break;
}
}
g_strfreev (split);
return SQL_FIELD (field);
}

View File

@ -33,6 +33,4 @@
*/
SqlObject * sql_parser_parse (gchar * sql) G_GNUC_WARN_UNUSED_RESULT;
SqlField * sql_parser_parse_field (const gchar * field_str);
#endif