diff --git a/db/db-model-private.c b/db/db-model-private.c index 5595d18..b9bd08a 100644 --- a/db/db-model-private.c +++ b/db/db-model-private.c @@ -17,6 +17,8 @@ * along with this program. If not, see . */ +#define remove_delimiters(str) (g_strdup (g_strstrip (g_strdelimit (str, "`\"", ' ')))) + /* * DbUpdatedField: * @column: the position of the field in the row @@ -80,6 +82,41 @@ typedef struct } DbModelRequest; +//----------------------------------------------- Table + +typedef struct +{ + gchar * name; + gchar * schema; +} +Table; + +static Table * table_copy (Table * src) +{ + Table * table = g_new0 (Table, 1); + table->name = g_strdup (src->name); + table->schema = g_strdup (src->schema); + return table; +} + +static void table_free (Table * table) +{ + g_free (table->name); + g_free (table->schema); + g_free (table); +} + +static gboolean table_equal (const Table * a, const Table * b) +{ + return !g_strcmp0 (a->name, b->name) + && !g_strcmp0 (a->schema, b->schema); +} + +static guint table_hash (const Table * table) +{ + return g_str_hash (table->name); +} + //----------------------------------------------- Field typedef struct @@ -90,8 +127,6 @@ typedef struct } Field; -#define remove_delimiters(str) (g_strdup (g_strstrip (g_strdelimit (str, "`\"", ' ')))) - static void field_parse (Field * field, const gchar * string) { gchar ** split = g_strsplit (string, ".", 0); @@ -136,133 +171,61 @@ static guint field_hash (const Field * field) return g_str_hash (field->name); } -//----------------------------------------------- Table +//----------------------------------------------- TableInfo typedef struct { gchar * name; gchar * schema; -} -Table; - -static void table_parse (Table * table, const gchar * string) -{ - gchar ** split = g_strsplit (string, ".", 0); - guint len = g_strv_length (split); - - table->name = len > 0 ? remove_delimiters (split[--len]) : NULL; - table->schema = len > 0 ? remove_delimiters (split[--len]) : NULL; - - g_strfreev (split); -} - -static Table * table_copy (Table * src) -{ - Table * table = g_new0 (Table, 1); - table->name = g_strdup (src->name); - table->schema = g_strdup (src->schema); - return table; -} - -static void table_free (Table * table) -{ - g_free (table->name); - g_free (table->schema); - g_free (table); -} - -static gboolean table_equal (const Table * a, const Table * b) -{ - return !g_strcmp0 (a->name, b->name) - && !g_strcmp0 (a->schema, b->schema); -} - -static guint table_hash (const Table * table) -{ - return g_str_hash (table->name); -} - -static gboolean table_has_column (Table * table, DbColumn * column) -{ - return !g_strcmp0 (column->table, table->name) - && !g_strcmp0 (column->schema, table->schema); -} - -//----------------------------------------------- TableData - -typedef struct -{ + gchar * alias; GSList * pkeys; + GHashTable * columns; + GSList * parent_columns; + GSList * child_columns; } -TableData; +TableInfo; -static void table_data_free (TableData * table_data) +static void table_info_free (TableInfo * table_info) { - g_slist_free (table_data->pkeys); - g_free (table_data); -} - -//----------------------------------------------- ParamDef - -typedef struct -{ - GvnParam * param; - SqlObject * equal_op; - SqlObject * link_op; -} -ParamDef; - -static void param_def_free (ParamDef * def) -{ - g_object_unref (def->param); - - if (def->equal_op) - { - SqlObject * operators = sql_object_get (def->link_op, "operators"); - sql_list_remove_item (SQL_LIST (operators), def->equal_op); - } - - g_free (def); + g_free (table_info->name); + g_free (table_info->schema); + g_free (table_info->alias); + g_slist_free (table_info->pkeys); + g_hash_table_unref (table_info->columns); + g_slist_free (table_info->parent_columns); + g_slist_free (table_info->child_columns); } //----------------------------------------------- ColumnDef -typedef enum -{ - PARAM_DEF, - FIELD_DEF -} -DefType; - typedef struct { - Field * field; - gpointer def; - DefType type; + gulong link; + GvnParam * param; + Field * src_column; } ColumnDef; -static ColumnDef * column_def_new (DefType type, gpointer def) +static ColumnDef * column_def_new () { ColumnDef * column_def = g_new (ColumnDef, 1); - column_def->type = type; - column_def->def = def; + column_def->link = 0; + column_def->param = NULL; + column_def->src_column = NULL; return column_def; } static void column_def_free (ColumnDef * def) { - field_free (def->field); - - switch (def->type) + if (def->param) { - case PARAM_DEF: - param_def_free (def->def); - break; - case FIELD_DEF: - field_free (def->def); - break; + if (def->link) + g_signal_handler_disconnect (def->param, def->link); + + g_object_unref (def->param); } + if (def->src_column) + field_free (def->src_column); g_free (def); } diff --git a/db/db-model.c b/db/db-model.c index 421e3fb..c2fdb3c 100644 --- a/db/db-model.c +++ b/db/db-model.c @@ -59,9 +59,10 @@ struct _DbModelPrivate guint result_pos; DbRequest * request; DbModelStatus status; - DbModelMode mode; gint stamp; + GHashTable * defaults; + gboolean fresh; gint sort_column_id; gint old_sort_column_id; @@ -73,22 +74,20 @@ 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; + DbModelUpdateFlags update_flags; + TableInfo * main_table; + DbModelMode mode; GHashTable * tables; gint updated_col; GQueue * operation; GHashTable * row_ops; GValue * updated_value; GSList * pending_request; + TableInfo ** column_table; + gboolean partial_delete; GSList * join; }; @@ -187,28 +186,6 @@ static void db_model_free_operation (DbModel * obj static void db_model_manage_join (DbModel * obj ,DbIter * iter ,gint col); -static void db_model_post_process_query (DbModel * obj); - -// 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); -} // Signal Handlers @@ -265,9 +242,9 @@ static void db_model_calculate_update_flags (DbModel * obj) { gint i; Table table; - TableData * table_data; + TableInfo * tinfo; DbModelPrivate * priv = obj->priv; - + // Allocates aditional memory when the model is updatable if (priv->user_update_flags && !priv->updatable_data_allocated) @@ -276,78 +253,79 @@ static void db_model_calculate_update_flags (DbModel * obj) 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 + (GHashFunc) table_hash + ,(GEqualFunc) table_equal + ,(GDestroyNotify) table_free + ,(GDestroyNotify) table_info_free ); } - + if (priv->user_update_flags && priv->fresh && priv->result) { + GArray * cols; + + g_free (priv->column_table); g_hash_table_remove_all (priv->tables); + priv->column_table = g_new (TableInfo *, priv->result->ncols); + 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) + DbColumn col = priv->column[i]; + + if (!col.table) { - table_data = g_new0 (TableData, 1); - table_data->pkeys = NULL; - g_hash_table_insert (priv->tables, table_copy (&table), table_data); + priv->column_table[i] = NULL; + continue; + } + + table.name = col.table_alias; + table.schema = col.schema; + tinfo = g_hash_table_lookup (priv->tables, &table); + + if (!tinfo) + { + tinfo = g_new (TableInfo, 1); + tinfo->name = g_strdup (col.table); + tinfo->schema = g_strdup (col.schema); + tinfo->alias = g_strdup (col.table_alias); + tinfo->columns = g_hash_table_new_full ( + g_str_hash + ,g_str_equal + ,NULL + ,(GDestroyNotify) g_array_free + ); + tinfo->pkeys = NULL; + tinfo->parent_columns = NULL; + tinfo->child_columns = NULL; + g_hash_table_insert (priv->tables, table_copy (&table), tinfo); } - 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; + priv->column_table[i] = tinfo; - 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); + if (col.info & DB_COLUMN_PRI_KEY) + tinfo->pkeys = g_slist_prepend (tinfo->pkeys, GINT_TO_POINTER (i)); + + cols = g_hash_table_lookup (tinfo->columns, col.name); + + if (!cols) + { + cols = g_array_sized_new (TRUE, FALSE, sizeof (gint), 1); + g_hash_table_insert (tinfo->columns, g_strdup (col.name), cols); + } + + g_array_append_val (cols, i); } } // Searchs for the main table - table.name = NULL; - if (priv->result) + for (i = 0; i < priv->result->ncols; i++) + if (priv->column[i].info & DB_COLUMN_PRI_KEY) { - if (!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; - break; - } - } - else - table_parse (&table, priv->user_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", priv->user_main_table); + priv->main_table = priv->column_table[i]; + break; } // Sets the updatable flags @@ -356,6 +334,18 @@ static void db_model_calculate_update_flags (DbModel * obj) priv->update_flags = DB_MODEL_ALL & priv->user_update_flags; else priv->update_flags = 0; + + // Sets the params editable + + if (priv->result) + for (i = 0; i < priv->result->ncols; i++) + { + gboolean editable = priv->column_table[i] + && priv->column_table[i]->pkeys + && priv->update_flags & DB_MODEL_UPDATE; + + gvn_param_spec_set_editable (priv->column[i].spec, editable); + } } static void db_model_on_data_ready (DbRequest * request, DbModel * obj) @@ -392,8 +382,6 @@ static void db_model_on_data_ready (DbRequest * request, DbModel * 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)); - - db_model_post_process_query (obj); } else db_model_set_sort_column_id (obj, @@ -418,37 +406,44 @@ static void db_model_process_insert (DbModel * obj, DbRequest * request, DbRow * DbResult * result; DbRow * req_row; DbIter iter; + Table table; + TableInfo * tinfo; 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); + if (!(result && result->data && result->nrows > 0)) + goto exit; - 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].schema, result->column[i].schema)) + iter.data = row; + iter.stamp = priv->stamp; + req_row = g_ptr_array_index (result->data, 0); + + table.name = result->column[0].table_alias; + table.schema = result->column[0].schema; + + if ((tinfo = g_hash_table_lookup (priv->tables, &table))) + for (i = 0; i < result->ncols; i++) + { + GArray * cols = g_hash_table_lookup (tinfo->columns, result->column[i].name); + + for (j = 0; j < cols->len; j++) { 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); - - priv->updated_col = j; - g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); - } + if (gvn_value_compare (new_value, DB_ROW_FIELD (row, i))) + continue; + + 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 = g_array_index (cols, gint, j); + g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); } } - if (result) - db_result_free (result); + exit: + db_result_free (result); } static void db_model_on_operations_done (DbRequest * request, DbModelRequest * data) @@ -460,15 +455,15 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d GError * err = NULL; DbModel * obj = data->obj; DbModelPrivate * priv = obj->priv; - - l = g_queue_peek_head_link (data->operations); - for (; l; l = l->next) + for (l = data->operations->head; l; l = l->next) { op = l->data; + iter.stamp = priv->stamp; + iter.data = op->row; - if (op->type & DB_MODEL_ROW_OP_DELETE - && op->type & DB_MODEL_ROW_OP_INSERT) // DELETE + INSERT + if (op->type & DB_MODEL_ROW_OP_INSERT + && op->type & DB_MODEL_ROW_OP_DELETE) // INSERT + DELETE { g_signal_emit (obj, db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (op->row)); @@ -482,8 +477,20 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d if (op->type & DB_MODEL_ROW_OP_DELETE) // DELETE { - g_signal_emit (obj, - db_model_signal[LINE_DELETED], 0, DB_ROW_POSITION (op->row)); + if (priv->partial_delete) + { + for (i = 0; i < priv->result->ncols; i++) + if (priv->column_table[i] == priv->main_table) + { + priv->updated_col = i; + priv->updated_value = + g_value_init (g_new0 (GValue, 1), GVN_TYPE_NULL); + g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, &iter); + } + } + else + 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 { @@ -506,8 +513,6 @@ static void db_model_on_operations_done (DbRequest * request, DbModelRequest * d 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); } @@ -554,25 +559,26 @@ static void db_model_on_join_query_done (DbRequest * request, JoinData * join_da { for (i = 0; i < priv->result->ncols; i++) for (j = 0; j < r->ncols; j++) - if (!g_strcmp0 (r->column[j].table, priv->column[i].table) - && !g_strcmp0 (r->column[j].name, priv->column[i].name)) + if (!g_strcmp0 (r->column[j].name, priv->column[i].name) + && !g_strcmp0 (r->column[j].table, priv->column[i].table) + && !g_strcmp0 (r->column[j].schema, priv->column[i].schema)) + { + if (r->nrows > 0) { - if (r->nrows > 0) - { - GValue * new_value = - DB_ROW_FIELD (g_ptr_array_index (r->data, 0), j); + GValue * new_value = + DB_ROW_FIELD (g_ptr_array_index (r->data, 0), j); - priv->updated_value = g_new0 (GValue, 1); - g_value_init (priv->updated_value, G_VALUE_TYPE (new_value)); - gvn_value_copy (new_value, priv->updated_value); - } - else - priv->updated_value = - g_value_init (g_new0 (GValue, 1), GVN_TYPE_NULL); - - priv->updated_col = i; - g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, iter); + priv->updated_value = g_new0 (GValue, 1); + g_value_init (priv->updated_value, G_VALUE_TYPE (new_value)); + gvn_value_copy (new_value, priv->updated_value); } + else + priv->updated_value = + g_value_init (g_new0 (GValue, 1), GVN_TYPE_NULL); + + priv->updated_col = i; + g_signal_emit (obj, db_model_signal[LINE_UPDATED], 0, iter); + } db_result_free (r); } @@ -738,293 +744,7 @@ void db_model_reverse_operations (DbModel * obj) } } -static DbModelField * db_model_field_new (const gchar * table, const gchar * schema) -{ - DbModelField * field = g_new (DbModelField, 1); - field->schema = g_strdup (schema); - field->table = g_strdup (table); - field->name = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); - field->main = FALSE; - return field; -} - -static DbModelField * db_model_field_new_from_string (const gchar * str) -{ - DbModelField * field = NULL; - gchar * new_str = g_strdup (str), ** aux, ** f; - gint i, f_len; - g_strstrip (new_str); - f = g_strsplit (new_str, ".", G_MAXINT); - g_free (new_str); - f_len = g_strv_length (f); - - for (i = 0; i < f_len; i++) - { - aux = g_strsplit (f[i], "\"", G_MAXINT); - - if (g_strcmp0 (aux[0], "")) - { - g_strfreev (aux); - break; - } - - g_free (f[i]); - f[i] = g_strdup (aux[1]); - g_strfreev (aux); - } - - switch (f_len) - { - case 3: - { - field = db_model_field_new (f[1], f[0]); - g_ptr_array_add (field->name, g_strdup (f[2])); - break; - } - case 2: - { - field = db_model_field_new (f[0], NULL); - g_ptr_array_add (field->name, g_strdup (f[1])); - break; - } - case 1: - { - field = db_model_field_new (NULL, NULL); - g_ptr_array_add (field->name, g_strdup (f[0])); - } - } - - g_strfreev (f); - - return field; -} - -static void db_model_field_free (DbModelField * field) -{ - if (field) - { - if (field->schema) - g_free (field->schema); - if (field->table) - g_free (field->table); - if (field->name) - g_ptr_array_free (field->name, TRUE); - } - - g_free (field); -} - -static void db_join_free (DbJoin * join) -{ - if (join) - { - if (join->left) - db_model_field_free (join->left); - if (join->right) - db_model_field_free (join->right); - } - - g_free (join); -} -/* -static void db_model_calculate_col_def (DbModel * obj, SqlJoin * join, - SqlField * l_field, SqlField * r_field) -{ - gint i, col = -1; - gchar * dst = NULL; - DbModelPrivate * priv = obj->priv; - SqlField * f = NULL; - SqlTarget * l_table = join->target_left, * r_table = join->target_right; - - for (i = 0; i < priv->result->ncols; i++) - { - f = NULL; - - if (!g_strcmp0 (priv->column[i].name, l_field->name)) - { - f = l_field; - dst = (join->type == SQL_JOIN_TYPE_RIGHT) ? - l_field->name : r_field->name; - } - else if (!g_strcmp0 (priv->column[i].name, r_field->name)) - { - f = r_field; - dst = (join->type == SQL_JOIN_TYPE_LEFT) ? - l_field->name : r_field->name; - } - - if (f) - {//TODO add schema checks - if (f->target) - { - if (!g_strcmp0 (priv->column[i].table, f->target) - || (!g_strcmp0 (priv->column[i].table, SQL_TABLE (l_table)->name) - && !g_strcmp0 (f->target, l_table->alias))) - { - col = i; - break; - } - else if (!g_strcmp0 (priv->column[i].table, SQL_TABLE (r_table)->name) - && !g_strcmp0 (f->target, r_table->alias)) - { - col = i; - break; - } - } - else - { - col = i; - break; - } - } - } - - if (f) - db_model_set_default_value_from_column (obj, dst, col); -} - -static void db_model_set_join_fields (DbModel * obj, SqlJoin * join, - SqlField * lsql_field, SqlField * rsql_field, - DbModelField * lfield, DbModelField * rfield) -{ - gboolean check; - SqlTarget * ltarget = join->target_left, * rtarget = join->target_right; - - check = !g_strcmp0 (lfield->schema, lsql_field->schema) - || !g_strcmp0 (lfield->table, lsql_field->target) - || !g_strcmp0 (ltarget->alias, lsql_field->target) - || !g_strcmp0 (rfield->schema, rfield->schema) - || !g_strcmp0 (rfield->table, rsql_field->target) - || !g_strcmp0 (rtarget->alias, rsql_field->target); - - g_ptr_array_add (lfield->name, - g_strdup (check ? lsql_field->name : rsql_field->name)); - g_ptr_array_add (rfield->name, - g_strdup (check ? rsql_field->name : lsql_field->name)); -} -*/ -static void db_model_post_process_query (DbModel * obj) -{ -/* -// TODO When parser gets fully functional, these 3 lines won't be needed, -// because obj->stmt will be a parsed stmt: - gchar * rend = db_conn_render (obj->priv->conn, obj->priv->stmt, obj->priv->batch, NULL); - SqlObject * stmt = sql_parser_parse (rend); - - g_free (rend); - - if (stmt && SQL_IS_SELECT (stmt)) - { - DbModelField * lfield, * rfield; - SqlJoin * join; - GList * n; - SqlSelect * select = SQL_SELECT (stmt); - gboolean calculate_join = FALSE; - - for (n = sql_list_get_items (SQL_DML (select)->targets); n; n = n->next) - if ((join = n->data) - && SQL_IS_JOIN (join) - && SQL_IS_TABLE (join->target_left) - && SQL_IS_TABLE (join->target_right) - && SQL_IS_OPERATION (join->condition)) - { -// DbJoin and ColDef creation - GList * operators; - SqlOperation * op = SQL_OPERATION (join->condition); - SqlField * lsql_field = NULL, * rsql_field = NULL; - - lfield = db_model_field_new (SQL_TABLE (join->target_left)->name, NULL); - rfield = db_model_field_new (SQL_TABLE (join->target_right)->name, NULL); - - if (join->type == SQL_JOIN_TYPE_RIGHT) - rfield->main = TRUE; - else - lfield->main = TRUE; - - if (op->type == SQL_OPERATION_TYPE_AND) - { - GList * l; - - for (l = sql_list_get_items (op->operators); l; l = l->next) - { - SqlOperation * subop = l->data; - operators = sql_list_get_items (subop->operators); - - if (SQL_IS_OPERATION (subop) - && subop->type == SQL_OPERATION_TYPE_EQUAL - && operators->data // Left Field - && operators->next && operators->next->data) // Right Field - { - lsql_field = SQL_FIELD (operators->data); - rsql_field = SQL_FIELD (operators->next->data); - - db_model_set_join_fields (obj, join, - lsql_field, rsql_field, lfield, rfield); - - calculate_join = TRUE; - - if (join->type != SQL_JOIN_TYPE_INNER) - db_model_calculate_col_def - (obj, join, lsql_field, rsql_field); - } - else - { - calculate_join = FALSE; - break; - } - } - } - else - { - operators = sql_list_get_items (op->operators); - - if (op->type == SQL_OPERATION_TYPE_EQUAL && operators->data - && operators->next && operators->next->data) - { - lsql_field = SQL_FIELD (operators->data); - rsql_field = SQL_FIELD (operators->next->data); - - db_model_set_join_fields (obj, join, - lsql_field, rsql_field, lfield, rfield); - - calculate_join = TRUE; - - if (join->type != SQL_JOIN_TYPE_INNER) - db_model_calculate_col_def - (obj, join ,lsql_field, rsql_field); - } - } - - if (calculate_join) - { - DbJoin * join_res = g_new (DbJoin, 1); - join_res->left = lfield; - join_res->right = rfield; - - obj->priv->join = g_slist_prepend (obj->priv->join, join_res); - } - else - { - db_model_field_free (lfield); - db_model_field_free (rfield); - } - } - } - - if (G_IS_OBJECT (stmt)) - g_object_unref (stmt); -*/ -} - -static inline gboolean stored (const gint * v, const gint length, const gint target) -{ - gint i; - - for (i = 0; i < length; i++) - if (v[i] == target) - return TRUE; - return FALSE; -} +// Utility functions /* * Comparison between values, using case-insensitive and UTF-8 strings @@ -1133,6 +853,37 @@ static void db_model_add_pending_request (DbModel * obj, DbRequest * request) request); } +static void db_model_clear (DbModel * obj) +{ + DbModelPrivate * priv = obj->priv; + + if (priv->request) + { + db_request_cancel (priv->request); + priv->request = NULL; + } + else if (priv->result) + { + db_model_clean_operations (obj); + db_model_cancel_pending_requests (obj); + + db_result_free (priv->result); + priv->result = NULL; + priv->column = NULL; + priv->data = NULL; + + 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; + } +} + +// Join related functions + static void db_model_manage_join (DbModel * obj, DbIter * iter, gint col) { DbModelPrivate * priv = obj->priv; @@ -1146,18 +897,18 @@ static void db_model_manage_join (DbModel * obj, DbIter * iter, gint col) gboolean send_request = FALSE, end = FALSE; SqlList * stmts = g_object_ref_sink (sql_list_new (SQL_TYPE_MULTI_STMT)); -/*FIXME - for (i = 0; i < obj->ncols; i++) - // Check for multi-field pkeys to be fully set - // need to know the total number of pkey fields - if (i != col && obj->column[i].info & DB_COLUMN_PRI_KEY - && gvn_value_is_null (DB_ROW_FIELD (iter->data, i)) - && !g_strcmp0 (obj->column[i].table, obj->column[col].table)) - { - end = TRUE; - break; - } -*/ +// FIXME +// for (i = 0; i < obj->ncols; i++) +// // Check for multi-field pkeys to be fully set +// // need to know the total number of pkey fields +// if (i != col && obj->column[i].info & DB_COLUMN_PRI_KEY +// && gvn_value_is_null (DB_ROW_FIELD (iter->data, i)) +// && !g_strcmp0 (obj->column[i].table, obj->column[col].table)) +// { +// end = TRUE; +// break; +// } + if (!end) for (n = priv->join; n; n = n->next) { @@ -1247,39 +998,345 @@ static void db_model_manage_join (DbModel * obj, DbIter * iter, gint col) g_object_unref (stmts); } } - -static void db_model_clear (DbModel * obj) +/* +static DbModelField * db_model_field_new (const gchar * table, const gchar * schema) { - DbModelPrivate * priv = obj->priv; - - if (priv->request) - { - db_request_cancel (priv->request); - priv->request = NULL; - } - else if (priv->result) - { - db_model_clean_operations (obj); - db_model_cancel_pending_requests (obj); - - db_result_free (priv->result); - priv->result = NULL; - priv->column = NULL; - priv->data = NULL; - - 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; - } + DbModelField * field = g_new (DbModelField, 1); + field->schema = g_strdup (schema); + field->table = g_strdup (table); + field->name = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + field->main = FALSE; + return field; } +static void db_model_field_free (DbModelField * field) +{ + if (field) + { + if (field->schema) + g_free (field->schema); + if (field->table) + g_free (field->table); + if (field->name) + g_ptr_array_free (field->name, TRUE); + } + + g_free (field); +} + +static void db_join_free (DbJoin * join) +{ + if (join) + { + if (join->left) + db_model_field_free (join->left); + if (join->right) + db_model_field_free (join->right); + } + + g_free (join); +} + +static void db_model_calculate_col_def (DbModel * obj, SqlJoin * join, + SqlField * l_field, SqlField * r_field) +{ + gint i, col = -1; + gchar * dst = NULL; + DbModelPrivate * priv = obj->priv; + SqlField * f = NULL; + SqlTarget * l_table = join->target_left, * r_table = join->target_right; + + for (i = 0; i < priv->result->ncols; i++) + { + f = NULL; + + if (!g_strcmp0 (priv->column[i].name, l_field->name)) + { + f = l_field; + dst = (join->type == SQL_JOIN_TYPE_RIGHT) ? + l_field->name : r_field->name; + } + else if (!g_strcmp0 (priv->column[i].name, r_field->name)) + { + f = r_field; + dst = (join->type == SQL_JOIN_TYPE_LEFT) ? + l_field->name : r_field->name; + } + + if (f) + {//TODO add schema checks + if (f->target) + { + if (!g_strcmp0 (priv->column[i].table, f->target) + || (!g_strcmp0 (priv->column[i].table, SQL_TABLE (l_table)->name) + && !g_strcmp0 (f->target, l_table->alias))) + { + col = i; + break; + } + else if (!g_strcmp0 (priv->column[i].table, SQL_TABLE (r_table)->name) + && !g_strcmp0 (f->target, r_table->alias)) + { + col = i; + break; + } + } + else + { + col = i; + break; + } + } + } + + if (f) + db_model_set_default_value_from_column (obj, dst, col); +} + +static void db_model_set_join_fields (DbModel * obj, SqlJoin * join, + SqlField * lsql_field, SqlField * rsql_field, + DbModelField * lfield, DbModelField * rfield) +{ + gboolean check; + SqlTarget * ltarget = join->target_left, * rtarget = join->target_right; + + check = !g_strcmp0 (lfield->schema, lsql_field->schema) + || !g_strcmp0 (lfield->table, lsql_field->target) + || !g_strcmp0 (ltarget->alias, lsql_field->target) + || !g_strcmp0 (rfield->schema, rfield->schema) + || !g_strcmp0 (rfield->table, rsql_field->target) + || !g_strcmp0 (rtarget->alias, rsql_field->target); + + g_ptr_array_add (lfield->name, + g_strdup (check ? lsql_field->name : rsql_field->name)); + g_ptr_array_add (rfield->name, + g_strdup (check ? rsql_field->name : lsql_field->name)); +} + +static void db_model_post_process_query (DbModel * obj) +{ +// TODO When parser gets fully functional, these 3 lines won't be needed, +// because obj->stmt will be a parsed stmt: + gchar * rend = db_conn_render (obj->priv->conn, obj->priv->stmt, obj->priv->batch, NULL); + SqlObject * stmt = sql_parser_parse (rend); + + g_free (rend); + + if (stmt && SQL_IS_SELECT (stmt)) + { + DbModelField * lfield, * rfield; + SqlJoin * join; + GList * n; + SqlSelect * select = SQL_SELECT (stmt); + gboolean calculate_join = FALSE; + + for (n = sql_list_get_items (SQL_DML (select)->targets); n; n = n->next) + if ((join = n->data) + && SQL_IS_JOIN (join) + && SQL_IS_TABLE (join->target_left) + && SQL_IS_TABLE (join->target_right) + && SQL_IS_OPERATION (join->condition)) + { +// DbJoin and ColDef creation + GList * operators; + SqlOperation * op = SQL_OPERATION (join->condition); + SqlField * lsql_field = NULL, * rsql_field = NULL; + + lfield = db_model_field_new (SQL_TABLE (join->target_left)->name, NULL); + rfield = db_model_field_new (SQL_TABLE (join->target_right)->name, NULL); + + if (join->type == SQL_JOIN_TYPE_RIGHT) + rfield->main = TRUE; + else + lfield->main = TRUE; + + if (op->type == SQL_OPERATION_TYPE_AND) + { + GList * l; + + for (l = sql_list_get_items (op->operators); l; l = l->next) + { + SqlOperation * subop = l->data; + operators = sql_list_get_items (subop->operators); + + if (SQL_IS_OPERATION (subop) + && subop->type == SQL_OPERATION_TYPE_EQUAL + && operators->data // Left Field + && operators->next && operators->next->data) // Right Field + { + lsql_field = SQL_FIELD (operators->data); + rsql_field = SQL_FIELD (operators->next->data); + + db_model_set_join_fields (obj, join, + lsql_field, rsql_field, lfield, rfield); + + calculate_join = TRUE; + + if (join->type != SQL_JOIN_TYPE_INNER) + db_model_calculate_col_def + (obj, join, lsql_field, rsql_field); + } + else + { + calculate_join = FALSE; + break; + } + } + } + else + { + operators = sql_list_get_items (op->operators); + + if (op->type == SQL_OPERATION_TYPE_EQUAL && operators->data + && operators->next && operators->next->data) + { + lsql_field = SQL_FIELD (operators->data); + rsql_field = SQL_FIELD (operators->next->data); + + db_model_set_join_fields (obj, join, + lsql_field, rsql_field, lfield, rfield); + + calculate_join = TRUE; + + if (join->type != SQL_JOIN_TYPE_INNER) + db_model_calculate_col_def + (obj, join ,lsql_field, rsql_field); + } + } + + if (calculate_join) + { + DbJoin * join_res = g_new (DbJoin, 1); + join_res->left = lfield; + join_res->right = rfield; + + obj->priv->join = g_slist_prepend (obj->priv->join, join_res); + } + else + { + db_model_field_free (lfield); + db_model_field_free (rfield); + } + } + } + + if (G_IS_OBJECT (stmt)) + g_object_unref (stmt); + +} + +static gboolean db_model_analyse_join_op (DbModel * obj, SqlOperation * op) +{ + gint i; + gint noperands; + SqlList * operands; + SqlOperationType operator = sql_operation_get_operator (op); + + noperands = sql_list_length (operands); + g_object_get (op, "operands", &operands, NULL); + + if (operator == SQL_OPERATION_TYPE_EQUAL && noperands == 2) + { + gpointer field1 = sql_list_get (operands, 0); + gpointer field2 = sql_list_get (operands, 1); + + if (!SQL_IS_FIELD (field1) || !SQL_IS_FIELD (field2) + || (g_strcmp0 (sql_field_get_target (field1), sql_field_get_target (field2)) + && g_strcmp0 (sql_field_get_schema (field1), sql_field_get_schema (field2)))) + return FALSE; + + + } + else if (operator == SQL_OPERATION_TYPE_AND) + { + for (i = 0; i < noperands; i++) + if (!db_model_analyse_join_op (obj, sql_list_get (operands, i))) + return FALSE; + + return TRUE; + } + + return FALSE; +} + +static void db_model_analyse_join (DbModel * obj, SqlTarget * target) +{ + SqlJoin * join; + SqlTarget * left; + SqlTarget * right; + SqlOperation * on; + + if (!SQL_IS_JOIN (target)) + return; + + join = SQL_JOIN (target); + g_object_get (join + ,"target-left", &left + ,"target-right", &right + ,"condition", &on + ,NULL + ); + + if (SQL_IS_TABLE (left) || SQL_IS_TABLE (right)) + db_model_analyse_join_op (obj, on); + + switch ((gint) sql_join_get_join_type (join)) + { + case SQL_JOIN_TYPE_INNER: + break; + case SQL_JOIN_TYPE_LEFT: + break; + case SQL_JOIN_TYPE_RIGHT: + break; + } + + db_model_analyse_join (obj, left); + db_model_analyse_join (obj, right); +} + +static void db_model_load_join (DbModel * obj) +{ + gchar * sql; + SqlObject * stmt; + SqlObject * select; + DbModelPrivate * priv = obj->priv; + + sql = db_conn_render (obj->priv->conn, obj->priv->stmt, NULL, NULL); + stmt = sql_parser_parse (sql); + g_free (sql); + + if (!stmt) + return; + + g_object_ref_sink (stmt); + + if (SQL_IS_MULTI_STMT (stmt)) + { + SqlList * stmts; + g_object_get (stmt, "stmts", &stmts, NULL); + select = sql_list_get (stmts, priv->result_pos); + } + else + select = stmt; + + if (!SQL_IS_SELECT (select)) + goto exit; + + gint i; + SqlList * targets; + + g_object_get (select, "targets", &targets, NULL); + + for (i = 0; i < sql_list_length (targets); i++) + db_model_analyse_join (obj, sql_list_get (targets, i)); + + exit: + g_object_unref (stmt); +} +*/ //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public -// Set&Get methods +// Setters & getters /** * db_model_set_conn: @@ -1542,8 +1599,8 @@ void db_model_add_join_columns (DbModel * obj, const gchar * left, const gchar * g_return_if_fail (DB_IS_MODEL (obj)); DbJoin * join = g_new (DbJoin, 1); - join->left = db_model_field_new_from_string (left); - join->right = db_model_field_new_from_string (right); +// join->left = db_model_field_new_from_string (left); +// join->right = db_model_field_new_from_string (right); obj->priv->join = g_slist_prepend (obj->priv->join, join); } @@ -1592,6 +1649,30 @@ void db_model_set_batch (DbModel * obj, SqlBatch * batch) priv->batch = batch; } +static ColumnDef * db_model_create_column_def (DbModel * obj, const gchar * field_str) +{ + Field * field = field_new_from_string (field_str); + + if (field->name && field->target && !field->schema) + { + ColumnDef * def = column_def_new (); + g_hash_table_insert (obj->priv->defaults, field, def); + return def; + } + else + { + g_warning ("DbModel: Field string shoud specify name and table alias: %s", field_str); + field_free (field); + } + + return NULL; +} + +static void db_model_on_param_changed (GvnParam * param, GValue * value, DbModel * obj) +{ + db_model_refresh (obj); +} + /** * db_model_set_default_value_from_column: * @obj: a #DbModel @@ -1601,17 +1682,16 @@ void db_model_set_batch (DbModel * obj, SqlBatch * batch) void db_model_set_default_value_from_column (DbModel * obj, const gchar * field_str, const gchar * column_str) { - Field * field; - ColumnDef * column_def; + ColumnDef * def; 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); + def = db_model_create_column_def (obj, field_str); + + if (def) + def->src_column = field_new_from_string (column_str); } /** @@ -1626,58 +1706,22 @@ void db_model_set_default_value_from_column (DbModel * obj, void db_model_set_default_value_from_param (DbModel * obj, const gchar * field_str, GvnParam * param, gboolean link) { - Field * field; - ParamDef * param_def; - ColumnDef * column_def; - SqlObject * equal = NULL; + ColumnDef * def; g_return_if_fail (DB_IS_MODEL (obj)); 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; + def = db_model_create_column_def (obj, field_str); - db_model_alloc_link_data (obj); - - link_operands = sql_operation_get_operands (SQL_OPERATION (obj->priv->link_op)); + if (!def) + return; - equal = sql_operation_new (SQL_OPERATION_TYPE_EQUAL); - sql_list_add (link_operands, equal); - - operands = sql_list_new (SQL_TYPE_EXPR); - 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); - } - - 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); -} - -/** - * db_model_request_main_table: - * @obj: a #DbModel - * @table: the name of the new main table of @model - * - * Requests the main table of @model. The main table is the only table on a - * #DbModel whose rows can be deleted or inserted. - **/ -void db_model_request_main_table (DbModel * obj, const gchar * table) -{ - g_return_if_fail (DB_IS_MODEL (obj)); - - g_free (obj->priv->user_main_table); - obj->priv->user_main_table = g_strdup (table); - db_model_calculate_update_flags (obj); + def->param = g_object_ref_sink (param); + + if (link) + def->link = g_signal_connect (param, "value-changed", + G_CALLBACK (db_model_on_param_changed), obj); } /** @@ -1943,17 +1987,7 @@ gboolean db_model_set_value (DbModel * obj, DbIter * iter, gint col, const GValu GvnParamSpec * spec = priv->column[col].spec; if (!gvn_param_spec_validate (spec, value, err)) - { return FALSE; - } - - if (!(priv->update_flags & DB_MODEL_UPDATE) - && !(row_op & DB_MODEL_ROW_OP_INSERT)) - { - g_set_error (err, DB_MODEL_LOG_DOMAIN - ,DB_MODEL_ERROR_NOT_UPDATABLE, "Model not updatable"); - return FALSE; - } if (!gvn_value_is_null (value)) { @@ -2033,21 +2067,17 @@ gboolean db_model_insert (DbModel * obj, DbIter * iter) for (i = 0; i < row->len; i++) { Field field; - ColumnDef * column_def; + ColumnDef * def; const GValue * def_value = NULL; DbColumn col = priv->column[i]; 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); - } + field.target = priv->column_table[i]->alias; + field.schema = NULL; + def = g_hash_table_lookup (priv->defaults, &field); + + if (def && def->param) + def_value = gvn_param_get_value (def->param); if (!def_value) def_value = gvn_param_spec_get_default (col.spec); @@ -2280,7 +2310,7 @@ gboolean db_model_has_pending_operations (DbModel * obj) } static SqlObject * db_model_create_where (DbModel * obj, - Table * table, DbOperation * operation, gboolean for_insert) + TableInfo * tinfo, DbOperation * operation, gboolean for_insert) { GSList * l; DbUpdatedField * u; @@ -2296,9 +2326,7 @@ 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) + for (l = tinfo->pkeys; l; l = l->next) { GSList * n; SqlObject * equal; @@ -2348,20 +2376,24 @@ static SqlObject * db_model_create_where (DbModel * obj, } static SqlObject * db_model_create_insert (DbModel * obj, - Table * table, DbOperation * operation) + TableInfo * tinfo, DbOperation * operation) { gint i; DbModelPrivate * priv = obj->priv; DbRow * row = operation->row; 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); + SqlObject * target, * insert, * set, * select, * where; + GHashTableIter iter; + Field * field; + ColumnDef * def; + GArray * cols; + gchar * colname; + + where = db_model_create_where (obj, tinfo, operation, TRUE); if (!where) return NULL; - - target = sql_table_new (table->name, table->schema); fields = sql_list_new (SQL_TYPE_FIELD); @@ -2373,6 +2405,7 @@ static SqlObject * db_model_create_insert (DbModel * obj, ); sql_list_add (sets, set); + target = sql_table_new (tinfo->name, tinfo->schema); insert = g_object_new (SQL_TYPE_INSERT ,"table", target ,"fields", fields @@ -2383,6 +2416,9 @@ static SqlObject * db_model_create_insert (DbModel * obj, select_fields = sql_list_new (SQL_TYPE_EXPR); targets = sql_list_new (SQL_TYPE_TARGET); + + target = sql_table_new (tinfo->name, tinfo->schema); + sql_target_set_alias (SQL_TARGET (target), tinfo->alias); sql_list_add (targets, target); select = g_object_new (SQL_TYPE_SELECT @@ -2392,28 +2428,16 @@ static SqlObject * db_model_create_insert (DbModel * obj, ,NULL ); - GHashTableIter iter; - ColumnDef * column_def; - Field * field; - - g_hash_table_iter_init (&iter, priv->column_defaults); + g_hash_table_iter_init (&iter, priv->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)) + while (g_hash_table_iter_next (&iter, (gpointer) &field, (gpointer) &def)) + if (!g_strcmp0 (field->target, tinfo->alias) + && !g_hash_table_lookup (tinfo->columns, field->name)) { - 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 (def->param) + value = gvn_param_get_value (def->param); + else + value = NULL; if (value) { @@ -2422,20 +2446,22 @@ static SqlObject * db_model_create_insert (DbModel * obj, } } - for (i = 0; i < row->len; i++) - if (table_has_column (table, &priv->column[i])) + g_hash_table_iter_init (&iter, tinfo->columns); + + while (g_hash_table_iter_next (&iter, (gpointer) &colname, (gpointer) &cols)) { + i = g_array_index (cols, gint, 0); value = &row->value[i]; if (!gvn_value_is_null (value)) { - sql_list_add (fields, sql_field_new (priv->column[i].name)); + sql_list_add (fields, sql_field_new (colname)); sql_list_add (values, sql_value_new_with_value (value)); } - sql_list_add (select_fields, sql_field_new (priv->column[i].name)); + sql_list_add (select_fields, sql_field_new (colname)); } - + stmts = sql_list_new (SQL_TYPE_STMT); sql_list_add (stmts, insert); sql_list_add (stmts, select); @@ -2482,9 +2508,7 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) stmts = sql_list_new (SQL_TYPE_STMT); g_object_ref_sink (stmts); - l = g_queue_peek_head_link (priv->operation); - - for (; l && !error; l = l->next) + for (l = priv->operation->head; l && !error; l = l->next) { SqlObject * stmt = NULL; @@ -2525,36 +2549,50 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) } else if (op->type & DB_MODEL_ROW_OP_UPDATE) // UPDATE || INSERT + SELECT { - Table * table; + GList * l; + GSList * n; + GQueue * fields; + TableInfo * tinfo; GHashTableIter iter; SqlList * update_list; + DbUpdatedField * u; + + GHashTable * tables = g_hash_table_new_full ( + g_direct_hash + ,g_direct_equal + ,NULL + ,(GDestroyNotify) g_queue_free + ); + + for (n = op->updated; n && (u = n->data); n = n->next) + { + tinfo = priv->column_table[u->column]; + fields = g_hash_table_lookup (tables, tinfo); + + if (!fields) + { + fields = g_queue_new (); + g_hash_table_insert (tables, tinfo, fields); + } + + g_queue_push_tail (fields, u); + } update_list = sql_list_new (SQL_TYPE_STMT); - g_hash_table_iter_init (&iter, priv->tables); + g_hash_table_iter_init (&iter, tables); - while (g_hash_table_iter_next (&iter, (gpointer) &table, NULL)) + while (g_hash_table_iter_next (&iter, (gpointer) &tinfo, (gpointer) &fields)) { - 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); + where = db_model_create_where (obj, tinfo, op, FALSE); if (where) { 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->name, table->schema)); + sql_list_add (targets, sql_table_new (tinfo->name, tinfo->schema)); - for (l = fields; l && (u = l->data); l = l->next) + for (l = fields->head; l && (u = l->data); l = l->next) { GValue * new_value = DB_ROW_FIELD (row, u->column); @@ -2574,15 +2612,14 @@ void db_model_perform_operations (DbModel * obj, gboolean retry) } else { - SqlObject * insert = db_model_create_insert (obj, table, op); + SqlObject * insert = db_model_create_insert (obj, tinfo, op); if (insert) sql_list_add (update_list, insert); } - - g_slist_free (fields); } + g_hash_table_unref (tables); stmt = g_object_new (SQL_TYPE_MULTI_STMT, "stmts", update_list, NULL); } @@ -2646,10 +2683,53 @@ void db_model_refresh (DbModel * obj) if (priv->conn && priv->stmt) { - SqlBatch * tmp_batch = sql_batch_new (); + Field * field; + ColumnDef * def; + SqlObject * link_op; + SqlList * link_operands; + SqlBatch * tmp_batch; + GHashTableIter iter; + + // Gets all the holders from the statement + + tmp_batch = sql_batch_new (); + g_object_ref_sink (tmp_batch); 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); + + // Creates the link operation + + link_op = sql_operation_new (SQL_OPERATION_TYPE_AND); + g_object_ref_sink (link_op); + + link_operands = sql_list_new (SQL_TYPE_EXPR); + sql_operation_set_operands (SQL_OPERATION (link_op), link_operands); + + g_hash_table_iter_init (&iter, priv->defaults); + + while (g_hash_table_iter_next (&iter, (gpointer) &field, (gpointer) &def)) + if (def->link) + { + SqlObject * sql_field; + SqlObject * equal_op; + SqlList * equal_operands; + + equal_op = sql_operation_new (SQL_OPERATION_TYPE_EQUAL); + sql_list_add (link_operands, equal_op); + + sql_field = sql_field_new_with_target ( + field->name, field->target, NULL); + + equal_operands = sql_list_new (SQL_TYPE_EXPR); + sql_list_add (equal_operands, sql_field); + sql_list_add (equal_operands, sql_value_new_with_param (def->param)); + sql_operation_set_operands (SQL_OPERATION (equal_op), equal_operands); + } + + if (sql_list_length (link_operands) > 0) + sql_batch_add (tmp_batch, "link", link_op); + + // Executes the statement if its ready if (sql_batch_is_ready (tmp_batch)) { @@ -2663,9 +2743,10 @@ void db_model_refresh (DbModel * obj) ,g_object_ref (obj) ,(GDestroyNotify) g_object_unref ); - - g_object_unref (g_object_ref_sink (tmp_batch)); } + + g_object_unref (link_op); + g_object_unref (tmp_batch); } if (!is_ready) @@ -2931,6 +3012,7 @@ typedef enum ,PROP_MAIN_TABLE ,PROP_UPDATE_FLAGS ,PROP_RESULT_POS + ,PROP_PARTIAL_DELETE } DbModelProp; @@ -2951,15 +3033,15 @@ static void db_model_set_property (DbModel * obj, guint property_id, case PROP_USE_FILE: obj->priv->use_file = g_value_get_boolean (value); break; - case PROP_MAIN_TABLE: - db_model_request_main_table (obj, g_value_get_string (value)); - break; case PROP_UPDATE_FLAGS: db_model_request_update_flags (obj, g_value_get_flags (value)); break; case PROP_RESULT_POS: obj->priv->result_pos = g_value_get_uint (value); break; + case PROP_PARTIAL_DELETE: + obj->priv->partial_delete = g_value_get_boolean (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); } @@ -2991,6 +3073,9 @@ static void db_model_get_property (DbModel * obj, guint property_id, case PROP_RESULT_POS: g_value_set_uint (value, obj->priv->result_pos); break; + case PROP_PARTIAL_DELETE: + g_value_set_boolean (value, obj->priv->partial_delete); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec); } @@ -3008,11 +3093,11 @@ static void db_model_init (DbModel *obj) priv->sql = NULL; priv->request = NULL; priv->status = DB_MODEL_STATUS_CLEAN; - priv->mode = DB_MODEL_MODE_ON_CHANGE; priv->result = NULL; priv->result_pos = 0; priv->data = NULL; priv->column = NULL; + priv->stamp = g_random_int (); priv->column_index = g_hash_table_new_full ( g_str_hash, g_str_equal, @@ -3020,33 +3105,31 @@ static void db_model_init (DbModel *obj) NULL ); - priv->stamp = g_random_int (); + priv->defaults = g_hash_table_new_full ( + (GHashFunc) field_hash, + (GEqualFunc) field_equal, + (GDestroyNotify) field_free, + (GDestroyNotify) column_def_free + ); priv->fresh = TRUE; priv->sort_column_id = DB_MODEL_UNSORTED_SORT_COLUMN_ID; priv->default_sort_data = NULL; priv->default_sort_func = NULL; priv->default_sort_destroy = NULL; - - 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->update_flags = 0; priv->main_table = NULL; - priv->user_main_table = NULL; + priv->mode = DB_MODEL_MODE_ON_CHANGE; priv->operation = NULL; priv->row_ops = NULL; - priv->join = NULL; priv->pending_request = NULL; priv->tables = NULL; + priv->column_table = NULL; + priv->partial_delete = FALSE; + priv->join = NULL; } static void db_model_finalize (DbModel * obj) @@ -3061,18 +3144,15 @@ static void db_model_finalize (DbModel * obj) g_free (priv->sql); 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->column_defaults); + g_hash_table_destroy (priv->defaults); if (priv->updatable_data_allocated) { - g_free (priv->user_main_table); g_queue_free (priv->operation); - g_hash_table_destroy (priv->row_ops); - g_slist_free_full (priv->join, (GDestroyNotify) db_join_free); - g_hash_table_destroy (priv->tables); + g_hash_table_unref (priv->row_ops); + g_hash_table_unref (priv->tables); + g_free (priv->column_table); +// g_slist_free_full (priv->join, (GDestroyNotify) db_join_free); } parent->finalize (G_OBJECT (obj)); @@ -3241,7 +3321,7 @@ static void db_model_class_init (DbModelClass *k) ,_("Main Table") ,_("The main table of the model") ,NULL - ,G_PARAM_READWRITE + ,G_PARAM_READABLE )); g_object_class_install_property (klass, PROP_UPDATE_FLAGS, @@ -3263,6 +3343,15 @@ static void db_model_class_init (DbModelClass *k) ,0 ,G_PARAM_READWRITE )); + + g_object_class_install_property (klass, PROP_PARTIAL_DELETE, + g_param_spec_boolean ("partial-delete" + ,_("Partial delete") + ,_("When a row is deleted set all the fields from " + "the table to null rather than delete it.") + ,FALSE + ,G_PARAM_READWRITE + )); } GType db_model_update_flags_get_type () diff --git a/db/db-model.h b/db/db-model.h index 831988e..b8f6c0f 100644 --- a/db/db-model.h +++ b/db/db-model.h @@ -197,7 +197,6 @@ void db_model_add_pre_stmt (DbModel * obj, SqlStmt * stmt); void db_model_add_post_stmt (DbModel * obj, SqlStmt * stmt); DbModelStatus db_model_get_status (DbModel * obj); const gchar * db_model_get_main_table (DbModel * obj); -void db_model_request_main_table (DbModel * obj, const gchar * table); DbModelUpdateFlags db_model_get_update_flags (DbModel * obj); void db_model_request_update_flags (DbModel * obj ,DbModelUpdateFlags flags); diff --git a/db/db-result.c b/db/db-result.c index 2e89d9d..44aca24 100644 --- a/db/db-result.c +++ b/db/db-result.c @@ -72,6 +72,8 @@ DbResult * db_result_copy (const DbResult * obj) result->column[n].info = obj->column[n].info; 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].table_alias = g_strdup (obj->column[n].table_alias); + result->column[n].schema = g_strdup (obj->column[n].schema); result->column[n].name = g_strdup (obj->column[n].name); result->column[n].alias = g_strdup (obj->column[n].alias); } @@ -107,6 +109,8 @@ void db_result_free (DbResult * obj) g_free (col.name); g_free (col.alias); g_free (col.table); + g_free (col.table_alias); + g_free (col.schema); } g_free (obj->column); diff --git a/db/db-result.h b/db/db-result.h index 6c9be48..8a1a3fd 100644 --- a/db/db-result.h +++ b/db/db-result.h @@ -69,13 +69,13 @@ DbColumnInfo; **/ struct _DbColumn { - DbColumnInfo info; - GvnParamSpec * spec; - gchar * schema; - gchar * table; - gchar * table_alias; gchar * name; gchar * alias; + gchar * table; + gchar * table_alias; + gchar * schema; + DbColumnInfo info; + GvnParamSpec * spec; }; GType db_result_get_type (); diff --git a/module/data/customer.glade b/module/data/customer.glade index 27e07b4..223d9c0 100644 --- a/module/data/customer.glade +++ b/module/data/customer.glade @@ -1,11 +1,11 @@ - + - SELECT id, street, pc, city, province, ok FROM user_address WHERE #link ORDER BY id + SELECT id, street, pc, city, province, ok, user_id FROM user_address WHERE #link ORDER BY id SELECT id, name, credit, active, born, photo, object_id FROM "user" ORDER BY id @@ -348,6 +348,13 @@ True + + + User + user_id + True + + diff --git a/plugin/pg/db-pg.c b/plugin/pg/db-pg.c index 6d5325f..3ab937e 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].table_alias = NULL; r->column[j].schema = NULL; if (GPOINTER_TO_INT (g_ptr_array_index (col_iter, j)) == 0) @@ -650,6 +651,7 @@ static DbResultSet * __db_pg_query r->column[j].alias = g_strdup (r->column[j].name); r->column[j].table = g_strdup (""); + r->column[j].table_alias = g_strdup (""); r->column[j].spec = gvn_param_spec_new_with_attrs (((GType*) g_ptr_array_index (types, ind))[j] , FALSE, FALSE, NULL); @@ -763,8 +765,12 @@ static DbResultSet * __db_pg_query guint n; if (!r->column[j].table) + { r->column[j].table = g_strdup (PQgetvalue (res_col, k, 1)); + r->column[j].table_alias = + g_strdup (r->column[j].table); + } g_strfreev (pkey); pkey = g_strsplit (PQgetvalue (res_col, k, 2), " ", G_MAXINT); diff --git a/sql/sql-batch.c b/sql/sql-batch.c index 4436b2c..8b79382 100644 --- a/sql/sql-batch.c +++ b/sql/sql-batch.c @@ -48,9 +48,12 @@ static void sql_batch_item_changed (SqlObject * item, SqlBatch * obj) static void sql_batch_free_item (SqlBatch * obj, SqlObject * item) { - g_signal_handlers_disconnect_by_func (item, - sql_batch_item_changed, obj); - g_object_unref (item); + if (item) + { + g_signal_handlers_disconnect_by_func (item, + sql_batch_item_changed, obj); + g_object_unref (item); + } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public diff --git a/sql/sql-field.h b/sql/sql-field.h index f21e85b..064bbe6 100644 --- a/sql/sql-field.h +++ b/sql/sql-field.h @@ -22,8 +22,8 @@ #include "sql-target.h" #define SQL_TYPE_FIELD (sql_field_get_type ()) -#define SQL_FIELD(object) (G_TYPE_CHECK_INSTANCE_CAST (object, SQL_TYPE_FIELD, SqlField)) -#define SQL_IS_FIELD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SQL_TYPE_FIELD)) +#define SQL_FIELD(self) (G_TYPE_CHECK_INSTANCE_CAST (self, SQL_TYPE_FIELD, SqlField)) +#define SQL_IS_FIELD(self) (G_TYPE_CHECK_INSTANCE_TYPE ((self), SQL_TYPE_FIELD)) typedef struct _SqlField SqlField; typedef struct _SqlFieldClass SqlFieldClass; @@ -49,10 +49,10 @@ SqlObject * sql_field_new_with_target (const gchar * name ,const gchar * schema); const gchar * sql_field_get_name (SqlField * self); -void sql_field_set_name (SqlField * obj, const gchar * name); +void sql_field_set_name (SqlField * self, const gchar * name); const gchar * sql_field_get_target (SqlField * self); -void sql_field_set_target (SqlField * obj, const gchar * target); +void sql_field_set_target (SqlField * self, const gchar * target); const gchar * sql_field_get_schema (SqlField * self); -void sql_field_set_schema (SqlField * obj, const gchar * schema); +void sql_field_set_schema (SqlField * self, const gchar * schema); #endif diff --git a/sql/sql-holder.c b/sql/sql-holder.c index 36df2a5..c44d255 100644 --- a/sql/sql-holder.c +++ b/sql/sql-holder.c @@ -31,36 +31,36 @@ SqlObject * sql_holder_new (const gchar * id) //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private -static void sql_holder_render (SqlHolder * obj, SqlRender * render, SqlBatch * batch) +static void sql_holder_render (SqlHolder * self, SqlRender * render, SqlBatch * batch) { - SqlObject * object = batch ? sql_batch_get (batch, obj->id) : NULL; + SqlObject * object = batch ? sql_batch_get (batch, self->id) : NULL; if (object) sql_render_add_object (render, object); else - sql_render_printf (render, "#%s", obj->id); + sql_render_printf (render, "#%s", self->id); } -static void sql_holder_find_holders (SqlHolder * obj, SqlBatch * batch) +static void sql_holder_find_holders (SqlHolder * self, SqlBatch * batch) { - sql_batch_add (batch, obj->id, NULL); + sql_batch_add (batch, self->id, NULL); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public /** * sql_holder_get_id: - * @obj: the #SqlHolder + * @self: the #SqlHolder * * Gets the identifier assigned to the holder. * * Return value: (transfer none): the id **/ -const gchar * sql_holder_get_id (SqlHolder * obj) +const gchar * sql_holder_get_id (SqlHolder * self) { - g_return_val_if_fail (SQL_IS_HOLDER (obj), NULL); + g_return_val_if_fail (SQL_IS_HOLDER (self), NULL); - return obj->id; + return self->id; } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties @@ -70,44 +70,44 @@ enum PROP_ID = 1 }; -static void sql_holder_set_property (SqlHolder * obj, guint id, +static void sql_holder_set_property (SqlHolder * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_ID: - g_free (obj->id); - obj->id = g_value_dup_string (value); + g_free (self->id); + self->id = g_value_dup_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_holder_get_property (SqlHolder * obj, guint id, +static void sql_holder_get_property (SqlHolder * self, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_ID: - g_value_set_string (value, sql_holder_get_id (obj)); + g_value_set_string (value, sql_holder_get_id (self)); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class -static void sql_holder_init (SqlHolder * obj) +static void sql_holder_init (SqlHolder * self) { - obj->id = NULL; + self->id = NULL; } -static void sql_holder_finalize (SqlHolder * obj) +static void sql_holder_finalize (SqlHolder * self) { - g_free (obj->id); - G_OBJECT_CLASS (sql_holder_parent_class)->finalize (G_OBJECT (obj)); + g_free (self->id); + G_OBJECT_CLASS (sql_holder_parent_class)->finalize (G_OBJECT (self)); } static void sql_holder_class_init (SqlHolderClass * k) diff --git a/sql/sql-holder.h b/sql/sql-holder.h index 76da647..03487a7 100644 --- a/sql/sql-holder.h +++ b/sql/sql-holder.h @@ -19,8 +19,8 @@ #define SQL_HOLDER_H #define SQL_TYPE_HOLDER (sql_holder_get_type ()) -#define SQL_HOLDER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, SQL_TYPE_HOLDER, SqlHolder)) -#define SQL_IS_HOLDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, SQL_TYPE_HOLDER)) +#define SQL_HOLDER(self) (G_TYPE_CHECK_INSTANCE_CAST (self, SQL_TYPE_HOLDER, SqlHolder)) +#define SQL_IS_HOLDER(self) (G_TYPE_CHECK_INSTANCE_TYPE (self, SQL_TYPE_HOLDER)) typedef struct _SqlHolder SqlHolder; typedef struct _SqlHolderClass SqlHolderClass; @@ -41,6 +41,6 @@ struct _SqlHolderClass GType sql_holder_get_type (); SqlObject * sql_holder_new (const gchar * id); -const gchar * sql_holder_get_id (SqlHolder * obj); +const gchar * sql_holder_get_id (SqlHolder * self); #endif \ No newline at end of file diff --git a/sql/sql-join.c b/sql/sql-join.c index 9c88c23..592e433 100644 --- a/sql/sql-join.c +++ b/sql/sql-join.c @@ -47,51 +47,58 @@ static const gchar * SQL_JOIN_TYPE[] = ,"RIGHT" }; -static void sql_join_render (SqlJoin * obj, SqlRender * render) +static void sql_join_render (SqlJoin * self, SqlRender * render) { - sql_render_add_item (render, TRUE, NULL, obj->target_left); - sql_render_add_token (render, SQL_JOIN_TYPE[obj->type]); + sql_render_add_item (render, TRUE, NULL, self->target_left); + sql_render_add_token (render, SQL_JOIN_TYPE[self->type]); sql_render_add_token (render, "JOIN"); - sql_render_add_item (render, TRUE, NULL, obj->target_right); + sql_render_add_item (render, TRUE, NULL, self->target_right); - if (obj->has_using) + if (self->has_using) { sql_render_add_token (render, "USING"); sql_render_append (render, "("); - sql_render_add_list (render, TRUE, NULL, obj->using_fields, ","); + sql_render_add_list (render, TRUE, NULL, self->using_fields, ","); sql_render_append (render, ")"); } else - sql_render_add_item (render, FALSE, "ON", obj->condition); + sql_render_add_item (render, FALSE, "ON", self->condition); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public -void sql_join_set_target_left (SqlJoin * obj, SqlTarget * target) +SqlJoinType sql_join_get_join_type (SqlJoin * self) { - g_return_if_fail (SQL_IS_JOIN (obj)); - g_return_if_fail (SQL_IS_TARGET (target) || SQL_IS_HOLDER (target) || !target); - - sql_object_remove (obj, obj->target_left); - obj->target_left = sql_object_add (obj, target); + g_return_if_fail (SQL_IS_JOIN (self)); + + return self->type; } -void sql_join_set_target_right (SqlJoin * obj, SqlTarget * target) +void sql_join_set_target_left (SqlJoin * self, SqlTarget * target) { - g_return_if_fail (SQL_IS_JOIN (obj)); + g_return_if_fail (SQL_IS_JOIN (self)); g_return_if_fail (SQL_IS_TARGET (target) || SQL_IS_HOLDER (target) || !target); - sql_object_remove (obj, obj->target_right); - obj->target_right = sql_object_add (obj, target); + sql_object_remove (self, self->target_left); + self->target_left = sql_object_add (self, target); } -void sql_join_set_condition (SqlJoin * obj, SqlExpr * condition) +void sql_join_set_target_right (SqlJoin * self, SqlTarget * target) { - g_return_if_fail (SQL_IS_JOIN (obj)); + g_return_if_fail (SQL_IS_JOIN (self)); + g_return_if_fail (SQL_IS_TARGET (target) || SQL_IS_HOLDER (target) || !target); + + sql_object_remove (self, self->target_right); + self->target_right = sql_object_add (self, target); +} + +void sql_join_set_condition (SqlJoin * self, SqlExpr * condition) +{ + g_return_if_fail (SQL_IS_JOIN (self)); g_return_if_fail (SQL_IS_EXPR (condition) || SQL_IS_HOLDER (condition) || !condition); - sql_object_remove (obj, obj->condition); - obj->condition = sql_object_add (obj, condition); + sql_object_remove (self, self->condition); + self->condition = sql_object_add (self, condition); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties @@ -106,80 +113,80 @@ enum ,PROP_USING_FIELDS }; -static void sql_join_set_property (SqlJoin * obj, guint id, +static void sql_join_set_property (SqlJoin * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_TARGET_LEFT: - sql_join_set_target_left (obj, g_value_get_object (value)); + sql_join_set_target_left (self, g_value_get_object (value)); break; case PROP_TARGET_RIGHT: - sql_join_set_target_right (obj, g_value_get_object (value)); + sql_join_set_target_right (self, g_value_get_object (value)); break; case PROP_TYPE: - obj->type = g_value_get_enum (value); + self->type = g_value_get_enum (value); break; case PROP_CONDITION: - sql_join_set_condition (obj, g_value_get_object (value)); + sql_join_set_condition (self, g_value_get_object (value)); break; case PROP_HAS_USING: - obj->has_using = g_value_get_boolean (value); + self->has_using = g_value_get_boolean (value); break; case PROP_USING_FIELDS: - sql_object_remove (obj, obj->using_fields); - obj->using_fields = sql_object_add (obj, g_value_get_object (value)); + sql_object_remove (self, self->using_fields); + self->using_fields = sql_object_add (self, g_value_get_object (value)); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } -static void sql_join_get_property (SqlJoin * obj, guint id, +static void sql_join_get_property (SqlJoin * self, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_TARGET_LEFT: - g_value_set_object (value, obj->target_left); + g_value_set_object (value, self->target_left); break; case PROP_TARGET_RIGHT: - g_value_set_object (value, obj->target_right); + g_value_set_object (value, self->target_right); break; case PROP_TYPE: - g_value_set_enum (value, obj->type); + g_value_set_enum (value, self->type); break; case PROP_CONDITION: - g_value_set_object (value, obj->condition); + g_value_set_object (value, self->condition); break; case PROP_HAS_USING: - g_value_set_boolean (value, obj->has_using); + g_value_set_boolean (value, self->has_using); break; case PROP_USING_FIELDS: - g_value_set_object (value, obj->using_fields); + g_value_set_object (value, self->using_fields); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class -static void sql_join_init (SqlJoin * obj) +static void sql_join_init (SqlJoin * self) { - obj->target_left = NULL; - obj->target_right = NULL; - obj->condition = NULL; - obj->using_fields = NULL; + self->target_left = NULL; + self->target_right = NULL; + self->condition = NULL; + self->using_fields = NULL; } -static void sql_join_finalize (SqlJoin * obj) +static void sql_join_finalize (SqlJoin * self) { - sql_object_remove (obj, obj->target_left); - sql_object_remove (obj, obj->target_right); - sql_object_remove (obj, obj->condition); - sql_object_remove (obj, obj->using_fields); - G_OBJECT_CLASS (sql_join_parent_class)->finalize (G_OBJECT (obj)); + sql_object_remove (self, self->target_left); + sql_object_remove (self, self->target_right); + sql_object_remove (self, self->condition); + sql_object_remove (self, self->using_fields); + G_OBJECT_CLASS (sql_join_parent_class)->finalize (G_OBJECT (self)); } static void sql_join_class_init (SqlJoinClass * klass) diff --git a/sql/sql-join.h b/sql/sql-join.h index 7e342c4..3058d3d 100644 --- a/sql/sql-join.h +++ b/sql/sql-join.h @@ -22,8 +22,8 @@ #include "sql-expr.h" #define SQL_TYPE_JOIN (sql_join_get_type ()) -#define SQL_IS_JOIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, SQL_TYPE_JOIN)) -#define SQL_JOIN(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, SQL_TYPE_JOIN, SqlJoin)) +#define SQL_IS_JOIN(self) (G_TYPE_CHECK_INSTANCE_TYPE (self, SQL_TYPE_JOIN)) +#define SQL_JOIN(self) (G_TYPE_CHECK_INSTANCE_CAST (self, SQL_TYPE_JOIN, SqlJoin)) #define SQL_TYPE_JOIN_TYPE (sql_join_type_get_type ()) @@ -60,8 +60,9 @@ GType sql_join_get_type (); GType sql_join_type_get_type (); SqlObject * sql_join_new (SqlTarget * left, SqlTarget * right, SqlJoinType type); -void sql_join_set_condition (SqlJoin * obj, SqlExpr * condition); -void sql_join_set_target_right (SqlJoin * obj, SqlTarget * target); -void sql_join_set_target_left (SqlJoin * obj, SqlTarget * target); +SqlJoinType sql_join_get_join_type (SqlJoin * self); +void sql_join_set_condition (SqlJoin * self, SqlExpr * condition); +void sql_join_set_target_right (SqlJoin * self, SqlTarget * target); +void sql_join_set_target_left (SqlJoin * self, SqlTarget * target); #endif \ No newline at end of file diff --git a/sql/sql-table.c b/sql/sql-table.c index e03e223..c2c3f0d 100644 --- a/sql/sql-table.c +++ b/sql/sql-table.c @@ -33,18 +33,68 @@ SqlObject * sql_table_new (const gchar * name, const gchar * schema) //+++++++++++++++++++++++++++++++++++++++++++++++++++ Private -static void sql_table_render (SqlTable * obj, SqlRender * render) +static void sql_table_render (SqlTable * self, SqlRender * render) { - 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->name); + sql_render_add_identifier (render, self->name); - if (g_strcmp0 (obj->name, SQL_TARGET (obj)->alias)) - sql_render_add_identifier (render, SQL_TARGET (obj)->alias); + if (SQL_TARGET (self)->alias) + sql_render_add_identifier (render, SQL_TARGET (self)->alias); +} + +//+++++++++++++++++++++++++++++++++++++++++++++++++++ Public + +/** + * sql_table_get_name: + * @self: the #SqlTable + * + * Return value: the table name + **/ +const gchar * sql_table_get_name (SqlTable * self) +{ + return self->name; +} + +/** + * sql_table_set_name: + * @self: the #SqlTable + * @target: the target name + **/ +void sql_table_set_name (SqlTable * self, const gchar * name) +{ + g_return_if_fail (SQL_IS_TABLE (self)); + + g_free (self->name); + self->name = g_strdup (name); +} + +/** + * sql_table_get_schema: + * @self: the #SqlTable + * + * Return value: the schema name + **/ +const gchar * sql_table_get_schema (SqlTable * self) +{ + return self->schema; +} + +/** + * sql_table_set_schema: + * @self: the #SqlTable + * @schema: the schema name + **/ +void sql_table_set_schema (SqlTable * self, const gchar * schema) +{ + g_return_if_fail (SQL_IS_TABLE (self)); + + g_free (self->schema); + self->schema = g_strdup (schema); } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties @@ -55,53 +105,53 @@ enum ,PROP_SCHEMA }; -static void sql_table_set_property (SqlTable * obj, guint id, +static void sql_table_set_property (SqlTable * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_NAME: - g_free (obj->name); - obj->name = g_value_dup_string (value); + g_free (self->name); + self->name = g_value_dup_string (value); break; case PROP_SCHEMA: - g_free (obj->schema); - obj->schema = g_value_dup_string (value); + g_free (self->schema); + self->schema = g_value_dup_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_table_get_property (SqlTable * obj, guint id, +static void sql_table_get_property (SqlTable * 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_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_table_init (SqlTable * obj) +static void sql_table_init (SqlTable * self) { - obj->name = NULL; - obj->schema = NULL; + self->name = NULL; + self->schema = NULL; } -static void sql_table_finalize (SqlTable * obj) +static void sql_table_finalize (SqlTable * self) { - g_free (obj->name); - g_free (obj->schema); - G_OBJECT_CLASS (sql_table_parent_class)->finalize (G_OBJECT (obj)); + g_free (self->name); + g_free (self->schema); + G_OBJECT_CLASS (sql_table_parent_class)->finalize (G_OBJECT (self)); } static void sql_table_class_init (SqlTableClass * klass) diff --git a/sql/sql-table.h b/sql/sql-table.h index ed7f5b6..62c4fc1 100644 --- a/sql/sql-table.h +++ b/sql/sql-table.h @@ -21,8 +21,8 @@ #include "sql-target.h" #define SQL_TYPE_TABLE (sql_table_get_type ()) -#define SQL_TABLE(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, SQL_TYPE_TABLE, SqlTable)) -#define SQL_IS_TABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, SQL_TYPE_TABLE)) +#define SQL_TABLE(self) (G_TYPE_CHECK_INSTANCE_CAST (self, SQL_TYPE_TABLE, SqlTable)) +#define SQL_IS_TABLE(self) (G_TYPE_CHECK_INSTANCE_TYPE (self, SQL_TYPE_TABLE)) typedef struct _SqlTable SqlTable; typedef struct _SqlTableClass SqlTableClass; @@ -40,7 +40,11 @@ struct _SqlTableClass SqlTargetClass parent; }; -GType sql_table_get_type (); -SqlObject * sql_table_new (const gchar * name, const gchar * schema); +GType sql_table_get_type (); +SqlObject * sql_table_new (const gchar * name, const gchar * schema); +const gchar * sql_table_get_name (SqlTable * self); +void sql_table_set_name (SqlTable * self, const gchar * name); +const gchar * sql_table_get_schema (SqlTable * self); +void sql_table_set_schema (SqlTable * self, const gchar * schema); #endif diff --git a/sql/sql-target.c b/sql/sql-target.c index 8213d9a..703867d 100644 --- a/sql/sql-target.c +++ b/sql/sql-target.c @@ -29,12 +29,28 @@ G_DEFINE_ABSTRACT_TYPE (SqlTarget, sql_target, SQL_TYPE_OBJECT); //+++++++++++++++++++++++++++++++++++++++++++++++++++ Public -void sql_target_set_alias (SqlTarget * obj, const gchar * alias) +/** + * sql_target_set_alias: + * @self: the #SqlTargetClass + * @alias: the target alias + **/ +void sql_target_set_alias (SqlTarget * self, const gchar * alias) { - g_return_if_fail (SQL_IS_TARGET (obj)); + g_return_if_fail (SQL_IS_TARGET (self)); - g_free (obj->alias); - obj->alias = g_strdup (alias); + g_free (self->alias); + self->alias = g_strdup (alias); +} + +/** + * sql_target_get_alias: + * @self: the #SqlTargetClass + **/ +const gchar * sql_target_get_alias (SqlTarget * self) +{ + g_return_if_fail (SQL_IS_TARGET (self)); + + return self->alias; } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Properties @@ -44,43 +60,43 @@ enum PROP_ALIAS = 1 }; -static void sql_target_set_property (SqlTarget * obj, guint id, +static void sql_target_set_property (SqlTarget * self, guint id, const GValue * value, GParamSpec * pspec) { switch (id) { case PROP_ALIAS: - sql_target_set_alias (obj, g_value_get_string (value)); + sql_target_set_alias (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_target_get_property (SqlTarget * obj, guint id, +static void sql_target_get_property (SqlTarget * self, guint id, GValue * value, GParamSpec * pspec) { switch (id) { case PROP_ALIAS: - g_value_set_string (value, obj->alias); + g_value_set_string (value, self->alias); break; default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, id, pspec); + G_OBJECT_WARN_INVALID_PROPERTY_ID (self, id, pspec); } } //+++++++++++++++++++++++++++++++++++++++++++++++++++ Class -static void sql_target_init (SqlTarget * obj) +static void sql_target_init (SqlTarget * self) { - obj->alias = NULL; + self->alias = NULL; } -static void sql_target_finalize (SqlTarget * obj) +static void sql_target_finalize (SqlTarget * self) { - g_free (obj->alias); - G_OBJECT_CLASS (sql_target_parent_class)->finalize (G_OBJECT (obj)); + g_free (self->alias); + G_OBJECT_CLASS (sql_target_parent_class)->finalize (G_OBJECT (self)); } static void sql_target_class_init (SqlTargetClass * k) diff --git a/sql/sql-target.h b/sql/sql-target.h index 43a20e4..bafd2b3 100644 --- a/sql/sql-target.h +++ b/sql/sql-target.h @@ -21,8 +21,8 @@ #include "sql-object.h" #define SQL_TYPE_TARGET (sql_target_get_type ()) -#define SQL_TARGET(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, SQL_TYPE_TARGET, SqlTarget)) -#define SQL_IS_TARGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, SQL_TYPE_TARGET)) +#define SQL_TARGET(self) (G_TYPE_CHECK_INSTANCE_CAST (self, SQL_TYPE_TARGET, SqlTarget)) +#define SQL_IS_TARGET(self) (G_TYPE_CHECK_INSTANCE_TYPE (self, SQL_TYPE_TARGET)) typedef struct _SqlTarget SqlTarget; typedef struct _SqlTargetClass SqlTargetClass; @@ -39,7 +39,8 @@ struct _SqlTargetClass SqlObjectClass parent; }; -GType sql_target_get_type (); -void sql_target_set_alias (SqlTarget * obj, const gchar * alias); +GType sql_target_get_type (); +void sql_target_set_alias (SqlTarget * self, const gchar * alias); +const gchar * sql_target_get_alias (SqlTarget * self); #endif \ No newline at end of file