[gnome-db] PATCH: gda_postgres_remove_row.



Hello,

Attached a patch for the remove_row method for Postgres. I made changes in 2 areas:

-1 data_model_hash implementation. In order to keep track of rows removed, I introduced an array to keep track of the active rows in a data model. The beauty of this is, that removed rows now physically do not show up in the data model. So all rows after the removed row will be renumbered without loosing their link with the original source like the Postgres cursor for instance.

-2 postgres recordset implementation. Added the remove_row functionality (among other changes see ChangeLog for that).

Attached patches for both head as 1.2. Please review. I have hit it very hard and so far I could not break it.  If patch is approved, all Postgres users should test against the latest cvs to find out if they run in any problems. If so, let me know the issue(s). I will continue testing in the next couple of days.

Thank you,
Bas.

Index: AUTHORS
===================================================================
RCS file: /cvs/gnome/libgda/AUTHORS,v
retrieving revision 1.16
diff -u -p -r1.16 AUTHORS
--- AUTHORS	11 Aug 2003 08:25:54 -0000	1.16
+++ AUTHORS	19 Jan 2005 10:05:52 -0000
@@ -11,3 +11,4 @@ Reinhard Muller <reinhard gnue org> (lib
 Holger Thon <holger thon gnome-db org> (gda-primebase, gda-sybase, gda-tds)
 Gerhard Dieringer <gdieringer compuserve com> (report, queries)
 Danilo Schoeneberg <dj starfire-programming net> (gda-msql,libgda)
+Bas Driessen <bas driessen xobas com> (gda-postgres, libgda)
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgda/ChangeLog,v
retrieving revision 1.732
diff -u -p -r1.732 ChangeLog
--- ChangeLog	15 Jan 2005 17:08:49 -0000	1.732
+++ ChangeLog	19 Jan 2005 10:05:58 -0000
@@ -1,3 +1,35 @@
+2005-01-19  Bas Driessen <bas driessen xobas com>
+
+	* libgda/gda-data-model-hash.c:
+	introduce row mapping array (row_map) to keep track
+	of active rows in a data-model that are represented
+	by a hash table. Array added to struct 
+	_GdaDataModelHashPrivate.
+	(gda_data_model_hash_remove_row): implemented
+	remove method function.
+	(gda_data_model_hash_append_row):
+	add new mapping entry to array when new row is 
+	appended to data-model.
+	(gda_data_model_hash_get_row):
+	get row according to mapping.
+	(gda_data_model_hash_get_n_rows):
+	return active number of rows in data-model or -1
+	if not initialized.
+	(gda_data_model_hash_clear):
+	initialize array upon (re)creation of hash table.
+	(gda_data_model_hash_init):
+	initialize array pointer and hash row count.
+	(gda_data_model_hash_finalize):
+	free array when no longer needed.
+
+	* providers/postgres/gda-postgres-recordset.c
+	(gda_postgres_recordset_remove_row):
+	implemented new method for data-model.
+	(gda_postgres_recordset_get_n_rows):
+	return active number of data-model rows.
+	(gda_postgres_recordset_get_row):
+	correct call to parent class function.	
+	
 2005-01-15  Rodrigo Moya <rodrigo gnome-db org>
 
 	* configure.in: include version number in AC_PROG_INTLTOOL.
Index: libgda/gda-data-model-hash.c
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-data-model-hash.c,v
retrieving revision 1.15
diff -u -p -r1.15 gda-data-model-hash.c
--- libgda/gda-data-model-hash.c	9 Jan 2005 21:00:55 -0000	1.15
+++ libgda/gda-data-model-hash.c	19 Jan 2005 10:06:02 -0000
@@ -1,10 +1,11 @@
 /* GDA library
- * Copyright (C) 1998 - 2004 The GNOME Foundation.
+ * Copyright (C) 1998 - 2005 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
  *	Gonzalo Paniagua Javier <gonzalo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
+ *	Bas Driessen <bas driessen xobas com>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -33,6 +34,10 @@ struct _GdaDataModelHashPrivate {
 
 	/* the hash of rows, each item is a GdaRow */
 	GHashTable *rows;
+	gint number_of_hash_table_rows;
+
+	/* the mapping of a row to hash table entry */
+	GArray *row_map;
 };
 
 static void gda_data_model_hash_class_init (GdaDataModelHashClass *klass);
@@ -50,7 +55,11 @@ static gint
 gda_data_model_hash_get_n_rows (GdaDataModelBase *model)
 {
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), -1);
-	return g_hash_table_size (GDA_DATA_MODEL_HASH (model)->priv->rows);
+
+	if (GDA_DATA_MODEL_HASH (model)->priv->row_map == NULL)
+		return -1;
+	else
+		return GDA_DATA_MODEL_HASH (model)->priv->row_map->len;
 }
 
 static gint
@@ -63,10 +72,15 @@ gda_data_model_hash_get_n_columns (GdaDa
 static const GdaRow *
 gda_data_model_hash_get_row (GdaDataModelBase *model, gint row)
 {
+	gint hash_entry;
+
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), NULL);
 
+	/* get row according mapping */
+	hash_entry = g_array_index (GDA_DATA_MODEL_HASH (model)->priv->row_map, gint, row);
+
 	return (const GdaRow *) g_hash_table_lookup (GDA_DATA_MODEL_HASH (model)->priv->rows,
-						     GINT_TO_POINTER (row));
+						     GINT_TO_POINTER (hash_entry));
 }
 
 static const GdaValue *
@@ -102,7 +116,7 @@ static const GdaRow *
 gda_data_model_hash_append_row (GdaDataModelBase *model, const GList *values)
 {
 	GdaRow *row;
-	gint cols, rownum;
+	gint cols, rownum_hash_new, rownum_array_new;
 
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), NULL);
 	g_return_val_if_fail (values != NULL, NULL);
@@ -114,17 +128,27 @@ gda_data_model_hash_append_row (GdaDataM
 	/* create the GdaRow to add */
 	row = gda_row_new_from_list (GDA_DATA_MODEL (model), values);
 
-	/* get the new row number */
-	rownum = gda_data_model_get_n_rows (GDA_DATA_MODEL (model));
+	/* get the new hash and array row number */
+	rownum_hash_new = GDA_DATA_MODEL_HASH (model)->priv->number_of_hash_table_rows;
+	rownum_array_new = GDA_DATA_MODEL_HASH (model)->priv->row_map->len;
 
 	if (row) {
 		gda_data_model_hash_insert_row (
 			GDA_DATA_MODEL_HASH (model),
-			rownum,
+			rownum_hash_new,
 			row);
 
-		gda_row_set_number (row, rownum);
-		gda_data_model_row_inserted (GDA_DATA_MODEL (model), rownum);
+		gda_row_set_number (row, rownum_array_new);
+
+		/* Append row number in row mapping array */
+		g_array_append_val (GDA_DATA_MODEL_HASH (model)->priv->row_map, rownum_hash_new);
+
+		/* emit update signals */
+		gda_data_model_row_inserted (GDA_DATA_MODEL (model), rownum_array_new);
+		gda_data_model_changed (GDA_DATA_MODEL (model));
+
+		/* increment the number of entries in the hash table */
+		GDA_DATA_MODEL_HASH (model)->priv->number_of_hash_table_rows++;
 	}
 
 	return row;
@@ -133,8 +157,37 @@ gda_data_model_hash_append_row (GdaDataM
 static gboolean
 gda_data_model_hash_remove_row (GdaDataModelBase *model, const GdaRow *row)
 {
+	gint i, cols, rownum;
+	GdaValue *value;
+
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), FALSE);
-	return FALSE;
+	g_return_val_if_fail (row != NULL, FALSE);
+
+	cols = GDA_DATA_MODEL_HASH (model)->priv->number_of_columns;
+
+	for (i=0; i<cols; i++) {
+		value = (GdaValue *) gda_row_get_value ((GdaRow *) row, i);
+		gda_value_set_string (value, "NULL");
+	}
+
+	rownum = gda_row_get_number ((GdaRow *) row);
+
+	/* renumber following rows */
+	for (i=(rownum+1); i<GDA_DATA_MODEL_HASH (model)->priv->row_map->len; i++) 
+		gda_row_set_number ((GdaRow *) gda_data_model_get_row (GDA_DATA_MODEL (model), i), (i-1));
+
+	/* tag the row as being removed */	
+	gda_row_set_id ((GdaRow *) row, "R");
+	gda_row_set_number ((GdaRow *) row, -1);
+
+	/* remove entry from array */
+	g_array_remove_index (GDA_DATA_MODEL_HASH (model)->priv->row_map, rownum);
+
+	/* emit updated signals */
+	gda_data_model_row_removed (GDA_DATA_MODEL (model), gda_row_get_number ((GdaRow *) row));
+	gda_data_model_changed (GDA_DATA_MODEL (model));
+	
+	return TRUE;
 }
 
 static void
@@ -170,7 +223,9 @@ gda_data_model_hash_init (GdaDataModelHa
 	/* allocate internal structure */
 	model->priv = g_new0 (GdaDataModelHashPrivate, 1);
 	model->priv->number_of_columns = 0;
+	model->priv->number_of_hash_table_rows = 0;
 	model->priv->rows = NULL;
+	model->priv->row_map = NULL;
 }
 
 static void
@@ -184,6 +239,8 @@ gda_data_model_hash_finalize (GObject *o
 	g_hash_table_destroy (model->priv->rows);
 	model->priv->rows = NULL;
 
+	g_array_free (model->priv->row_map, TRUE);
+
 	g_free (model->priv);
 	model->priv = NULL;
 
@@ -303,6 +360,8 @@ gda_data_model_hash_set_n_columns (GdaDa
 void
 gda_data_model_hash_clear (GdaDataModelHash *model)
 {
+	gint i;
+
 	g_return_if_fail (GDA_IS_DATA_MODEL_HASH (model));
 
 	if (model->priv->rows != NULL)
@@ -310,5 +369,23 @@ gda_data_model_hash_clear (GdaDataModelH
 	model->priv->rows = g_hash_table_new_full (g_direct_hash,
 						   g_direct_equal,
 						   NULL, free_hash);
+
+	/* free array if exists */
+	if (model->priv->row_map != NULL)
+	{
+		g_array_free (model->priv->row_map, TRUE);
+		model->priv->row_map = NULL;
+	}
+
+	/* get number of entries in data model */
+	model->priv->number_of_hash_table_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (model));
+
+	/* create row mapping array */
+	model->priv->row_map = g_array_new (FALSE, FALSE, sizeof (gint));
+
+        /* Initialize row mapping array */
+        for (i = 0; i < model->priv->number_of_hash_table_rows; i++)
+                g_array_append_val (model->priv->row_map, i);
+
 }
 
Index: providers/postgres/gda-postgres-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/postgres/gda-postgres-recordset.c,v
retrieving revision 1.37
diff -u -p -r1.37 gda-postgres-recordset.c
--- providers/postgres/gda-postgres-recordset.c	15 Jan 2005 16:36:08 -0000	1.37
+++ providers/postgres/gda-postgres-recordset.c	19 Jan 2005 10:06:04 -0000
@@ -1,11 +1,12 @@
 /* GDA Postgres provider
- * Copyright (C) 1998 - 2004 The GNOME Foundation
+ * Copyright (C) 1998 - 2005 The GNOME Foundation
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
  *	Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *      Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *      Bas Driessen <bas driessen xobas com>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -58,6 +59,7 @@ static GdaDataModelColumnAttributes *gda
 static gint gda_postgres_recordset_get_n_rows 		      (GdaDataModelBase *model);
 static const GdaRow *gda_postgres_recordset_get_row 	      (GdaDataModelBase *model, gint rownum);
 static const GdaRow *gda_postgres_recordset_append_row        (GdaDataModelBase *model, const GList *values);
+static gboolean gda_postgres_recordset_remove_row 	      (GdaDataModelBase *model, const GdaRow *row);
 static gboolean gda_postgres_recordset_update_row 	      (GdaDataModelBase *model, const GdaRow *row);
 
 static GObjectClass *parent_class = NULL;
@@ -92,6 +94,7 @@ gda_postgres_recordset_class_init (GdaPo
 	model_class->get_value_at = gda_postgres_recordset_get_value_at;
 	model_class->get_row = gda_postgres_recordset_get_row;
 	model_class->append_row = gda_postgres_recordset_append_row;
+	model_class->remove_row = gda_postgres_recordset_remove_row;
 	model_class->update_row = gda_postgres_recordset_update_row;
 }
 
@@ -178,7 +181,7 @@ gda_postgres_recordset_get_row (GdaDataM
 	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
 	g_return_val_if_fail (recset->priv != NULL, 0);
 
-	row_list = (GdaRow *) gda_data_model_hash_get_row (model, row);
+	row_list = (GdaRow *) GDA_DATA_MODEL_BASE_CLASS (parent_class)->get_row (model, row);
 	if (row_list != NULL)
 		return (const GdaRow *)row_list;
 
@@ -312,12 +315,115 @@ gda_postgres_recordset_append_row (GdaDa
 	else
 		gda_connection_add_error (priv_data->cnc,
 					  gda_postgres_make_error (pg_conn, NULL));
+
+	/* append row in hash table */
 	row = GDA_DATA_MODEL_BASE_CLASS (parent_class)->append_row (model, values);
 
 	return row;
 }
 
 static gboolean
+gda_postgres_recordset_remove_row (GdaDataModelBase *model, const GdaRow *row)
+{
+	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
+	GdaPostgresRecordsetPrivate *priv_data;
+	gint colnum, uk, i;
+	PGresult *pg_res, *pg_rm_res;
+	gchar *query, *query_where, *tmp;
+	GdaPostgresConnectionData *cnc_priv_data;
+	PGconn *pg_conn;
+	gboolean status = FALSE;
+	GdaValue *value;
+
+	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), FALSE);
+	g_return_val_if_fail (recset->priv != NULL, FALSE);
+	g_return_val_if_fail (row != NULL, FALSE);
+
+	priv_data = recset->priv;
+	pg_res = priv_data->pg_res;
+	cnc_priv_data = g_object_get_data (G_OBJECT (priv_data->cnc),
+					   OBJECT_DATA_POSTGRES_HANDLE);
+	pg_conn = cnc_priv_data->pconn;
+
+	/* checks if the given row belongs to the given model */
+	if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Given row doesn't belong to the model."));
+		return FALSE;
+	}
+
+	/* checks if the table name has been guessed */
+	if (priv_data->table_name == NULL) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Table name could not be guessed."));
+		return FALSE;
+	}
+
+	query_where = g_strdup ("WHERE TRUE ");
+
+	for (colnum = uk = 0;
+	     colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL(model));
+	     colnum++)
+	{
+		GdaDataModelColumnAttributes *attrs = gda_data_model_describe_column (GDA_DATA_MODEL(model), colnum);
+		const gchar *column_name = PQfname (pg_res, colnum);
+		gchar *curval = gda_value_stringify (gda_row_get_value ((GdaRow *) row, colnum));
+
+		/* unique column: we will use it as an index */
+		if (gda_field_attributes_get_primary_key (attrs) ||
+		    gda_field_attributes_get_unique_key (attrs))
+		{
+			/* fills the 'where' part of the update command */
+			tmp = g_strdup_printf ("AND %s = '%s' ",
+					       column_name,
+					       curval);
+			query_where = g_strconcat (query_where, tmp, NULL);
+			g_free (tmp);
+			uk++;
+		}
+
+		g_free (curval);
+		gda_field_attributes_free (attrs);
+	}
+
+	if (uk == 0) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Model doesn't have at least one unique key."));
+	}
+	else {
+		/* build the delete command */
+		query = g_strdup_printf ("DELETE FROM %s %s",
+					 priv_data->table_name,
+					 query_where);
+
+		/* remove the row */
+		pg_rm_res = PQexec (pg_conn, query);
+		g_free (query);
+
+		if (pg_rm_res != NULL) {
+			/* removal ok! */
+			if (PQresultStatus (pg_rm_res) == PGRES_COMMAND_OK)
+				status = TRUE;
+			else
+				gda_connection_add_error (priv_data->cnc,
+							  gda_postgres_make_error (pg_conn, pg_rm_res));
+			PQclear (pg_rm_res);
+		}
+		else
+			gda_connection_add_error (priv_data->cnc,
+						  gda_postgres_make_error (pg_conn, NULL));
+	}
+
+	g_free (query_where);
+
+	/* remove entry from data model */
+	if (status == TRUE)
+		status = GDA_DATA_MODEL_BASE_CLASS (parent_class)->remove_row (model, row);
+
+	return status;
+}
+
+static gboolean
 gda_postgres_recordset_update_row (GdaDataModelBase *model, const GdaRow *row)
 {
 	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
@@ -654,7 +760,12 @@ gda_postgres_recordset_get_n_rows (GdaDa
 	g_return_val_if_fail (recset->priv != NULL, 0);
 
 	parent_row_num = GDA_DATA_MODEL_BASE_CLASS (parent_class)->get_n_rows (model);
-	return MAX(recset->priv->nrows, parent_row_num);
+
+	/* if not initialized return number of PQ Tuples */
+	if (parent_row_num < 0)
+		return recset->priv->nrows;
+	else
+		return parent_row_num;
 }
 
 /*
Index: AUTHORS
===================================================================
RCS file: /cvs/gnome/libgda/AUTHORS,v
retrieving revision 1.16
diff -u -p -r1.16 AUTHORS
--- AUTHORS	11 Aug 2003 08:25:54 -0000	1.16
+++ AUTHORS	19 Jan 2005 10:06:50 -0000
@@ -11,3 +11,4 @@ Reinhard Muller <reinhard gnue org> (lib
 Holger Thon <holger thon gnome-db org> (gda-primebase, gda-sybase, gda-tds)
 Gerhard Dieringer <gdieringer compuserve com> (report, queries)
 Danilo Schoeneberg <dj starfire-programming net> (gda-msql,libgda)
+Bas Driessen <bas driessen xobas com> (gda-postgres,libgda)
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgda/ChangeLog,v
retrieving revision 1.723.2.6
diff -u -p -r1.723.2.6 ChangeLog
--- ChangeLog	15 Jan 2005 17:10:35 -0000	1.723.2.6
+++ ChangeLog	19 Jan 2005 10:06:55 -0000
@@ -1,3 +1,35 @@
+2005-01-19  Bas Driessen <bas driessen xobas com>
+
+	* libgda/gda-data-model-hash.c:
+	introduce row mapping array (row_map) to keep track
+	of active rows in a data-model that are represented
+	by a hash table. Array added to struct
+	_GdaDataModelHashPrivate.
+	(gda_data_model_hash_remove_row): implemented
+	remove method function.
+	(gda_data_model_hash_append_row):
+	add new mapping entry to array when new row is
+	appended to data-model.
+	(gda_data_model_hash_get_row):
+	get row according to mapping.
+	(gda_data_model_hash_get_n_rows):
+	return active number of rows in data-model or -1
+	if not initialized.
+	(gda_data_model_hash_clear):
+	initialize array upon (re)creation of hash table.
+	(gda_data_model_hash_init):
+	initialize array pointer and hash row count.
+	(gda_data_model_hash_finalize):
+	free array when no longer needed.
+
+	* providers/postgres/gda-postgres-recordset.c
+	(gda_postgres_recordset_remove_row):
+	implemented new method for data-model.
+	(gda_postgres_recordset_get_n_rows):
+	return active number of data-model rows.
+	(gda_postgres_recordset_get_row):
+	correct call to parent class function.
+
 2005-01-15  Rodrigo Moya <rodrigo gnome-db org>
 
 	* configure.in: include version number in AC_PROG_INTLTOOL.
Index: libgda/gda-data-model-hash.c
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-data-model-hash.c,v
retrieving revision 1.12.2.2
diff -u -p -r1.12.2.2 gda-data-model-hash.c
--- libgda/gda-data-model-hash.c	7 Jan 2005 11:04:54 -0000	1.12.2.2
+++ libgda/gda-data-model-hash.c	19 Jan 2005 10:06:55 -0000
@@ -1,9 +1,10 @@
 /* GDA library
- * Copyright (C) 1998-2002 The GNOME Foundation.
+ * Copyright (C) 1998-2005 The GNOME Foundation.
  *
  * AUTHORS:
  *	Rodrigo Moya <rodrigo gnome-db org>
  *	Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *	Bas Driessen <bas driessen xobas com>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -32,6 +33,10 @@ struct _GdaDataModelHashPrivate {
 
 	/* the hash of rows, each item is a GdaRow */
 	GHashTable *rows;
+	gint number_of_hash_table_rows;
+
+	/* the mapping of a row to hash table entry */
+	GArray *row_map;
 };
 
 static void gda_data_model_hash_class_init (GdaDataModelHashClass *klass);
@@ -49,7 +54,11 @@ static gint
 gda_data_model_hash_get_n_rows (GdaDataModel *model)
 {
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), -1);
-	return g_hash_table_size (GDA_DATA_MODEL_HASH (model)->priv->rows);
+
+	if (GDA_DATA_MODEL_HASH (model)->priv->row_map == NULL)
+		return -1;
+	else
+		return GDA_DATA_MODEL_HASH (model)->priv->row_map->len;
 }
 
 static gint
@@ -78,7 +87,7 @@ static const GdaRow *
 gda_data_model_hash_append_row (GdaDataModel *model, const GList *values)
 {
 	GdaRow *row;
-	gint cols, rownum;
+	gint cols, rownum_hash_new, rownum_array_new;
 
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), NULL);
 	g_return_val_if_fail (values != NULL, NULL);
@@ -90,17 +99,26 @@ gda_data_model_hash_append_row (GdaDataM
 	/* create the GdaRow to add */
 	row = gda_row_new_from_list (model, values);
 
-	/* get the new row number */
-	rownum = gda_data_model_get_n_rows (model);
+	/* get the new hash and array row number */
+	rownum_hash_new = GDA_DATA_MODEL_HASH (model)->priv->number_of_hash_table_rows;
+	rownum_array_new = GDA_DATA_MODEL_HASH (model)->priv->row_map->len;
 
 	if (row) {
 		gda_data_model_hash_insert_row (
 			GDA_DATA_MODEL_HASH (model),
-			rownum,
+			rownum_hash_new,
 			row);
-		gda_row_set_number (row, rownum);
-		gda_data_model_row_inserted (model, rownum);
-		gda_data_model_changed (model);
+		gda_row_set_number (row, rownum_array_new);
+
+		/* append row number in row mapping array */
+		g_array_append_val (GDA_DATA_MODEL_HASH (model)->priv->row_map, rownum_hash_new);
+
+		/* emit update signals */
+		gda_data_model_row_inserted (GDA_DATA_MODEL (model), rownum_array_new);
+		gda_data_model_changed (GDA_DATA_MODEL (model));
+
+		/* increment the number of entries in the hash table */
+		GDA_DATA_MODEL_HASH (model)->priv->number_of_hash_table_rows++;
 	}
 
 	return row;
@@ -109,8 +127,37 @@ gda_data_model_hash_append_row (GdaDataM
 static gboolean
 gda_data_model_hash_remove_row (GdaDataModel *model, const GdaRow *row)
 {
+	gint i, cols, rownum;
+	GdaValue *value;
+
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), FALSE);
-	return FALSE;
+	g_return_val_if_fail (row != NULL, FALSE);
+
+	cols = GDA_DATA_MODEL_HASH (model)->priv->number_of_columns;
+
+	for (i=0; i<cols; i++) {
+		value = (GdaValue *) gda_row_get_value ((GdaRow *) row, i);
+		gda_value_set_string (value, "NULL");
+	}
+
+	rownum = gda_row_get_number ((GdaRow *) row);
+
+	/* renumber following rows */
+	for (i=(rownum+1); i<GDA_DATA_MODEL_HASH (model)->priv->row_map->len; i++)
+		gda_row_set_number ((GdaRow *) gda_data_model_get_row (GDA_DATA_MODEL (model), i), (i-1));
+
+	/* tag the row as being removed */
+	gda_row_set_id ((GdaRow *) row, "R");
+	gda_row_set_number ((GdaRow *) row, -1);
+
+	/* remove entry from array */
+	g_array_remove_index (GDA_DATA_MODEL_HASH (model)->priv->row_map, rownum);
+
+	/* emit updated signals */
+	gda_data_model_row_removed (GDA_DATA_MODEL (model), gda_row_get_number ((GdaRow *) row));
+	gda_data_model_changed (GDA_DATA_MODEL (model));
+
+	return TRUE;
 }
 
 static void
@@ -146,7 +193,9 @@ gda_data_model_hash_init (GdaDataModelHa
 	/* allocate internal structure */
 	model->priv = g_new0 (GdaDataModelHashPrivate, 1);
 	model->priv->number_of_columns = 0;
+	model->priv->number_of_hash_table_rows = 0;
 	model->priv->rows = NULL;
+	model->priv->row_map = NULL;
 }
 
 static void
@@ -160,6 +209,8 @@ gda_data_model_hash_finalize (GObject *o
 	g_hash_table_destroy (model->priv->rows);
 	model->priv->rows = NULL;
 
+	g_array_free (model->priv->row_map, TRUE);
+
 	g_free (model->priv);
 	model->priv = NULL;
 
@@ -284,10 +335,15 @@ gda_data_model_hash_insert_row (GdaDataM
 const GdaRow *
 gda_data_model_hash_get_row (GdaDataModel *model, gint row)
 {
+	gint hash_entry;
+
 	g_return_val_if_fail (GDA_IS_DATA_MODEL_HASH (model), NULL);
 
+	/* get row according mapping */
+	hash_entry = g_array_index (GDA_DATA_MODEL_HASH (model)->priv->row_map, gint, row);
+
 	return (const GdaRow *) g_hash_table_lookup (GDA_DATA_MODEL_HASH (model)->priv->rows,
-						     GINT_TO_POINTER (row));
+						     GINT_TO_POINTER (hash_entry));
 }
 
 /**
@@ -320,6 +376,8 @@ gda_data_model_hash_set_n_columns (GdaDa
 void
 gda_data_model_hash_clear (GdaDataModelHash *model)
 {
+	gint i;
+
 	g_return_if_fail (GDA_IS_DATA_MODEL_HASH (model));
 
 	if (model->priv->rows != NULL)
@@ -327,5 +385,22 @@ gda_data_model_hash_clear (GdaDataModelH
 	model->priv->rows = g_hash_table_new_full (g_direct_hash,
 						   g_direct_equal,
 						   NULL, free_hash);
+
+	/* free array if exists */
+	if (model->priv->row_map != NULL)
+	{
+		g_array_free (model->priv->row_map, TRUE);
+		model->priv->row_map = NULL;
+	}
+
+	/* get number of entries in data model */
+	model->priv->number_of_hash_table_rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (model));
+
+	/* create row mapping array */
+	model->priv->row_map = g_array_new (FALSE, FALSE, sizeof (gint));
+
+	/* Initialize row mapping array */
+	for (i = 0; i < model->priv->number_of_hash_table_rows; i++)
+		g_array_append_val (model->priv->row_map, i);
 }
 
Index: providers/postgres/gda-postgres-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/postgres/gda-postgres-recordset.c,v
retrieving revision 1.35.2.1
diff -u -p -r1.35.2.1 gda-postgres-recordset.c
--- providers/postgres/gda-postgres-recordset.c	15 Jan 2005 16:35:06 -0000	1.35.2.1
+++ providers/postgres/gda-postgres-recordset.c	19 Jan 2005 10:06:56 -0000
@@ -1,11 +1,12 @@
 /* GDA Postgres provider
- * Copyright (C) 1998-2002 The GNOME Foundation
+ * Copyright (C) 1998-2005 The GNOME Foundation
  *
  * AUTHORS:
  *      Michael Lausch <michael lausch at>
  *	Rodrigo Moya <rodrigo gnome-db org>
  *      Vivien Malerba <malerba gnome-db org>
  *      Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *	Bas Driessen <bas driessen xobas com>
  *
  * This Library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public License as
@@ -57,6 +58,7 @@ static GdaFieldAttributes *gda_postgres_
 static gint gda_postgres_recordset_get_n_rows 		      (GdaDataModel *model);
 static const GdaRow *gda_postgres_recordset_get_row 	      (GdaDataModel *model, gint rownum);
 static const GdaRow *gda_postgres_recordset_append_row        (GdaDataModel *model, const GList *values);
+static gboolean gda_postgres_recordset_remove_row 	      (GdaDataModel *model, const GdaRow *row);
 static gboolean gda_postgres_recordset_update_row 	      (GdaDataModel *model, const GdaRow *row);
 
 static GObjectClass *parent_class = NULL;
@@ -91,6 +93,7 @@ gda_postgres_recordset_class_init (GdaPo
 	model_class->get_value_at = gda_postgres_recordset_get_value_at;
 	model_class->get_row = gda_postgres_recordset_get_row;
 	model_class->append_row = gda_postgres_recordset_append_row;
+	model_class->remove_row = gda_postgres_recordset_remove_row;
 	model_class->update_row = gda_postgres_recordset_update_row;
 }
 
@@ -177,7 +180,7 @@ gda_postgres_recordset_get_row (GdaDataM
 	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), NULL);
 	g_return_val_if_fail (recset->priv != NULL, 0);
 
-	row_list = (GdaRow *) gda_data_model_hash_get_row (model, row);
+	row_list = (GdaRow *) GDA_DATA_MODEL_CLASS (parent_class)->get_row (model, row);
 	if (row_list != NULL)
 		return (const GdaRow *)row_list;
 
@@ -311,12 +314,115 @@ gda_postgres_recordset_append_row (GdaDa
 	else
 		gda_connection_add_error (priv_data->cnc,
 					  gda_postgres_make_error (pg_conn, NULL));
+
+	/* append row in hash table */
 	row = GDA_DATA_MODEL_CLASS (parent_class)->append_row (model, values);
 
 	return row;
 }
 
 static gboolean
+gda_postgres_recordset_remove_row (GdaDataModel *model, const GdaRow *row)
+{
+	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
+	GdaPostgresRecordsetPrivate *priv_data;
+	gint colnum, uk, i;
+	PGresult *pg_res, *pg_rm_res;
+	gchar *query, *query_where, *tmp;
+	GdaPostgresConnectionData *cnc_priv_data;
+	PGconn *pg_conn;
+	gboolean status = FALSE;
+	GdaValue *value;
+
+	g_return_val_if_fail (GDA_IS_POSTGRES_RECORDSET (recset), FALSE);
+	g_return_val_if_fail (recset->priv != NULL, FALSE);
+	g_return_val_if_fail (row != NULL, FALSE);
+
+	priv_data = recset->priv;
+	pg_res = priv_data->pg_res;
+	cnc_priv_data = g_object_get_data (G_OBJECT (priv_data->cnc),
+					   OBJECT_DATA_POSTGRES_HANDLE);
+	pg_conn = cnc_priv_data->pconn;
+
+	/* checks if the given row belongs to the given model */
+	if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Given row doesn't belong to the model."));
+		return FALSE;
+	}
+
+	/* checks if the table name has been guessed */
+	if (priv_data->table_name == NULL) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Table name could not be guessed."));
+		return FALSE;
+	}
+
+	query_where = g_strdup ("WHERE TRUE ");
+
+	for (colnum = uk = 0;
+	     colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL(model));
+	     colnum++)
+	{
+		GdaFieldAttributes *attrs = gda_data_model_describe_column (GDA_DATA_MODEL(model), colnum);
+		const gchar *column_name = PQfname (pg_res, colnum);
+		gchar *curval = gda_value_stringify (gda_row_get_value ((GdaRow *) row, colnum));
+
+		/* unique column: we will use it as an index */
+		if (gda_field_attributes_get_primary_key (attrs) ||
+			gda_field_attributes_get_unique_key (attrs))
+		{
+			/* fills the 'where' part of the update command */
+			tmp = g_strdup_printf ("AND %s = '%s' ",
+					       column_name,
+					       curval);
+			query_where = g_strconcat (query_where, tmp, NULL);
+			g_free (tmp);
+			uk++;
+		}
+
+		g_free (curval);
+		gda_field_attributes_free (attrs);
+	}
+
+	if (uk == 0) {
+		gda_connection_add_error_string (priv_data->cnc,
+						_("Model doesn't have at least one unique key."));
+	}
+	else {
+		/* build the delete command */
+		query = g_strdup_printf ("DELETE FROM %s %s",
+					 priv_data->table_name,
+					 query_where);
+
+		/* remove the row */
+		pg_rm_res = PQexec (pg_conn, query);
+		g_free (query);
+
+		if (pg_rm_res != NULL) {
+		/* removal ok! */
+			if (PQresultStatus (pg_rm_res) == PGRES_COMMAND_OK)
+				status = TRUE;
+			else
+				gda_connection_add_error (priv_data->cnc,
+							  gda_postgres_make_error (pg_conn, pg_rm_res));
+			PQclear (pg_rm_res);
+		}
+		else
+			gda_connection_add_error (priv_data->cnc,
+						  gda_postgres_make_error (pg_conn, NULL));
+	}
+
+	g_free (query_where);
+
+	/* remove entry from data model */
+	if (status == TRUE)
+		status = GDA_DATA_MODEL_CLASS (parent_class)->remove_row (model, row);
+
+	return status;
+}
+
+static gboolean
 gda_postgres_recordset_update_row (GdaDataModel *model, const GdaRow *row)
 {
 	GdaPostgresRecordset *recset = (GdaPostgresRecordset *) model;
@@ -652,7 +758,12 @@ gda_postgres_recordset_get_n_rows (GdaDa
 	g_return_val_if_fail (recset->priv != NULL, 0);
 
 	parent_row_num = GDA_DATA_MODEL_CLASS (parent_class)->get_n_rows (model);
-	return MAX(recset->priv->nrows, parent_row_num);
+
+	/* if not initialized return number of PQ Tuples */
+	if (parent_row_num < 0)
+		return recset->priv->nrows;
+	else
+		return parent_row_num;
 }
 
 /*


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]