diff --git a/db/db-model.c b/db/db-model.c index 1cf7b78..7ca5c6e 100644 --- a/db/db-model.c +++ b/db/db-model.c @@ -20,6 +20,7 @@ #include #include "db-model.h" #include "db-row.h" +#include "db-model-private.c" #define MODEL_NOT_READY(obj) (obj->priv->status != DB_MODEL_STATUS_READY) #define VALID_ITER(iter, model) (iter->data && iter->stamp == model->priv->stamp) @@ -50,7 +51,7 @@ struct _DbModelPrivate SqlStmt * stmt; gchar * sql; gboolean use_file; - gchar * main_table; + Table * main_table; DbModelUpdateFlags update_flags; SqlBatch * batch; @@ -74,8 +75,9 @@ struct _DbModelPrivate SqlObject * link_op; SqlBatch * internal_batch; - GHashTable * defaults; - GHashTable * column_default; + GHashTable * column_defaults; + GHashTable * tables; + gboolean updatable_data_allocated; gint stamp; @@ -96,57 +98,6 @@ struct _DbModelPrivate // Structures -/* - * DbUpdatedField: - * @column: the position of the field in the row - * @value: the old value of the updated field - * - * Previous value of an updated field. - **/ -typedef struct -{ - gint column; - GValue * value; -} -DbUpdatedField; - -/* - * DbOperation: - * @type: #DbModelRowOp flags - * @locked: %TRUE while the operation is being performed - * @row: the #DbRow over which the operation has been performed - * @updated: (element-type Db.UpdatedField): old values for the updated fields - * in @row - * @request: #DbRequest associated to the operation, once performed - * - * A structure explaining the operations performed over each #DbRow. - **/ -typedef struct -{ - DbModelRowOp type; - gboolean locked; - DbRow * row; - GSList * updated; -} -DbOperation; - -/* - * DbModelRequest: - * @request: a DbRequest being performed - * @operations: a GQueue of operations being performed - * @model: the DbModel over which the operations are being performed - * - * This struct holds the information of a request performed but not yet - * finalized. - **/ -typedef struct -{ - DbModel * obj; - GQueue * operations; - SqlList * stmts; -} -DbModelRequest; - typedef struct { DbModel * obj; @@ -171,30 +122,13 @@ typedef struct } DbJoin; -typedef struct -{ - gchar * field; - gpointer param; - gboolean link; - SqlObject * equal_op; - DbModel * obj; -} -ParamDef; - -typedef struct -{ - gint count; - gint * index; -} -DbModelPKey; - enum { DB_MODEL_UNSORTED_SORT_COLUMN_ID = -2, DB_MODEL_DEFAULT_SORT_COLUMN_ID }; -// Constructors +//+++++++++++++++++++++++++++++++++++++++++++++++++++ Constructors /** * db_model_new: @@ -246,6 +180,7 @@ DbModel * db_model_new_with_file (DbConn * conn, const gchar * file) // Prototypes +static void db_model_on_batch_changed (SqlBatch * batch, DbModel * obj); static void db_model_set_status (DbModel * obj ,DbModelStatus status); static void db_model_clear (DbModel * obj); @@ -256,7 +191,84 @@ static void db_model_manage_join (DbModel * obj ,gint col); static void db_model_post_process_query (DbModel * obj); -// Signal Handlers +// Memory allocate functions + +static void db_model_alloc_link_data (DbModel * obj) +{ + SqlList * operators; + DbModelPrivate * priv = obj->priv; + + if (priv->link_op) + return; + + priv->internal_batch = g_object_ref_sink (sql_batch_new ()); + g_signal_connect (priv->internal_batch, "changed", + G_CALLBACK (db_model_on_batch_changed), obj); + + priv->link_op = sql_operation_new (SQL_OPERATION_TYPE_AND); + sql_batch_add (priv->internal_batch, "link", priv->link_op); + + operators = sql_list_new (SQL_TYPE_EXPR); + 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 { @@ -310,34 +322,52 @@ static void db_model_on_line_deleted (DbModel * obj, gint position) static void db_model_calculate_update_flags (DbModel * obj) { gint i; - gchar * main_table = NULL; + Table table; DbModelPrivate * priv = obj->priv; - + + priv->main_table = NULL; + if (priv->result) - for (i = 0; i < priv->result->ncols && !main_table; i++) - if (priv->column[i].info & DB_COLUMN_PRI_KEY) { if (!priv->user_main_table) - main_table = priv->column[i].table; - else if (!g_strcmp0 (priv->user_main_table, priv->column[i].table)) - main_table = priv->user_main_table; + { + 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; + 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); + } } - - g_free (priv->main_table); - - if (main_table) - { + + if (priv->main_table) priv->update_flags = DB_MODEL_ALL & priv->user_update_flags; - priv->main_table = g_strdup (main_table); - } else - { - if (priv->user_main_table && priv->result) - g_log (g_quark_to_string (DB_MODEL_LOG_DOMAIN), G_LOG_LEVEL_WARNING, - "The requested table can't be set as main table"); - priv->update_flags = 0; - priv->main_table = NULL; + + 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 + ); } } @@ -358,7 +388,7 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj) if ((r = db_request_fetch_result (request, NULL))) { - gint i, j; + gint i; priv->column = r->column; priv->data = r->data; @@ -370,40 +400,22 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj) } else { - GSList * t = NULL; - priv->result = r; if (priv->fresh) - priv->column_index = g_hash_table_new_full (g_str_hash, - g_str_equal, (GDestroyNotify) g_free, NULL); - - for (i = 0; i < priv->result->ncols; i++) { - // Set fields editable if *all* primary keys are selected FIXME - if (priv->column[i].info & DB_COLUMN_PRI_KEY - && !g_slist_find_custom (t, priv->column[i].table, (GCompareFunc) g_strcmp0)) - for (j = 0; j < priv->result->ncols; j++) - if (!g_strcmp0 (priv->column[i].table, priv->column[j].table)) - { - gvn_param_spec_set_editable (priv->column[j].spec, TRUE); - t = g_slist_prepend (t, priv->column[j].table); - } + db_model_calculate_update_flags (obj); + db_model_alloc_stmt_data (obj); - if (priv->fresh && priv->column_index) + for (i = 0; i < priv->result->ncols; i++) g_hash_table_insert (priv->column_index, - g_strdup (priv->column[i].display), GINT_TO_POINTER (i)); + g_strdup (priv->column[i].alias), GINT_TO_POINTER (i)); + + db_model_post_process_query (obj); } - - g_slist_free (t); - - db_model_calculate_update_flags (obj); - - if (!priv->fresh) + else db_model_set_sort_column_id (obj, priv->old_sort_column_id, priv->old_order); - else - db_model_post_process_query (obj); db_model_set_status (obj, DB_MODEL_STATUS_READY); } @@ -414,6 +426,148 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * obj) g_clear_object (&priv->request); } +static void db_model_process_insert (DbModel * obj, DbRequest * request, DbRow * row, GError * err) +{ + gint i, j; + DbModelPrivate * priv = obj->priv; + DbResult * result; + DbRow * req_row; + DbIter iter; + + result = db_request_fetch_result (request, &err); + + if (result && result->data && result->nrows > 0 ) + { + iter.stamp = priv->stamp; + iter.data = row; + req_row = g_ptr_array_index (result->data, 0); + + 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)) + { + GValue * v; + gboolean emit = TRUE; + + 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) + { + priv->updated_col = j; + g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); + } + } + } + + if (result) + db_result_free (result); +} + +static void db_model_on_operations_done (DbRequest * request, DbModelRequest * data) +{ + GList * l; + guint i = 0; + 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) + { + op = l->data; + + if (op->type & DB_MODEL_ROW_OP_DELETE + && op->type & DB_MODEL_ROW_OP_INSERT) // DELETE + INSERT + { + g_signal_emit (obj, + db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (op->row)); + continue; + } + + if (db_request_fetch_non_select (request, &err) == -1) + break; + + g_hash_table_remove (priv->row_ops, op->row); + + if (op->type & DB_MODEL_ROW_OP_DELETE) // DELETE + { + g_signal_emit (obj, + db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (op->row)); + } + else if (op->type & DB_MODEL_ROW_OP_INSERT) // INSERT + SELECT + { + db_model_process_insert (obj, request, op->row, err); + } + else if (op->type & DB_MODEL_ROW_OP_UPDATE) // UPDATE || INSERT + SELECT + { + guint j; + SqlList * list; + DbIter iter; + SqlObject * multi = sql_list_get (data->stmts, i); + + g_object_get (multi, "stmts", &list, NULL); + + for (j = 0; j < sql_list_length (list); j++) + { + if (j > 0) + db_request_fetch_non_select (request, &err); + + 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); + } + + i++; + } + + if (!err) + { + while ((op = g_queue_pop_head (data->operations))) + db_model_free_operation (obj, op); + + 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) +{ + db_model_refresh (obj); +} + +static void db_model_on_batch_changed (SqlBatch * batch, DbModel * obj) +{ + db_model_refresh (obj); +} + static void db_model_on_join_query_done (DbRequest * request, JoinData * join_data) { gint i, j; @@ -461,135 +615,7 @@ static void db_model_on_join_query_done (DbRequest * request, JoinData * join_da g_object_unref (request); } -static void db_model_on_stmt_changed (SqlStmt * stmt, DbModel * obj) -{ - db_model_refresh (obj); -} - -static void db_model_on_batch_changed (SqlBatch * batch, DbModel * obj) -{ - db_model_refresh (obj); -} - -static void db_model_process_insert (DbModel * obj, DbRequest * request, DbRow * row, GError * err) -{ - gint i, j; - DbModelPrivate * priv = obj->priv; - DbResult * result; - DbRow * req_row; - DbIter iter; - - result = db_request_fetch_result (request, &err); - - if (result && result->data && result->nrows > 0) - { - iter.stamp = priv->stamp; - iter.data = row; - req_row = g_ptr_array_index (result->data, 0); - - 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)) - { - GValue * v; - gboolean emit = TRUE; - - 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) - { - priv->updated_col = j; - g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); - } - } - } - - if (result) - db_result_free (result); -} - -static void db_model_on_operations_done (DbRequest * request, DbModelRequest * data) -{ - guint i = 0; - DbOperation * op; - GError * err = NULL; - DbModel * obj = data->obj; - DbModelPrivate * priv = obj->priv; - - priv->pending_request = - g_slist_remove (priv->pending_request, request); - - while ((op = g_queue_pop_head (data->operations)) - && db_request_fetch_non_select (request, &err) != -1) - { - DbRow * row = op->row; - db_request_fetch_non_select (request, &err); - - g_hash_table_remove (priv->row_ops, row); - - if (op->type & DB_MODEL_ROW_OP_DELETE) // DELETE - { - g_signal_emit (obj, - db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (row)); - } - else if (op->type & DB_MODEL_ROW_OP_INSERT) // INSERT + SELECT - { - db_model_process_insert (obj, request, row, err); - } - else if (op->type & DB_MODEL_ROW_OP_UPDATE) // UPDATE || INSERT + SELECT - { - guint j; - SqlList * list; - SqlObject * multi = sql_list_get (data->stmts, i); - - g_object_get (multi, "stmts", &list, NULL); - - for (j = 0; j < sql_list_length (list); j++) - if (G_OBJECT_TYPE (sql_list_get (list, j)) == SQL_TYPE_MULTI_STMT) - db_model_process_insert (obj, request, row, err); - } - - db_model_free_operation (obj, op); - i++; - } - - //XXX Iterate both the result list and the queue at the same time - // when the Request has its Results set on errors(future?). - // Currently, if something fails in the plugin's code, it returns NULL - - if (err) - { - while ((op = g_queue_pop_head (data->operations))) - { - op->locked = FALSE; - g_queue_push_tail (priv->operation, op); - } - } - else - g_signal_emit (obj, db_model_signal[OPERATIONS_DONE], 0); - - g_object_unref (request); -} - -// Private helper methods and functions +// Private helper methods and functions static void join_data_free (JoinData * join_data) { @@ -598,18 +624,6 @@ static void join_data_free (JoinData * join_data) g_free (join_data); } -static void db_updated_field_free (DbUpdatedField * u) -{ - if (u && u->value) - { - g_value_unset (u->value); - g_free (u->value); - } - - g_free (u); - u = NULL; -} - static void db_model_free_operation (DbModel * obj, DbOperation * op) { if (op->updated) @@ -633,6 +647,14 @@ static void db_model_request_free (DbModelRequest * req) { if (req) { + DbOperation * op; + + while ((op = g_queue_pop_head (req->operations))) + { + op->locked = FALSE; + g_queue_push_tail (req->obj->priv->operation, op); + } + g_queue_free (req->operations); g_object_unref (req->obj); g_object_unref (req->stmts); @@ -710,6 +732,10 @@ void db_model_reverse_operations (DbModel * obj) while ((op = g_queue_pop_tail (priv->operation))) { + DbIter iter; + iter.data = op->row; + iter.stamp = priv->stamp; + g_hash_table_remove (priv->row_ops, op->row); if (op->type & DB_MODEL_ROW_OP_DELETE) @@ -720,13 +746,7 @@ void db_model_reverse_operations (DbModel * obj) db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (op->row)); } else - { - DbIter iter; - iter.data = op->row; - iter.stamp = priv->stamp; - g_signal_emit (obj, db_model_signal[LINE_TOGGLED], 0, &iter); - } } else if (op->type & DB_MODEL_ROW_OP_INSERT) { @@ -736,14 +756,10 @@ void db_model_reverse_operations (DbModel * obj) else if (op->type & DB_MODEL_ROW_OP_UPDATE) { GSList * n; - DbUpdatedField * u; for (n = op->updated; n; n = n->next) { - DbIter iter; - iter.stamp = priv->stamp; - iter.data = op->row; - u = n->data; + DbUpdatedField * u = n->data; priv->updated_value = g_new0 (GValue, 1); g_value_init (priv->updated_value, G_VALUE_TYPE (u->value)); @@ -1211,15 +1227,15 @@ static void db_model_manage_join (DbModel * obj, DbIter * iter, gint col) select = sql_select_new (); - sql_object_add_child (select, "targets", sql_table_new (other_field->table)); + sql_object_add_child (select, "targets", sql_table_new (other_field->table, NULL)); where = sql_operation_new (SQL_OPERATION_TYPE_AND); for (i = 0; i < priv->result->ncols; i++) if (!g_strcmp0 (priv->column[i].table, other_field->table)) { - sql_object_add_child (select, "exprs", - sql_field_new_with_table (priv->column[i].name, other_field->table, NULL)); + sql_object_add_child (select, "fields", + sql_field_new_with_target (priv->column[i].name, other_field->table, NULL)); } else if (!g_strcmp0 (priv->column[i].table, main_field->table)) { @@ -1230,7 +1246,7 @@ static void db_model_manage_join (DbModel * obj, DbIter * iter, gint col) SqlObject * equal = sql_operation_new (SQL_OPERATION_TYPE_EQUAL); sql_object_add_child (equal, "operators", - sql_field_new_with_table (g_ptr_array_index (other_field->name, j) + sql_field_new_with_target (g_ptr_array_index (other_field->name, j) ,other_field->table, NULL)); sql_object_add_child (equal, "operators", @@ -1299,62 +1315,6 @@ static void db_model_clear (DbModel * obj) } } -// Memory allocate functions - -static void param_def_free (ParamDef * def) -{ - g_object_unref (def->param); - - if (def->equal_op) - { - SqlObject * operators = - sql_object_get (def->obj->priv->link_op, "operators"); - sql_list_remove_item (SQL_LIST (operators), def->equal_op); - } - - g_free (def); -} - -static void db_model_alloc_updatable_data (DbModel * obj) -{ - DbModelPrivate * priv = obj->priv; - - priv->operation = g_queue_new (); - priv->row_ops = g_hash_table_new (g_direct_hash, g_direct_equal); - priv->defaults = g_hash_table_new_full ( - g_str_hash, - g_str_equal, - g_free, - (GDestroyNotify) param_def_free - ); - priv->column_default = g_hash_table_new_full ( - g_str_hash, - g_str_equal, - g_free, - g_free - ); -} - -static void db_model_alloc_link_data (DbModel * obj) -{ - DbModelPrivate * priv = obj->priv; - - if (!priv->internal_batch) - { - SqlList * operators; - - priv->internal_batch = g_object_ref_sink (sql_batch_new ()); - g_signal_connect (priv->internal_batch, "changed", - G_CALLBACK (db_model_on_batch_changed), obj); - - priv->link_op = sql_operation_new (SQL_OPERATION_TYPE_AND); - sql_batch_add (priv->internal_batch, "link", priv->link_op); - - operators = sql_list_new (SQL_TYPE_EXPR); - sql_operation_set_operands (SQL_OPERATION (priv->link_op), operators); - } -} - //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public // Set&Get methods @@ -1437,7 +1397,7 @@ const gchar * db_model_get_column_name (DbModel * obj, gint col) && 0 <= col && col < obj->priv->result->ncols) && obj->priv->column) - return obj->priv->column[col].display; + return obj->priv->column[col].alias; return NULL; } @@ -1673,38 +1633,48 @@ void db_model_set_batch (DbModel * obj, SqlBatch * batch) /** * db_model_set_default_value_from_column: * @obj: a #DbModel - * @field: the field to be set - * @column: field from wich the value is picked + * @field_str: the field to be set + * @column_str: field from wich the value is picked **/ void db_model_set_default_value_from_column (DbModel * obj, - const gchar * field, const gchar * column) + const gchar * field_str, const gchar * column_str) { - g_return_if_fail (DB_IS_MODEL (obj)); - g_return_if_fail (field); - g_return_if_fail (column); + Field * field; + ColumnDef * column_def; - g_hash_table_insert (obj->priv->column_default, g_strdup (field), g_strdup (column)); - g_hash_table_remove (obj->priv->defaults, field); + g_return_if_fail (DB_IS_MODEL (obj)); + g_return_if_fail (field_str); + g_return_if_fail (column_str); + + field = field_new_from_string (field_str); + + column_def = column_def_new (FIELD_DEF, field_new_from_string (column_str)); + g_hash_table_insert (obj->priv->column_defaults, field, column_def); } /** * db_model_set_default_value_from_param: * @obj: a #DbModel - * @field: the field to be set + * @field_str: the field to be set * @param: a #GvnParam * @link: * * Get the default value for @dst_field from @param. **/ void db_model_set_default_value_from_param (DbModel * obj, - const gchar * field, GvnParam * param, gboolean link) + const gchar * field_str, GvnParam * param, gboolean link) { + Field * field; + ParamDef * param_def; + ColumnDef * column_def; SqlObject * equal = NULL; g_return_if_fail (DB_IS_MODEL (obj)); - g_return_if_fail (field); + g_return_if_fail (field_str); g_return_if_fail (GVN_IS_PARAM (param)); + field = field_new_from_string (field_str); + if (link) { SqlList * operands, * link_operands; @@ -1717,18 +1687,18 @@ void db_model_set_default_value_from_param (DbModel * obj, sql_list_add (link_operands, equal); operands = sql_list_new (SQL_TYPE_EXPR); - sql_list_add (operands, sql_field_new (field)); + sql_list_add (operands, sql_field_new_with_target (field->name, field->target, field->schema)); sql_list_add (operands, sql_value_new_with_param (param)); sql_operation_set_operands (SQL_OPERATION (equal), operands); } - ParamDef * def = g_new (ParamDef, 1); - def->param = g_object_ref (param); - def->link = link; - def->equal_op = equal; - def->obj = obj; - g_hash_table_insert (obj->priv->defaults, g_strdup (field), def); - g_hash_table_remove (obj->priv->column_default, field); + param_def = g_new (ParamDef, 1); + param_def->param = g_object_ref (param); + param_def->equal_op = equal; + param_def->link_op = obj->priv->link_op; + + column_def = column_def_new (PARAM_DEF, param_def); + g_hash_table_insert (obj->priv->column_defaults, field, column_def); } /** @@ -1765,7 +1735,11 @@ void db_model_request_main_table (DbModel * obj, const gchar * table) const gchar * db_model_get_main_table (DbModel * obj) { g_return_val_if_fail (DB_IS_MODEL (obj), NULL); - return obj->priv->main_table; + + if (obj->priv->main_table) + return obj->priv->main_table->name; + + return NULL; } /** @@ -2096,17 +2070,31 @@ gboolean db_model_insert (DbModel * obj, DbIter * iter) for (i = 0; i < row->len; i++) { + Field field; + ColumnDef * column_def; const GValue * def_value = NULL; - ParamDef * def = g_hash_table_lookup (priv->defaults, priv->column[i].display); + DbColumn col = priv->column[i]; - if (def) - def_value = gvn_param_get_value (def->param); + field.name = col.name; + field.target = col.table; + field.schema = col.schema; + + column_def = g_hash_table_lookup (priv->column_defaults, &field); + + if (column_def && column_def->type == PARAM_DEF) + { + ParamDef * param_def = column_def->def; + def_value = gvn_param_get_value (param_def->param); + } if (!def_value) - def_value = gvn_param_spec_get_default (priv->column[i].spec); + def_value = gvn_param_spec_get_default (col.spec); if (def_value && G_VALUE_TYPE (def_value) != SQL_TYPE_FUNCTION) - gvn_value_copy (def_value, &row->value[i]); + { + g_value_init (&row->value[i], G_VALUE_TYPE (def_value)); + g_value_copy (def_value, &row->value[i]); + } else g_value_init (&row->value[i], GVN_TYPE_NULL); } @@ -2327,9 +2315,8 @@ gboolean db_model_has_pending_operations (DbModel * obj) } static SqlObject * db_model_create_where (DbModel * obj, - const gchar * table, DbOperation * operation, gboolean for_insert) + Table * table, DbOperation * operation, gboolean for_insert) { - gint i; GSList * l; DbUpdatedField * u; GValue * g_value; @@ -2344,34 +2331,37 @@ 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); - for (i = 0; i < row->len; i++) - if ((priv->column[i].info & DB_COLUMN_PRI_KEY) - && !g_strcmp0 (priv->column[i].table, table)) + TableData * table_data = g_hash_table_lookup (priv->tables, table); + + for (l = table_data->pkeys; l; l = l->next) { SqlObject * equal; SqlList * operands; + gint col = GPOINTER_TO_INT (l->data); value = NULL; - g_value = &row->value[i]; + g_value = &row->value[col]; for (l = operation->updated; l && (u = l->data); l = l->next) - if (u->column == i) + if (u->column == col) { g_value = u->value; break; } - if (gvn_value_is_null (g_value) && for_insert) + if (!gvn_value_is_null (g_value)) { - const GValue * def = gvn_param_spec_get_default (priv->column[i].spec); + value = sql_value_new_with_value (g_value); + } + else if (for_insert) + { + const GValue * def = gvn_param_spec_get_default (priv->column[col].spec); if (def && G_IS_VALUE (def) && G_VALUE_TYPE (def) == SQL_TYPE_FUNCTION) value = g_value_get_object (def); } - else - value = sql_value_new_with_value (g_value); if (!value) { @@ -2383,7 +2373,7 @@ static SqlObject * db_model_create_where (DbModel * obj, sql_list_add (and_operands, equal); operands = sql_list_new (SQL_TYPE_EXPR); - sql_list_add (operands, sql_field_new (priv->column[i].name)); + sql_list_add (operands, sql_field_new (priv->column[col].name)); sql_list_add (operands, value); sql_operation_set_operands (SQL_OPERATION (equal), operands); } @@ -2392,20 +2382,20 @@ static SqlObject * db_model_create_where (DbModel * obj, } static SqlObject * db_model_create_insert (DbModel * obj, - const gchar * table, DbOperation * operation) + Table * table, DbOperation * operation) { gint i; DbModelPrivate * priv = obj->priv; DbRow * row = operation->row; - GValue * value; - SqlList * targets, * stmts, * sets, * fields, * values, * exprs; + const GValue * value; + SqlList * targets, * stmts, * sets, * fields, * values, * select_fields; SqlObject * target, * insert, * set, * select; SqlObject * where = db_model_create_where (obj, table, operation, TRUE); if (!where) return NULL; - target = sql_table_new (table); + target = sql_table_new (table->name, table->schema); fields = sql_list_new (SQL_TYPE_FIELD); @@ -2424,42 +2414,60 @@ static SqlObject * db_model_create_insert (DbModel * obj, ,NULL ); - exprs = sql_list_new (SQL_TYPE_EXPR); + select_fields = sql_list_new (SQL_TYPE_EXPR); targets = sql_list_new (SQL_TYPE_TARGET); sql_list_add (targets, target); select = g_object_new (SQL_TYPE_SELECT - ,"exprs", exprs + ,"fields", select_fields ,"targets", targets ,"where", where ,NULL ); + + GHashTableIter iter; + ColumnDef * column_def; + Field * field; + + g_hash_table_iter_init (&iter, priv->column_defaults); + + while (g_hash_table_iter_next (&iter, (gpointer) &field, (gpointer) &column_def)) + if (!g_strcmp0 (field->target, table->name) + && !g_strcmp0 (field->schema, table->schema)) + { + switch (column_def->type) + { + case PARAM_DEF: + { + ParamDef * param_def = column_def->def; + value = gvn_param_get_value (param_def->param); + break; + } + case FIELD_DEF: + value = NULL; // FIXME + break; + } + + if (value) + { + sql_list_add (fields, sql_field_new (field->name)); + sql_list_add (values, sql_value_new_with_value (value)); + } + } for (i = 0; i < row->len; i++) - if (!g_strcmp0 (priv->column[i].table, table)) + if (table_has_column (table, &priv->column[i])) { - if (gvn_value_is_null (&row->value[i])) - { - gchar * column_def = g_hash_table_lookup (priv->column_default, - priv->column[i].display); - gint col = db_model_get_column_index (obj, column_def); - - if (col != -1) - value = &row->value[col]; - else - value = NULL; - } - else - value = &row->value[i]; + value = &row->value[i]; - if (value) + if (!gvn_value_is_null (value)) { sql_list_add (fields, sql_field_new (priv->column[i].name)); sql_list_add (values, sql_value_new_with_value (value)); } - sql_list_add (exprs, sql_field_new (priv->column[i].name)); + sql_list_add (select_fields, sql_field_new (priv->column[i].name)); } stmts = sql_list_new (SQL_TYPE_STMT); @@ -2482,14 +2490,14 @@ static SqlObject * db_model_create_insert (DbModel * obj, **/ void db_model_perform_operations (DbModel * obj, gboolean retry) { + GList * l; + DbOperation * op; DbModelPrivate * priv; - gboolean error = FALSE; DbRow * row; - DbOperation * op_elem; SqlObject * where; SqlList * stmts; DbRequest * request; - GQueue * req_ops; + gboolean error = FALSE; g_return_if_fail (DB_IS_MODEL (obj)); @@ -2504,80 +2512,83 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) if (!priv->operation->length) return; - - req_ops = g_queue_new (); - stmts = sql_list_new (SQL_TYPE_STMT); + + stmts = sql_list_new (SQL_TYPE_STMT); + g_object_ref_sink (stmts); - while (!error && (op_elem = g_queue_pop_head (priv->operation))) + l = g_queue_peek_head_link (priv->operation); + + for (; l && !error; l = l->next) { SqlObject * stmt = NULL; - op_elem->locked = TRUE; - row = op_elem->row; + op = l->data; + op->locked = TRUE; + row = op->row; - if (op_elem->type & DB_MODEL_ROW_OP_DELETE) // DELETE + if (op->type & DB_MODEL_ROW_OP_DELETE) // DELETE { - if (op_elem->type & DB_MODEL_ROW_OP_INSERT) + if (!(op->type & DB_MODEL_ROW_OP_INSERT)) { - db_model_free_operation (obj, op_elem); - op_elem = NULL; - g_signal_emit (obj, - db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (row)); - } - else if ((where = db_model_create_where (obj, priv->main_table, op_elem, FALSE))) - { - SqlList * targets = sql_list_new (SQL_TYPE_TARGET); - sql_list_add (targets, sql_table_new (priv->main_table)); + where = db_model_create_where (obj, priv->main_table, op, FALSE); - stmt = g_object_new (SQL_TYPE_DELETE - ,"where", where - ,"targets", targets - ,NULL - ); + if (where) + { + SqlList * targets = sql_list_new (SQL_TYPE_TARGET); + sql_list_add (targets, sql_table_new ( + priv->main_table->name, + priv->main_table->schema + )); + + stmt = g_object_new (SQL_TYPE_DELETE + ,"where", where + ,"targets", targets + ,NULL + ); + } + else + error = TRUE; } - else - error = TRUE; } - else if (op_elem->type & DB_MODEL_ROW_OP_INSERT) // INSERT + SELECT + else if (op->type & DB_MODEL_ROW_OP_INSERT) // INSERT + SELECT { - stmt = db_model_create_insert (obj, priv->main_table, op_elem); + stmt = db_model_create_insert (obj, priv->main_table, op); if (!stmt) error = TRUE; } - else if (op_elem->type & DB_MODEL_ROW_OP_UPDATE) // UPDATE || INSERT + SELECT + else if (op->type & DB_MODEL_ROW_OP_UPDATE) // UPDATE || INSERT + SELECT { - GSList * l; + Table * table; GHashTableIter iter; - gpointer table; SqlList * update_list; - - GHashTable * tables = g_hash_table_new ( - g_str_hash, g_str_equal); - - for (l = op_elem->updated; l; l = l->next) - { - DbUpdatedField * u = l->data; - g_hash_table_add (tables, priv->column[u->column].table); - } - + update_list = sql_list_new (SQL_TYPE_STMT); - g_hash_table_iter_init (&iter, tables); + g_hash_table_iter_init (&iter, priv->tables); - while (g_hash_table_iter_next (&iter, &table, NULL)) + while (g_hash_table_iter_next (&iter, (gpointer) &table, NULL)) { - where = db_model_create_where (obj, priv->main_table, op_elem, FALSE); + GSList * l; + DbUpdatedField * u; + GSList * fields = NULL; + + for (l = op->updated; l && (u = l->data); l = l->next) + if (table_has_column (table, &priv->column[u->column])) + fields = g_slist_prepend (fields, u); + + if (!fields) + continue; + + where = db_model_create_where (obj, table, op, FALSE); if (where) { - DbUpdatedField * u; SqlList * sets = sql_list_new (SQL_TYPE_UPDATE_SET); SqlList * targets = sql_list_new (SQL_TYPE_TARGET); - sql_list_add (targets, sql_table_new (table)); + sql_list_add (targets, sql_table_new (table->name, table->schema)); - for (l = op_elem->updated; l && (u = l->data); l = l->next) - if (!g_strcmp0 (priv->column[u->column].table, table)) + for (l = fields; l && (u = l->data); l = l->next) { GValue * new_value = DB_ROW_FIELD (row, u->column); @@ -2597,30 +2608,33 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) } else { - SqlObject * insert = db_model_create_insert (obj, table, op_elem); + SqlObject * insert = db_model_create_insert (obj, table, op); if (insert) sql_list_add (update_list, insert); } + + g_slist_free (fields); } - - g_hash_table_destroy (tables); + stmt = g_object_new (SQL_TYPE_MULTI_STMT, "stmts", update_list, NULL); } if (stmt) sql_list_add (stmts, stmt); - if (op_elem) - g_queue_push_tail (req_ops, op_elem); } - if (sql_list_length (stmts) > 0) + if (sql_list_length (stmts) > 0 && !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))) + g_queue_push_tail (ops, op); DbModelRequest * data = g_new (DbModelRequest, 1); data->obj = g_object_ref (obj); - data->operations = req_ops; + data->operations = ops; data->stmts = g_object_ref_sink (stmts); request = db_conn_query_with_stmt_async (priv->conn @@ -2633,11 +2647,9 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) db_model_add_pending_request (obj, request); } else - { - g_queue_free (req_ops); - g_object_unref (g_object_ref_sink (stmts)); - db_model_clean_operations (obj); - } + g_warning ("DbModel: Error performing operations"); + + g_object_unref (stmts); } /** @@ -2649,34 +2661,38 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) void db_model_refresh (DbModel * obj) { DbModelPrivate * priv; + gboolean is_ready = FALSE; g_return_if_fail (DB_IS_MODEL (obj)); priv = obj->priv; db_model_clear (obj); - if (priv->conn - && priv->stmt && sql_object_is_ready (SQL_OBJECT (priv->stmt)) - && (!priv->batch || sql_batch_is_ready (priv->batch)) - && (!priv->internal_batch || sql_batch_is_ready (priv->internal_batch))) + if (priv->conn && priv->stmt) { SqlBatch * tmp_batch = sql_batch_new (); + sql_object_get_holders (SQL_OBJECT (priv->stmt), tmp_batch); sql_batch_merge (tmp_batch, priv->batch); - sql_batch_merge (tmp_batch, priv->internal_batch); - - db_model_set_status (obj, DB_MODEL_STATUS_LOADING); + sql_batch_merge (tmp_batch, priv->internal_batch); + + if (sql_batch_is_ready (tmp_batch)) + { + is_ready = TRUE; + db_model_set_status (obj, DB_MODEL_STATUS_LOADING); - priv->request = db_conn_query_with_stmt_async (priv->conn - ,priv->stmt - ,tmp_batch - ,(DbRequestDoneCallback) db_model_on_data_ready - ,g_object_ref (obj) - ,(GDestroyNotify) g_object_unref - ); + priv->request = db_conn_query_with_stmt_async (priv->conn + ,priv->stmt + ,tmp_batch + ,(DbRequestDoneCallback) db_model_on_data_ready + ,g_object_ref (obj) + ,(GDestroyNotify) g_object_unref + ); - g_object_unref (g_object_ref_sink (tmp_batch)); + g_object_unref (g_object_ref_sink (tmp_batch)); + } } - else + + if (!is_ready) db_model_set_status (obj, DB_MODEL_STATUS_CLEAN); } @@ -2991,7 +3007,7 @@ static void db_model_get_property (DbModel * obj, guint property_id, g_value_set_boolean (value, obj->priv->use_file); break; case PROP_MAIN_TABLE: - g_value_set_string (value, obj->priv->main_table); + g_value_set_string (value, db_model_get_main_table (obj)); break; case PROP_UPDATE_FLAGS: g_value_set_flags (value, obj->priv->update_flags); @@ -3014,8 +3030,6 @@ static void db_model_init (DbModel *obj) priv->stmt = NULL; priv->use_file = FALSE; priv->sql = NULL; - priv->update_flags = 0; - priv->user_update_flags = DB_MODEL_ALL; priv->request = NULL; priv->status = DB_MODEL_STATUS_CLEAN; priv->mode = DB_MODEL_MODE_ON_CHANGE; @@ -3023,22 +3037,12 @@ static void db_model_init (DbModel *obj) priv->result_pos = 0; priv->data = NULL; priv->column = NULL; - priv->column_index = NULL; - - priv->link_op = NULL; - priv->internal_batch = NULL; - - priv->main_table = NULL; - priv->user_main_table = NULL; - priv->defaults = NULL; - priv->column_default = NULL; - priv->operation = NULL; - priv->row_ops = NULL; - priv->join = NULL; - priv->pending_request = NULL; - - // TODO: Call this method only when is necessary - db_model_alloc_updatable_data (obj); + priv->column_index = g_hash_table_new_full ( + g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL + ); priv->stamp = g_random_int (); @@ -3047,6 +3051,21 @@ static void db_model_init (DbModel *obj) priv->default_sort_data = NULL; priv->default_sort_func = NULL; priv->default_sort_destroy = NULL; + + priv->link_op = NULL; + priv->internal_batch = NULL; + + 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; + priv->pending_request = NULL; + priv->tables = NULL; } static void db_model_finalize (DbModel * obj) @@ -3058,25 +3077,22 @@ static void db_model_finalize (DbModel * obj) g_clear_object (&priv->conn); g_clear_object (&priv->stmt); - - if (priv->join) - g_slist_free_full (priv->join, (GDestroyNotify) db_join_free); - - g_hash_table_destroy (priv->row_ops); - g_queue_free (priv->operation); - g_free (priv->sql); - g_free (priv->main_table); - g_free (priv->user_main_table); - - if (priv->column_index) - g_hash_table_destroy (priv->column_index); - + g_hash_table_destroy (priv->column_index); db_model_set_batch (obj, NULL); + g_clear_object (&priv->link_op); g_clear_object (&priv->internal_batch); - g_hash_table_destroy (priv->defaults); - g_hash_table_destroy (priv->column_default); + + 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); + } parent->finalize (G_OBJECT (obj)); } diff --git a/db/db-result.c b/db/db-result.c index 68ff801..2e89d9d 100644 --- a/db/db-result.c +++ b/db/db-result.c @@ -73,7 +73,7 @@ DbResult * db_result_copy (const DbResult * obj) result->column[n].spec = gvn_param_spec_copy (obj->column[n].spec); result->column[n].table = g_strdup (obj->column[n].table); result->column[n].name = g_strdup (obj->column[n].name); - result->column[n].display = g_strdup (obj->column[n].display); + result->column[n].alias = g_strdup (obj->column[n].alias); } for (n = 0; n < obj->nrows; n++) @@ -105,7 +105,7 @@ void db_result_free (DbResult * obj) DbColumn col = obj->column[i]; gvn_param_spec_free (col.spec); g_free (col.name); - g_free (col.display); + g_free (col.alias); g_free (col.table); } diff --git a/db/db-result.h b/db/db-result.h index 1bf95e8..6c9be48 100644 --- a/db/db-result.h +++ b/db/db-result.h @@ -71,10 +71,11 @@ struct _DbColumn { DbColumnInfo info; GvnParamSpec * spec; + gchar * schema; gchar * table; gchar * table_alias; gchar * name; - gchar * display; + gchar * alias; }; GType db_result_get_type (); diff --git a/plugin/mysql/db-mysql.c b/plugin/mysql/db-mysql.c index 37be7ff..86bed77 100644 --- a/plugin/mysql/db-mysql.c +++ b/plugin/mysql/db-mysql.c @@ -226,7 +226,7 @@ static DbResultSet * db_mysql_query (DbMysql * obj, const gchar * sql, GError ** column = &result->column[i]; column->info = 0; column->name = g_strdup (field[i].org_name); - column->display = g_strdup (field[i].name); + column->alias = g_strdup (field[i].name); column->table = g_strdup (field[i].org_table); column->table_alias = g_strdup (field[i].table); diff --git a/plugin/pg/db-pg.c b/plugin/pg/db-pg.c index c704fd0..c05d82e 100644 --- a/plugin/pg/db-pg.c +++ b/plugin/pg/db-pg.c @@ -647,7 +647,7 @@ static DbResultSet * __db_pg_query else r->column[j].name = fname; - r->column[j].display = g_strdup (r->column[j].name); + r->column[j].alias = g_strdup (r->column[j].name); r->column[j].table = g_strdup (""); r->column[j].spec = gvn_param_spec_new_with_attrs (((GType*) g_ptr_array_index (types, ind))[j] @@ -676,7 +676,7 @@ static DbResultSet * __db_pg_query fdisp = g_ptr_array_index (name_array, j); r->column[j].name = g_strdup (fname); - r->column[j].display = g_strdup (fdisp); + r->column[j].alias = g_strdup (fdisp); // Getting the default value from res_col //FIXME use the parser if (!PQgetisnull (res_col, ctup, 3)) diff --git a/sql/parser/gram.y b/sql/parser/gram.y index 75a367b..c44b0e1 100644 --- a/sql/parser/gram.y +++ b/sql/parser/gram.y @@ -386,7 +386,7 @@ join(A) ::= target(left) join_type(type) target(right) join_cond(condition). SQL_TABLE (right)->schema : NULL; sql_list_add (equal, - sql_field_new_with_table (SQL_FIELD (n->data)->name, target, schema)); + sql_field_new_with_target (SQL_FIELD (n->data)->name, target, schema)); sql_list_add (exprs, op); } diff --git a/sql/parser/scan.rl b/sql/parser/scan.rl index 8b96bc1..6f16392 100644 --- a/sql/parser/scan.rl +++ b/sql/parser/scan.rl @@ -261,3 +261,45 @@ 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-batch.c b/sql/sql-batch.c index 91e2ac1..4436b2c 100644 --- a/sql/sql-batch.c +++ b/sql/sql-batch.c @@ -41,16 +41,16 @@ SqlBatch * sql_batch_new () //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private -static void sql_batch_child_changed (SqlObject * child, SqlBatch * obj) +static void sql_batch_item_changed (SqlObject * item, SqlBatch * obj) { sql_batch_changed (obj); } -static void sql_batch_free_child (SqlBatch * obj, SqlObject * child) +static void sql_batch_free_item (SqlBatch * obj, SqlObject * item) { - g_signal_handlers_disconnect_by_func (child, - sql_batch_child_changed, obj); - g_object_unref (child); + g_signal_handlers_disconnect_by_func (item, + sql_batch_item_changed, obj); + g_object_unref (item); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public @@ -65,22 +65,18 @@ static void sql_batch_free_child (SqlBatch * obj, SqlObject * child) **/ gboolean sql_batch_is_ready (SqlBatch * obj) { - gboolean is_ready = TRUE; + gpointer item; + GHashTableIter iter; g_return_val_if_fail (SQL_IS_BATCH (obj), FALSE); - if (obj->items) - { - GList * i; - GList * items = g_hash_table_get_values (obj->items); - - for (i = items; i && is_ready; i = i->next) - is_ready = sql_object_is_ready (i->data); - - g_list_free (items); - } + g_hash_table_iter_init (&iter, obj->items); - return is_ready; + while (g_hash_table_iter_next (&iter, NULL, &item)) + if (!item || !sql_object_is_ready (item)) + return FALSE; + + return TRUE; } /** @@ -107,29 +103,26 @@ SqlObject * sql_batch_get (SqlBatch * obj, const gchar * id) * sql_batch_add: * @obj: a #SqlBatch * @id: the id of the #SqlHolder - * @held_object: the held object + * @item: the #SqlObject * - * Adds a held object. + * Adds a new item to the batch. **/ -void sql_batch_add (SqlBatch * obj, const gchar * id, SqlObject * object) +void sql_batch_add (SqlBatch * obj, const gchar * id, SqlObject * item) { g_return_if_fail (SQL_IS_BATCH (obj)); g_return_if_fail (id); + g_return_if_fail (SQL_IS_OBJECT (item) || !item); sql_batch_remove (obj, id); - if (!obj->items) - obj->items = g_hash_table_new_full ( - g_str_hash - ,g_str_equal - ,g_free - ,NULL - ); - - g_signal_connect (object, "changed", - G_CALLBACK (sql_batch_child_changed), obj); - g_hash_table_replace (obj->items, - g_strdup (id), g_object_ref_sink (object)); + if (item) + { + g_object_ref_sink (item); + g_signal_connect (item, "changed", + G_CALLBACK (sql_batch_item_changed), obj); + } + + g_hash_table_replace (obj->items, g_strdup (id), item); } /** @@ -143,10 +136,7 @@ void sql_batch_add_from_param (SqlBatch * obj, const gchar * id, GvnParam * para g_return_if_fail (id); g_return_if_fail (GVN_IS_PARAM (param)); - SqlObject * value = sql_value_new (); - sql_value_set_param (SQL_VALUE (value), param); - sql_batch_add (obj, id, value); - g_object_unref (value); + sql_batch_add (obj, id, sql_value_new_with_param (param)); } /** @@ -160,13 +150,8 @@ void sql_batch_add_from_value (SqlBatch * obj, const gchar * id, GType type, gpo g_return_if_fail (id); GValue gvalue = {0}; - SqlObject * value; - gvn_value_new_with_content (&gvalue, type, content); - value = sql_value_new (); - sql_value_set_value (SQL_VALUE (value), &gvalue); - sql_batch_add (obj, id, value); - g_object_unref (value); + sql_batch_add (obj, id, sql_value_new_with_value (&gvalue)); g_value_unset (&gvalue); } @@ -182,11 +167,11 @@ void sql_batch_remove (SqlBatch * obj, const gchar * id) g_return_val_if_fail (SQL_IS_BATCH (obj), NULL); g_return_val_if_fail (id, NULL); - SqlObject * child = sql_batch_get (obj, id); + SqlObject * item = sql_batch_get (obj, id); - if (child) + if (item) { - sql_batch_free_child (obj, child); + sql_batch_free_item (obj, item); g_hash_table_remove (obj->items, id); } } @@ -232,23 +217,25 @@ void sql_batch_changed (SqlBatch * obj) static void sql_batch_init (SqlBatch * obj) { - obj->items = NULL; + obj->items = g_hash_table_new_full ( + g_str_hash + ,g_str_equal + ,g_free + ,NULL + ); } static void sql_batch_finalize (SqlBatch * obj) { - if (obj->items) - { - GHashTableIter iter; - gpointer child; + gpointer item; + GHashTableIter iter; - g_hash_table_iter_init (&iter, obj->items); + g_hash_table_iter_init (&iter, obj->items); - while (g_hash_table_iter_next (&iter, NULL, &child)) - sql_batch_free_child (obj, child); - - g_hash_table_destroy (obj->items); - } + while (g_hash_table_iter_next (&iter, NULL, &item)) + sql_batch_free_item (obj, item); + + g_hash_table_destroy (obj->items); G_OBJECT_CLASS (sql_batch_parent_class)->finalize (G_OBJECT (obj)); } diff --git a/sql/sql-delete.c b/sql/sql-delete.c index 12521c0..a58e946 100644 --- a/sql/sql-delete.c +++ b/sql/sql-delete.c @@ -36,7 +36,7 @@ SqlObject * sql_delete_new () static void sql_delete_render (SqlDelete * obj, SqlRender * render) { sql_render_add_token (render, "DELETE"); - sql_render_add_list (render, TRUE, NULL, obj->tables, ","); + sql_render_add_list (render, FALSE, NULL, obj->tables, ","); if (SQL_DML (obj)->targets) { diff --git a/sql/sql-field.c b/sql/sql-field.c index f07b612..f7a05d0 100644 --- a/sql/sql-field.c +++ b/sql/sql-field.c @@ -52,7 +52,7 @@ SqlObject * sql_field_new (const gchar * name) * * Return value: an #SqlExpr */ -SqlObject * sql_field_new_with_table (const gchar * name, const gchar * target, const gchar * schema) +SqlObject * sql_field_new_with_target (const gchar * name, const gchar * target, const gchar * schema) { return g_object_new (SQL_TYPE_FIELD ,"name", name @@ -64,38 +64,102 @@ SqlObject * sql_field_new_with_table (const gchar * name, const gchar * target, //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private -static void sql_field_render (SqlField * obj, SqlRender * render) +static void sql_field_render (SqlField * self, SqlRender * render) { - if (obj->target) + if (self->target) { - if (obj->schema) + if (self->schema) { - sql_render_add_identifier (render, obj->schema); + sql_render_add_identifier (render, self->schema); sql_render_append (render, "."); } - sql_render_add_identifier (render, obj->target); + sql_render_add_identifier (render, self->target); sql_render_append (render, "."); } - if (!g_strcmp0 (obj->name, "*")) + if (!g_strcmp0 (self->name, "*")) { sql_render_add_espace (render); sql_render_append (render, "*"); } else - sql_render_add_identifier (render, obj->name); + sql_render_add_identifier (render, self->name); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public -void sql_field_set_name (SqlField * obj, const gchar * name) +/** + * sql_field_get_name: + * @self: the #SqlField + * + * Return value: the field name + **/ +const gchar * sql_field_get_name (SqlField * self) { - g_return_if_fail (SQL_IS_FIELD (obj)); + return self->name; +} + +/** + * sql_field_set_name: + * @self: the #SqlField + * @name: the field name + **/ +void sql_field_set_name (SqlField * self, const gchar * name) +{ + g_return_if_fail (SQL_IS_FIELD (self)); g_return_if_fail (name); - g_free (obj->name); - obj->name = g_strdup (name); + g_free (self->name); + self->name = g_strdup (name); +} + +/** + * sql_field_get_target: + * @self: the #SqlField + * + * Return value: the target name + **/ +const gchar * sql_field_get_target (SqlField * self) +{ + return self->target; +} + +/** + * sql_field_set_target: + * @self: the #SqlField + * @target: the target name + **/ +void sql_field_set_target (SqlField * self, const gchar * target) +{ + g_return_if_fail (SQL_IS_FIELD (self)); + + g_free (self->target); + self->target = g_strdup (target); +} + +/** + * sql_field_get_schema: + * @self: the #SqlField + * + * Return value: the schema name + **/ +const gchar * sql_field_get_schema (SqlField * self) +{ + return self->schema; +} + +/** + * sql_field_set_schema: + * @self: the #SqlField + * @schema: the schema name + **/ +void sql_field_set_schema (SqlField * self, const gchar * schema) +{ + g_return_if_fail (SQL_IS_FIELD (self)); + + g_free (self->schema); + self->schema = g_strdup (schema); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties @@ -107,61 +171,59 @@ enum ,PROP_SCHEMA }; -static void sql_field_set_property (SqlField * obj, guint id, +static void sql_field_set_property (SqlField * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_NAME: - sql_field_set_name (obj, g_value_get_string (value)); + sql_field_set_name (self, g_value_get_string (value)); break; case PROP_TARGET: - g_free (obj->target); - obj->target = g_value_dup_string (value); + sql_field_set_target (self, g_value_get_string (value)); break; case PROP_SCHEMA: - g_free (obj->schema); - obj->schema = g_value_dup_string (value); + sql_field_set_schema (self, g_value_get_string (value)); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } -static void sql_field_get_property (SqlField * obj, guint id, +static void sql_field_get_property (SqlField * self, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_NAME: - g_value_set_string (value, obj->name); + g_value_set_string (value, self->name); break; case PROP_TARGET: - g_value_set_string (value, obj->target); + g_value_set_string (value, self->target); break; case PROP_SCHEMA: - g_value_set_string (value, obj->schema); + g_value_set_string (value, self->schema); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class -static void sql_field_init (SqlField * obj) +static void sql_field_init (SqlField * self) { - obj->name = NULL; - obj->target = NULL; - obj->schema = NULL; + self->name = NULL; + self->target = NULL; + self->schema = NULL; } -static void sql_field_finalize (SqlField * obj) +static void sql_field_finalize (SqlField * self) { - g_free (obj->name); - g_free (obj->target); - g_free (obj->schema); - G_OBJECT_CLASS (sql_field_parent_class)->finalize (G_OBJECT (obj)); + g_free (self->name); + g_free (self->target); + g_free (self->schema); + G_OBJECT_CLASS (sql_field_parent_class)->finalize (G_OBJECT (self)); } static void sql_field_class_init (SqlFieldClass * klass) diff --git a/sql/sql-field.h b/sql/sql-field.h index c01723d..f21e85b 100644 --- a/sql/sql-field.h +++ b/sql/sql-field.h @@ -42,11 +42,17 @@ struct _SqlFieldClass SqlExprClass parent; }; -GType sql_field_get_type (); -SqlObject * sql_field_new (const gchar * name); -SqlObject * sql_field_new_with_table (const gchar * name - ,const gchar * target - ,const gchar * schema); -void sql_field_set_name (SqlField * obj, const gchar * name); +GType sql_field_get_type (); +SqlObject * sql_field_new (const gchar * name); +SqlObject * sql_field_new_with_target (const gchar * name + ,const gchar * target + ,const gchar * schema); + +const gchar * sql_field_get_name (SqlField * self); +void sql_field_set_name (SqlField * obj, const gchar * name); +const gchar * sql_field_get_target (SqlField * self); +void sql_field_set_target (SqlField * obj, const gchar * target); +const gchar * sql_field_get_schema (SqlField * self); +void sql_field_set_schema (SqlField * obj, const gchar * schema); #endif diff --git a/sql/sql-holder.c b/sql/sql-holder.c index 0fe13d8..36df2a5 100644 --- a/sql/sql-holder.c +++ b/sql/sql-holder.c @@ -41,9 +41,9 @@ static void sql_holder_render (SqlHolder * obj, SqlRender * render, SqlBatch * b sql_render_printf (render, "#%s", obj->id); } -static void sql_holder_find_holders (SqlHolder * obj, GQueue * holders) +static void sql_holder_find_holders (SqlHolder * obj, SqlBatch * batch) { - g_queue_push_tail (holders, obj->id); + sql_batch_add (batch, obj->id, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public diff --git a/sql/sql-insert.c b/sql/sql-insert.c index 1a6f7be..9675184 100644 --- a/sql/sql-insert.c +++ b/sql/sql-insert.c @@ -39,13 +39,14 @@ static void sql_insert_render (SqlInsert * obj, SqlRender * render) if (obj->table) { - if (obj->values) + if (obj->fields && sql_list_length (obj->fields) > 0) { sql_render_add_espace (render); sql_render_append (render, "("); sql_render_add_list (render, FALSE, NULL, obj->fields, ","); sql_render_append (render, ")"); sql_render_add_token (render, "VALUES"); + sql_render_add_espace (render); sql_render_add_list (render, FALSE, NULL, obj->values, ","); } else @@ -61,7 +62,7 @@ void sql_insert_set_table_from_name (SqlInsert * obj, const gchar * table) g_return_if_fail (table); sql_object_remove (obj, obj->table); - obj->table = sql_object_add (obj, sql_table_new (table)); + obj->table = sql_object_add (obj, sql_table_new (table, NULL)); } void sql_insert_add_expr (SqlInsert * obj, SqlExpr * expr) diff --git a/sql/sql-list.c b/sql/sql-list.c index 664e240..c935619 100644 --- a/sql/sql-list.c +++ b/sql/sql-list.c @@ -70,12 +70,12 @@ static gboolean sql_list_is_ready (SqlList * obj) return TRUE; } -static void sql_list_find_holders (SqlList * obj, GQueue * holders) +static void sql_list_find_holders (SqlList * obj, SqlBatch * batch) { GList * i; for (i = obj->items.head; i; i = i->next) - sql_object_get_holders (i->data, holders); + sql_object_get_holders (i->data, batch); } static void sql_list_item_changed (SqlObject * item, SqlObject * obj) diff --git a/sql/sql-object.c b/sql/sql-object.c index 9d8673c..9590887 100644 --- a/sql/sql-object.c +++ b/sql/sql-object.c @@ -41,7 +41,7 @@ static void sql_object_child_changed (SqlObject * child, SqlObject * obj) sql_object_changed (obj); } -static void sql_object_find_holders (SqlObject * obj, GQueue * holders) +static void sql_object_find_holders (SqlObject * obj, SqlBatch * batch) { guint i; guint nparams; @@ -52,8 +52,12 @@ static void sql_object_find_holders (SqlObject * obj, GQueue * holders) for (i = 0; i < nparams; i++) if (SQL_IS_PARAM_OBJECT (params[i]) || SQL_IS_PARAM_LIST (params[i])) { - SqlObject * child = sql_object_get (obj, params[i]->name); - sql_object_get_holders (child, holders); + SqlObject * child; + + g_object_get (obj, params[i]->name, &child, NULL); + + if (child) + sql_object_get_holders (child, batch); } g_free (params); @@ -131,17 +135,19 @@ gboolean sql_object_is_ready (SqlObject * obj) guint nparams; GParamSpec ** params; gboolean is_ready = TRUE; - SqlObjectClass * klass = SQL_OBJECT_GET_CLASS (obj); + SqlObjectClass * klass; g_return_val_if_fail (SQL_IS_OBJECT (obj), FALSE); - - params = g_object_class_list_properties (G_OBJECT_GET_CLASS (obj), &nparams); + + klass = SQL_OBJECT_GET_CLASS (obj); + params = g_object_class_list_properties (G_OBJECT_CLASS (klass), &nparams); for (i = 0; i < nparams && is_ready; i++) if (SQL_IS_PARAM_OBJECT (params[i]) || SQL_IS_PARAM_LIST (params[i])) { - SqlObject * child = sql_object_get (obj, params[i]->name); - is_ready = sql_object_is_ready (child); + SqlObject * child; + g_object_get (obj, params[i]->name, &child, NULL); + is_ready = !child || sql_object_is_ready (child); } g_free (params); @@ -199,12 +205,12 @@ void sql_object_remove_child (SqlObject * obj, const gchar * property, guint n) * * Gets all identifiers of the contained holders. **/ -void sql_object_get_holders (SqlObject * obj, GQueue * holders) +void sql_object_get_holders (SqlObject * obj, SqlBatch * batch) { - g_return_if_fail (SQL_IS_OBJECT (obj) || !obj); + g_return_if_fail (SQL_IS_OBJECT (obj)); + g_return_if_fail (SQL_IS_BATCH (batch)); - if (obj) - SQL_OBJECT_GET_CLASS (obj)->find_holders (obj, holders); + SQL_OBJECT_GET_CLASS (obj)->find_holders (obj, batch); } /** diff --git a/sql/sql-object.h b/sql/sql-object.h index 7016168..4d71bd4 100644 --- a/sql/sql-object.h +++ b/sql/sql-object.h @@ -32,7 +32,7 @@ typedef struct _SqlObject SqlObject; typedef struct _SqlObjectClass SqlObjectClass; typedef gboolean (* SqlObjectIsReadyFunc) (SqlObject * obj); -typedef void (* SqlObjectFindHoldersFunc) (SqlObject * obj, GQueue * holders); +typedef void (* SqlObjectFindHoldersFunc) (); // (SqlObject * obj, SqlBatch * holders); typedef void (* SqlRenderFunc) (); // (SqlObject * obj, SqlRender * render, SqlBatch * batch); struct _SqlObject @@ -55,7 +55,7 @@ struct _SqlObjectClass GType sql_object_get_type (); void sql_object_render (SqlObject * obj, SqlRender * render, SqlBatch * batch); gboolean sql_object_is_ready (SqlObject * obj); -void sql_object_get_holders (SqlObject * obj, GQueue * holders); +void sql_object_get_holders (SqlObject * obj, SqlBatch * batch); void sql_object_set (SqlObject * obj, const gchar * property, SqlObject * set); SqlObject * sql_object_get (SqlObject * obj, const gchar * property); diff --git a/sql/sql-parser.h b/sql/sql-parser.h index 9c68dd2..afccf3a 100644 --- a/sql/sql-parser.h +++ b/sql/sql-parser.h @@ -19,6 +19,7 @@ #define SQL_PARSER_H #include "sql-object.h" +#include "sql-field.h" #define SQL_PARSER_LOG_DOMAIN (g_quark_from_string ("SqlParser")) @@ -30,6 +31,8 @@ * * Return value: (transfer full): an #SqlObject. */ -SqlObject * sql_parser_parse (gchar * sql) G_GNUC_WARN_UNUSED_RESULT; +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 diff --git a/sql/sql-render.c b/sql/sql-render.c index 604286e..0bfdedb 100644 --- a/sql/sql-render.c +++ b/sql/sql-render.c @@ -308,7 +308,7 @@ void sql_render_add_list (SqlRender * obj, gboolean required, const gchar * toke SqlList * list, const gchar * separator) { g_return_if_fail (SQL_IS_RENDER (obj)); - g_return_if_fail (SQL_IS_LIST (list)); + g_return_if_fail (SQL_IS_LIST (list) || !list); sql_render_add_list_with_func (obj, required, token, list, separator, NULL); } @@ -330,7 +330,7 @@ void sql_render_add_list_with_func (SqlRender * obj, gboolean required, const gc GList * i; g_return_if_fail (SQL_IS_RENDER (obj)); - g_return_if_fail (SQL_IS_LIST (list)); + g_return_if_fail (SQL_IS_LIST (list) || !list); if (list && (i = sql_list_get_items (list))) { diff --git a/sql/sql-set.c b/sql/sql-set.c index 486da18..3f2a8f7 100644 --- a/sql/sql-set.c +++ b/sql/sql-set.c @@ -33,11 +33,6 @@ SqlObject * sql_set_new () static void sql_set_render (SqlSet * obj, SqlRender * render) { -/* if (obj) - sql_render_add_object (render, obj); - else - sql_render_add_token (render, "DEFAULT"); -*/ sql_render_append (render, "("); sql_render_add_list (render, FALSE, NULL, obj->exprs, ","); sql_render_append (render, ")"); diff --git a/sql/sql-string.c b/sql/sql-string.c index 12a2b00..470f345 100644 --- a/sql/sql-string.c +++ b/sql/sql-string.c @@ -59,12 +59,12 @@ static void sql_string_render (SqlString * obj, SqlRender * render) sql_render_append (render, ptr); } -static void sql_string_find_holders (SqlString * obj, GQueue * holders) +static void sql_string_find_holders (SqlString * obj, SqlBatch * batch) { GSList * i; for (i = obj->holders; i; i = i->next) - sql_object_get_holders (((HolderData *) i->data)->holder, holders); + sql_object_get_holders (((HolderData *) i->data)->holder, batch); } static void sql_string_free_holder_data (HolderData * holder_data) diff --git a/sql/sql-table.c b/sql/sql-table.c index af81713..e03e223 100644 --- a/sql/sql-table.c +++ b/sql/sql-table.c @@ -26,9 +26,9 @@ **/ G_DEFINE_TYPE (SqlTable, sql_table, SQL_TYPE_TARGET); -SqlObject * sql_table_new (const gchar * name) +SqlObject * sql_table_new (const gchar * name, const gchar * schema) { - return g_object_new (SQL_TYPE_TABLE, "name", name, NULL); + return g_object_new (SQL_TYPE_TABLE, "name", name, "schema", schema, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private diff --git a/sql/sql-table.h b/sql/sql-table.h index 9544872..ed7f5b6 100644 --- a/sql/sql-table.h +++ b/sql/sql-table.h @@ -41,6 +41,6 @@ struct _SqlTableClass }; GType sql_table_get_type (); -SqlObject * sql_table_new (const gchar * name); +SqlObject * sql_table_new (const gchar * name, const gchar * schema); #endif