diff --git a/db/db-model-private.c b/db/db-model-private.c index c6e33af..5595d18 100644 --- a/db/db-model-private.c +++ b/db/db-model-private.c @@ -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) { diff --git a/db/db-model.c b/db/db-model.c index 7ca5c6e..421e3fb 100644 --- a/db/db-model.c +++ b/db/db-model.c @@ -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) - g_log (g_quark_to_string (DB_MODEL_LOG_DOMAIN), G_LOG_LEVEL_WARNING, - "Can't set '%s' as main table", table.name); - } } + 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", 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]; - priv->updated_value = g_new0 (GValue, 1); - - 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) + 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); + priv->updated_col = j; g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); } @@ -485,13 +455,11 @@ 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); @@ -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); @@ -538,7 +505,7 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d if (G_OBJECT_TYPE (sql_list_get (list, j)) == SQL_TYPE_MULTI_STMT) db_model_process_insert (obj, request, op->row, err); } - + iter.stamp = priv->stamp; iter.data = op->row; g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); @@ -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; @@ -1302,16 +1266,14 @@ static void db_model_clear (DbModel * obj) priv->result = NULL; 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; } } @@ -1674,7 +1636,7 @@ void db_model_set_default_value_from_param (DbModel * obj, g_return_if_fail (GVN_IS_PARAM (param)); field = field_new_from_string (field_str); - + if (link) { SqlList * operands, * link_operands; @@ -2311,7 +2273,10 @@ gboolean db_model_has_pending_operations (DbModel * obj) { g_return_val_if_fail (DB_IS_MODEL (obj), FALSE); - return g_hash_table_size (obj->priv->row_ops) > 0; + 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, @@ -2330,11 +2295,12 @@ static SqlObject * db_model_create_where (DbModel * obj, and_operands = sql_list_new (SQL_TYPE_EXPR); sql_operation_set_operands (SQL_OPERATION (where), and_operands); - + TableData * table_data = g_hash_table_lookup (priv->tables, table); - + 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))) @@ -2636,18 +2601,29 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) data->obj = g_object_ref (obj); data->operations = ops; data->stmts = g_object_ref_sink (stmts); - - request = db_conn_query_with_stmt_async (priv->conn - ,SQL_STMT (multi) - ,NULL - ,(DbRequestDoneCallback) db_model_on_operations_done - ,data - ,(GDestroyNotify) db_model_request_free - ); - db_model_add_pending_request (obj, request); + + 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 + ,(DbRequestDoneCallback) db_model_on_operations_done + ,data + ,(GDestroyNotify) db_model_request_free + ); + db_model_add_pending_request (obj, request); + } + else + { + db_model_on_operations_done (NULL, data); + db_model_request_free (data); + } } else - g_warning ("DbModel: Error performing operations"); + 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)); diff --git a/module/src/vn-customer.c b/module/src/vn-customer.c index 70b5a8c..aad83b7 100644 --- a/module/src/vn-customer.c +++ b/module/src/vn-customer.c @@ -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 diff --git a/plugin/mysql/db-mysql.c b/plugin/mysql/db-mysql.c index 86bed77..0aeb45d 100644 --- a/plugin/mysql/db-mysql.c +++ b/plugin/mysql/db-mysql.c @@ -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) { diff --git a/plugin/pg/db-pg.c b/plugin/pg/db-pg.c index c05d82e..6d5325f 100644 --- a/plugin/pg/db-pg.c +++ b/plugin/pg/db-pg.c @@ -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) { diff --git a/sql/parser/scan.rl b/sql/parser/scan.rl index 6f16392..8b96bc1 100644 --- a/sql/parser/scan.rl +++ b/sql/parser/scan.rl @@ -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); -} diff --git a/sql/sql-parser.h b/sql/sql-parser.h index afccf3a..d060221 100644 --- a/sql/sql-parser.h +++ b/sql/sql-parser.h @@ -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 \ No newline at end of file