[gnome-db] Minor API change and MySQL [update/delete]_row
- From: Paisa Seeluangsawat <paisa unt edu>
- To: GDA <gnome-db-list gnome org>
- Cc: Rodrigo Moya <rodrigo gnome-db org>, Laurent Sansonetti <laurent datarescue be>
- Subject: [gnome-db] Minor API change and MySQL [update/delete]_row
- Date: Sat, 25 Oct 2003 21:18:43 -0500
Here's an alpha code for MySql updating and deleting row--only work
when there's a unique, non-null key (ahem ;-). There are still a few
FIXME's in the code. It also prints out the sql query for your
debugging pleasure. These will go away in a few weeks. I'm just
going by 'commit early, commit often' :-).
No one replied to my last e-mail about the 'const' issue, and adding
gda_data_model_get_updatable_row(). So, taking silence as
consent...I...err...I... Don't be mad at me, OK?
There's a family of functions that I couldn't find any code using
them. Since they sound like an old, unused updating scheme, I removed
them.
- gda_data_model_begin_edit(),
- gda_data_model_end_edit(),
- gda_data_model_cancel_edit(),
- gda_data_model_is_editing()
Other minor changes are documented in ChangeLog
There are functions that are only useful to providers, and end users
shouldn't have to learn them. May I move this into a separate header?
Paisa
Index: ChangeLog
===================================================================
RCS file: /cvs/gnome/libgda/ChangeLog,v
retrieving revision 1.581
diff -u -r1.581 ChangeLog
--- ChangeLog 18 Oct 2003 23:10:39 -0000 1.581
+++ ChangeLog 26 Oct 2003 00:49:25 -0000
@@ -1,3 +1,45 @@
+2003-10-25 Paisa Seeluangsawat <paisa users sf net>
+
+ *gda-blob.c: fixed return type mismatch in gda_blob_free_data()
+
+ *gda-data-model.[hc]:
+ providers/ldap/gda-ldap-recordset.c:
+ providers/msql/gda-msql-recordset.c:
+ providers/oracle/gda-oracle-recordset.c:
+ removed
+ gda_data_model_begin_edit(),
+ gda_data_model_end_edit(),
+ gda_data_model_cancel_edit(),
+ gda_data_model_is_editing()
+ and their related codes
+
+ *gda-data-model.[hc]
+ - inserted const's
+ - marks functions that are only of use to providers and
+ hopefully will go into a separate header.
+ - updated some doc comments.
+ - added gda_data_model_get_updatable_row()
+ - gda_data_model_foreach()
+ - stop the loop when user function returns FALSE (as
+ advertised in the spec).
+ - GdaDataModelForeachFunc now takes 'const GdaRow*' so
+ stop cloning GdaRow.
+
+ *gda-row.[hc]
+ - inserted const's
+ - marks functions that are only of use to providers.
+ - updated some doc comments.
+ - added gda_row_get_updatable_value()
+
+ *gda-mysql-provider.c
+ - get_table_fields(): removed 13 lines of error handling
+ that would never be reached (according to mysql doc).
+
+ *gda-mysql-recordset.c
+ - added gda_data_model_get_updatable_row()
+ - implemented gda_data_model_get_updatable_row()
+ - implemented gda_data_model_get_updatable_row()
+
2003-10-19 Laurent Sansonetti <laurent datarescue be>
* doc/C/examples/full_example.c:
Index: libgda/gda-blob.c
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-blob.c,v
retrieving revision 1.2
diff -u -r1.2 gda-blob.c
--- libgda/gda-blob.c 16 Aug 2003 20:38:55 -0000 1.2
+++ libgda/gda-blob.c 26 Oct 2003 00:49:25 -0000
@@ -158,9 +158,9 @@
void
gda_blob_free_data (GdaBlob *blob)
{
- g_return_val_if_fail (blob != NULL, -1);
+ g_return_if_fail (blob != NULL);
g_return_if_fail (blob->free_data != NULL);
- return blob->free_data (blob);
+ blob->free_data (blob);
}
Index: libgda/gda-data-model.c
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-data-model.c,v
retrieving revision 1.38
diff -u -r1.38 gda-data-model.c
--- libgda/gda-data-model.c 18 Oct 2003 23:03:52 -0000 1.38
+++ libgda/gda-data-model.c 26 Oct 2003 00:49:26 -0000
@@ -51,9 +51,6 @@
ROW_INSERTED,
ROW_UPDATED,
ROW_REMOVED,
- BEGIN_EDIT,
- CANCEL_EDIT,
- END_EDIT,
LAST_SIGNAL
};
@@ -103,40 +100,14 @@
NULL, NULL,
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT);
- gda_data_model_signals[BEGIN_EDIT] =
- g_signal_new ("begin_edit",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GdaDataModelClass, begin_edit),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- gda_data_model_signals[CANCEL_EDIT] =
- g_signal_new ("cancel_edit",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GdaDataModelClass, cancel_edit),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
- gda_data_model_signals[END_EDIT] =
- g_signal_new ("end_edit",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GdaDataModelClass, end_edit),
- NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
object_class->finalize = gda_data_model_finalize;
klass->changed = NULL;
- klass->begin_edit = NULL;
- klass->cancel_edit = NULL;
- klass->end_edit = NULL;
klass->get_n_rows = NULL;
klass->get_n_columns = NULL;
klass->describe_column = NULL;
klass->get_row = NULL;
+ klass->get_updatable_row = NULL;
klass->get_value_at = NULL;
klass->is_editable = NULL;
klass->append_row = NULL;
@@ -413,7 +384,7 @@
fa = gda_data_model_describe_column (model, col);
if (fa) {
- gda_data_model_set_column_title (model, col, title);
+ gda_data_model_set_column_title ((GdaDataModel*) model, col, title);
gda_field_attributes_free (fa);
return g_hash_table_lookup (model->priv->column_titles,
@@ -499,7 +470,8 @@
* @model: a #GdaDataModel object.
* @row: row number.
*
- * Retrieves a given row from a data model.
+ * Retrieves a given row from a data model. If you want non-const
+ * #GdaRow, use #gda_data_model_get_row.
*
* Returns: a #GdaRow object.
*/
@@ -513,6 +485,25 @@
}
/**
+ * gda_data_model_get_updatable_row
+ * @model: a #GdaDataModel object.
+ * @row: row number.
+ *
+ * Retrieves an editable row from a data model.
+ *
+ * Returns: a #GdaRow object. #NULL if fail.
+ */
+GdaRow *
+gda_data_model_get_updatable_row (GdaDataModel *model, gint row)
+{
+ g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL);
+ g_return_val_if_fail (CLASS (model)->get_updatable_row != NULL, NULL);
+
+ return CLASS (model)->get_updatable_row (model, row);
+}
+
+
+/**
* gda_data_model_get_value_at
* @model: a #GdaDataModel object.
* @col: column number.
@@ -539,9 +530,9 @@
* gda_data_model_is_editable
* @model: a #GdaDataModel object.
*
- * Checks whether the given data model can be edited or not.
+ * Cursoriry checks whether the given data model can be edited or not.
*
- * Returns: %TRUE if it can be edited, %FALSE if not.
+ * Returns: %TRUE you might (just might) be able to update or insert rows, %FALSE if you can not.
*/
gboolean
gda_data_model_is_editable (GdaDataModel *model)
@@ -555,7 +546,9 @@
/**
* gda_data_model_append_row
* @model: a #GdaDataModel object.
- * @values: the row to add.
+ * @values: #GList of #GdaValue* representing the row to add. The
+ * length must match model's column count. These #GdaValue
+ * are value-copied. The user is still responsible for freeing them.
*
* Appends a row to the given data model.
*
@@ -573,15 +566,16 @@
/**
* gda_data_model_remove_row
* @model: a #GdaDataModel object.
- * @row: the #GdaRow to be removed.
+ * @row: a #GdaRow returned from #gda_data_model_get_updatable_row.
*
* Removes a row from the data model. This results in the underlying
- * database row being removed in the database.
+ * database row being removed in the database. If succeed, row is no
+ * longer useable.
*
* Returns: %TRUE if successful, %FALSE otherwise.
*/
gboolean
-gda_data_model_remove_row (GdaDataModel *model, const GdaRow *row)
+gda_data_model_remove_row (GdaDataModel *model, GdaRow *row)
{
g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
g_return_val_if_fail (row != NULL, FALSE);
@@ -593,15 +587,16 @@
/**
* gda_data_model_update_row
* @model: a #GdaDataModel object.
- * @row: the #GdaRow to be updated.
+ * @row: a #GdaRow returned from #gda_data_model_get_updatable_row.
*
* Updates a row data model. This results in the underlying
- * database row's values being changed.
+ * database row's values being changed. If succeed, row is no
+ * longer useable.
*
* Returns: %TRUE if successful, %FALSE otherwise.
*/
gboolean
-gda_data_model_update_row (GdaDataModel *model, const GdaRow *row)
+gda_data_model_update_row (GdaDataModel *model, GdaRow *row)
{
g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
g_return_val_if_fail (row != NULL, FALSE);
@@ -610,6 +605,8 @@
return CLASS (model)->update_row (model, row);
}
+
+
/**
* gda_data_model_foreach
* @model: a #GdaDataModel object.
@@ -634,118 +631,23 @@
GdaDataModelForeachFunc func,
gpointer user_data)
{
- gint cols;
gint rows;
- gint c, r;
- GdaRow *row;
+ gint r;
+ const GdaRow *row;
g_return_if_fail (GDA_IS_DATA_MODEL (model));
g_return_if_fail (func != NULL);
rows = gda_data_model_get_n_rows (model);
- cols = gda_data_model_get_n_columns (model);
-
- for (r = 0; r < rows; r++) {
- row = gda_row_new (model, cols);
- for (c = 0; c < cols; c++) {
- GdaValue *value;
- value = gda_value_copy (gda_data_model_get_value_at (model, c, r));
- memcpy (gda_row_get_value (row, c), value, sizeof (GdaValue));
- }
-
+ gboolean more = TRUE;
+ for (r = 0; more && r < rows ; r++) {
+ row = gda_data_model_get_row (model, r);
/* call the callback function */
- func (model, row, user_data);
-
- gda_row_free (row);
+ more = func (model, row, user_data);
}
}
-/**
- * gda_data_model_is_editing
- * @model: a #GdaDataModel object.
- *
- * Checks whether this data model is in editing mode or not. Editing
- * mode is set to %TRUE when @gda_data_model_begin_edit has been
- * called successfully, and is not set back to %FALSE until either
- * @gda_data_model_cancel_edit or @gda_data_model_end_edit have
- * been called.
- *
- * Returns: %TRUE if editing mode, %FALSE otherwise.
- */
-gboolean
-gda_data_model_is_editing (GdaDataModel *model)
-{
- g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
- return model->priv->editing;
-}
-/**
- * gda_data_model_begin_edit
- * @model: a #GdaDataModel object.
- *
- * Starts edition of this data model. This function should be the
- * first called when modifying the data model.
- *
- * Returns: %TRUE on success, %FALSE if there was an error.
- */
-gboolean
-gda_data_model_begin_edit (GdaDataModel *model)
-{
- g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
- g_return_val_if_fail (model->priv->editing == FALSE, FALSE);
-
- if (!gda_data_model_is_editable (model)) {
- gda_log_error (_("Data model %p is not editable"), model);
- return FALSE;
- }
-
- model->priv->editing = TRUE;
- g_signal_emit (G_OBJECT (model), gda_data_model_signals[BEGIN_EDIT], 0);
-
- return model->priv->editing;
-}
-
-/**
- * gda_data_model_cancel_edit
- * @model: a #GdaDataModel object.
- *
- * Cancels edition of this data model. This means that all changes
- * will be discarded, and the old data put back in the model.
- *
- * Returns: %TRUE on success, %FALSE if there was an error.
- */
-gboolean
-gda_data_model_cancel_edit (GdaDataModel *model)
-{
- g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
- g_return_val_if_fail (model->priv->editing, FALSE);
-
- g_signal_emit (G_OBJECT (model), gda_data_model_signals[CANCEL_EDIT], 0);
- model->priv->editing = FALSE;
-
- return TRUE;
-}
-
-/**
- * gda_data_model_end_edit
- * @model: a #GdaDataModel object.
- *
- * Approves all modifications and send them to the underlying
- * data source/store.
- *
- * Returns: %TRUE on success, %FALSE if there was an error.
- */
-gboolean
-gda_data_model_end_edit (GdaDataModel *model)
-{
- g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
- g_return_val_if_fail (model->priv->editing, FALSE);
-
- g_signal_emit (G_OBJECT (model), gda_data_model_signals[END_EDIT], 0);
- model->priv->editing = FALSE;
-
- return TRUE;
-}
static gchar *
export_to_separated (GdaDataModel *model, gchar sep)
Index: libgda/gda-data-model.h
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-data-model.h,v
retrieving revision 1.22
diff -u -r1.22 gda-data-model.h
--- libgda/gda-data-model.h 18 Oct 2003 23:03:52 -0000 1.22
+++ libgda/gda-data-model.h 26 Oct 2003 00:49:26 -0000
@@ -55,29 +55,22 @@
void (* row_updated) (GdaDataModel *model, gint row);
void (* row_removed) (GdaDataModel *model, gint row);
- void (* begin_edit) (GdaDataModel *model);
- void (* cancel_edit) (GdaDataModel *model);
- void (* end_edit) (GdaDataModel *model);
-
/* virtual methods */
gint (* get_n_rows) (GdaDataModel *model);
gint (* get_n_columns) (GdaDataModel *model);
GdaFieldAttributes * (* describe_column) (GdaDataModel *model, gint col);
const GdaRow * (* get_row) (GdaDataModel *model, gint row);
+ GdaRow * (* get_updatable_row) (GdaDataModel *model, gint row);
const GdaValue * (* get_value_at) (GdaDataModel *model, gint col, gint row);
gboolean (* is_editable) (GdaDataModel *model);
const GdaRow * (* append_row) (GdaDataModel *model, const GList *values);
- gboolean (* remove_row) (GdaDataModel *model, const GdaRow *row);
- gboolean (* update_row) (GdaDataModel *model, const GdaRow *row);
+ gboolean (* remove_row) (GdaDataModel *model, GdaRow *row);
+ gboolean (* update_row) (GdaDataModel *model, GdaRow *row);
};
GType gda_data_model_get_type (void);
-void gda_data_model_changed (GdaDataModel *model);
-void gda_data_model_row_inserted (GdaDataModel *model, gint row);
-void gda_data_model_row_updated (GdaDataModel *model, gint row);
-void gda_data_model_row_removed (GdaDataModel *model, gint row);
void gda_data_model_freeze (GdaDataModel *model);
void gda_data_model_thaw (GdaDataModel *model);
@@ -85,29 +78,25 @@
gint gda_data_model_get_n_columns (GdaDataModel *model);
GdaFieldAttributes *gda_data_model_describe_column (GdaDataModel *model, gint col);
const gchar *gda_data_model_get_column_title (GdaDataModel *model, gint col);
-void gda_data_model_set_column_title (GdaDataModel *model, gint col, const gchar *title);
gint gda_data_model_get_column_position (GdaDataModel *model, const gchar *title);
+
const GdaRow *gda_data_model_get_row (GdaDataModel *model, gint row);
+GdaRow *gda_data_model_get_updatable_row (GdaDataModel *model, gint row);
const GdaValue *gda_data_model_get_value_at (GdaDataModel *model, gint col, gint row);
gboolean gda_data_model_is_editable (GdaDataModel *model);
const GdaRow *gda_data_model_append_row (GdaDataModel *model, const GList *values);
-gboolean gda_data_model_remove_row (GdaDataModel *model, const GdaRow *row);
-gboolean gda_data_model_update_row (GdaDataModel *model, const GdaRow *row);
+gboolean gda_data_model_remove_row (GdaDataModel *model, GdaRow *row);
+gboolean gda_data_model_update_row (GdaDataModel *model, GdaRow *row);
typedef gboolean (* GdaDataModelForeachFunc) (GdaDataModel *model,
- GdaRow *row,
+ const GdaRow *row,
gpointer user_data);
void gda_data_model_foreach (GdaDataModel *model,
GdaDataModelForeachFunc func,
gpointer user_data);
-gboolean gda_data_model_is_editing (GdaDataModel *model);
-gboolean gda_data_model_begin_edit (GdaDataModel *model);
-gboolean gda_data_model_cancel_edit (GdaDataModel *model);
-gboolean gda_data_model_end_edit (GdaDataModel *model);
-
gchar *gda_data_model_to_comma_separated (GdaDataModel *model);
gchar *gda_data_model_to_tab_separated (GdaDataModel *model);
gchar *gda_data_model_to_xml (GdaDataModel *model, gboolean standalone);
@@ -115,10 +104,21 @@
gboolean gda_data_model_add_data_from_xml_node (GdaDataModel *model, xmlNodePtr node);
const gchar *gda_data_model_get_command_text (GdaDataModel *model);
-void gda_data_model_set_command_text (GdaDataModel *model, const gchar *txt);
GdaCommandType gda_data_model_get_command_type (GdaDataModel *model);
-void gda_data_model_set_command_type (GdaDataModel *model,
- GdaCommandType type);
+
+
+// FIXME: These hopefully will go into *_impl.h ================
+
+void gda_data_model_changed (GdaDataModel *model);
+void gda_data_model_row_inserted (GdaDataModel *model, gint row);
+void gda_data_model_row_updated (GdaDataModel *model, gint row);
+void gda_data_model_row_removed (GdaDataModel *model, gint row);
+
+void gda_data_model_set_column_title (GdaDataModel *model, gint col, const gchar *title);
+
+void gda_data_model_set_command_text (GdaDataModel *model, const gchar *txt);
+void gda_data_model_set_command_type (GdaDataModel *model, GdaCommandType type);
+
G_END_DECLS
Index: libgda/gda-row.c
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-row.c,v
retrieving revision 1.35
diff -u -r1.35 gda-row.c
--- libgda/gda-row.c 18 Oct 2003 23:03:52 -0000 1.35
+++ libgda/gda-row.c 26 Oct 2003 00:49:26 -0000
@@ -63,7 +63,8 @@
* @model: a #GdaDataModel.
* @values: a list of #GdaValue's.
*
- * Creates a #GdaRow from a list of #GdaValue's.
+ * Creates a #GdaRow from a list of #GdaValue's. These GdaValue's are
+ * value-copied and the user are still resposible for freeing them.
*
* Returns: the newly created row.
*/
@@ -76,12 +77,12 @@
row = gda_row_new (model, g_list_length ((GList *) values));
for (i = 0, l = values; l != NULL; l = l->next, i++) {
- const GdaValue *value = (const GdaValue *) l->data;
+ GdaValue *value = (GdaValue *) l->data;
if (value)
- gda_value_set_from_value (gda_row_get_value (row, i), value);
+ gda_value_set_from_value (gda_row_get_updatable_value (row, i), value);
else
- gda_value_set_null (gda_row_get_value (row, i));
+ gda_value_set_null (gda_row_get_updatable_value (row, i));
}
return row;
@@ -116,7 +117,7 @@
* Returns: a #GdaDataModel.
*/
GdaDataModel *
-gda_row_get_model (GdaRow *row)
+gda_row_get_model (const GdaRow *row)
{
g_return_val_if_fail (row != NULL, NULL);
return row->model;
@@ -132,7 +133,7 @@
* Returns: the row number, or -1 if there was an error.
*/
gint
-gda_row_get_number (GdaRow *row)
+gda_row_get_number (const GdaRow *row)
{
g_return_val_if_fail (row != NULL, -1);
return row->number;
@@ -166,7 +167,7 @@
* Returns: the unique identifier for this row.
*/
const gchar *
-gda_row_get_id (GdaRow *row)
+gda_row_get_id (const GdaRow *row)
{
g_return_val_if_fail (row != NULL, NULL);
return (const gchar *) row->id;
@@ -195,7 +196,9 @@
* @row: a #GdaRow (which contains #GdaValue).
* @num: field index.
*
- * Gets a pointer to a #GdaValue stored in a #GdaRow.
+ * Gets a const pointer to a #GdaValue stored in a #GdaRow. If you
+ * want non-const values (possible only from non-const #GdaRow), use
+ * #gda_row_get_updatable_value.
*
* This is a pointer to the internal array of values. Don't try to free
* or modify it!
@@ -203,7 +206,27 @@
* Returns: a pointer to the #GdaValue in the position @num of @row.
*/
G_CONST_RETURN GdaValue *
-gda_row_get_value (GdaRow *row, gint num)
+gda_row_get_value (const GdaRow *row, gint num)
+{
+ g_return_val_if_fail (row != NULL, NULL);
+ g_return_val_if_fail (num >= 0 && num < row->nfields, NULL);
+
+ return &row->fields[num];
+}
+
+/**
+ * gda_row_get_updatable_value
+ * @row: a #GdaRow (which contains #GdaValue).
+ * @num: field index.
+ *
+ * Gets a pointer to a #GdaValue stored in a #GdaRow.
+ *
+ * This is a pointer to the internal array of values. Don't try to free it!
+ *
+ * Returns: a pointer to the #GdaValue in the position @num of @row.
+ */
+GdaValue *
+gda_row_get_updatable_value (GdaRow *row, gint num)
{
g_return_val_if_fail (row != NULL, NULL);
g_return_val_if_fail (num >= 0 && num < row->nfields, NULL);
@@ -211,6 +234,7 @@
return &row->fields[num];
}
+
/**
* gda_row_get_length
* @row: a #GdaRow.
@@ -218,7 +242,7 @@
* Returns: the number of columns that the @row has.
*/
gint
-gda_row_get_length (GdaRow *row)
+gda_row_get_length (const GdaRow *row)
{
g_return_val_if_fail (row != NULL, 0);
return row->nfields;
Index: libgda/gda-row.h
===================================================================
RCS file: /cvs/gnome/libgda/libgda/gda-row.h,v
retrieving revision 1.26
diff -u -r1.26 gda-row.h
--- libgda/gda-row.h 12 May 2003 22:58:05 -0000 1.26
+++ libgda/gda-row.h 26 Oct 2003 00:49:26 -0000
@@ -31,16 +31,22 @@
typedef struct _GdaDataModel GdaDataModel;
typedef struct _GdaRow GdaRow;
-GdaRow *gda_row_new (GdaDataModel *model, gint count);
-GdaRow *gda_row_new_from_list (GdaDataModel *model, const GList *values);
-void gda_row_free (GdaRow *row);
-GdaDataModel *gda_row_get_model (GdaRow *row);
-gint gda_row_get_number (GdaRow *row);
-void gda_row_set_number (GdaRow *row, gint number);
-const gchar *gda_row_get_id (GdaRow *row);
-void gda_row_set_id (GdaRow *row, const gchar *id);
-G_CONST_RETURN GdaValue *gda_row_get_value (GdaRow *row, gint num);
-gint gda_row_get_length (GdaRow *row);
+GdaDataModel *gda_row_get_model (const GdaRow *row);
+gint gda_row_get_number (const GdaRow *row);
+gint gda_row_get_length (const GdaRow *row);
+G_CONST_RETURN GdaValue *gda_row_get_value (const GdaRow *row, gint num);
+GdaValue *gda_row_get_updatable_value (GdaRow *row, gint num);
+
+
+// FIXME These hopefully will go into *_impl.h ================
+
+GdaRow *gda_row_new (GdaDataModel *model, gint count);
+GdaRow *gda_row_new_from_list (GdaDataModel *model, const GList *values);
+void gda_row_free (GdaRow *row);
+void gda_row_set_number (GdaRow *row, gint number);
+
+void gda_row_set_id (GdaRow *row, const gchar *id);
+const gchar *gda_row_get_id (const GdaRow *row);
G_END_DECLS
Index: providers/ldap/gda-ldap-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/ldap/gda-ldap-recordset.c,v
retrieving revision 1.2
diff -u -r1.2 gda-ldap-recordset.c
--- providers/ldap/gda-ldap-recordset.c 16 Jan 2003 00:10:33 -0000 1.2
+++ providers/ldap/gda-ldap-recordset.c 26 Oct 2003 00:49:26 -0000
@@ -274,7 +274,6 @@
g_return_val_if_fail (GDA_IS_LDAP_RECORDSET (recset), NULL);
g_return_val_if_fail (values != NULL, NULL);
g_return_val_if_fail (gda_data_model_is_editable (model), NULL);
- g_return_val_if_fail (gda_data_model_is_editing (model), NULL);
/* cols = ldap_num_fields (recset->ldap_res);*/
if (cols != g_list_length ((GList *) values)) {
Index: providers/msql/gda-msql-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/msql/gda-msql-recordset.c,v
retrieving revision 1.3
diff -u -r1.3 gda-msql-recordset.c
--- providers/msql/gda-msql-recordset.c 19 Sep 2003 18:43:08 -0000 1.3
+++ providers/msql/gda-msql-recordset.c 26 Oct 2003 00:49:26 -0000
@@ -219,10 +219,9 @@
GdaMsqlRecordset *rs=(GdaMsqlRecordset*)model;
if ((!GDA_IS_MSQL_RECORDSET(rs)) ||
- (!values) || (!gda_data_model_is_editable(model)) ||
- (!gda_data_model_is_editing(model))) {
+ (!values) || (!gda_data_model_is_editable(model)))
return NULL;
- }
+
cols=msqlNumFields(rs->res);
if (cols!=g_list_length((GList*)values)) {
gda_connection_add_error_string(rs->cnc,
Index: providers/mysql/gda-mysql-provider.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/mysql/gda-mysql-provider.c,v
retrieving revision 1.46
diff -u -r1.46 gda-mysql-provider.c
--- providers/mysql/gda-mysql-provider.c 16 Oct 2003 22:58:06 -0000 1.46
+++ providers/mysql/gda-mysql-provider.c 26 Oct 2003 00:49:27 -0000
@@ -1138,20 +1138,7 @@
mysql_data_seek (mysql_res, r);
mysql_row = mysql_fetch_row (mysql_res);
- if (!mysql_row) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
-
value_list = field_row_to_value_list (mysql_row);
- if (!value_list) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
gda_data_model_append_row (GDA_DATA_MODEL (recset),
(const GList *) value_list);
Index: providers/mysql/gda-mysql-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/mysql/gda-mysql-recordset.c,v
retrieving revision 1.27
diff -u -r1.27 gda-mysql-recordset.c
--- providers/mysql/gda-mysql-recordset.c 16 Oct 2003 22:58:06 -0000 1.27
+++ providers/mysql/gda-mysql-recordset.c 26 Oct 2003 00:49:27 -0000
@@ -35,6 +35,13 @@
GdaMysqlRecordsetClass *klass);
static void gda_mysql_recordset_finalize (GObject *object);
+void fill_gda_value (GdaValue *gda_value, enum enum_field_types type,
+ gchar *value, unsigned long length);
+void find_key_columns (GdaMysqlRecordset *recset);
+void printfa_cols (GString *str, GdaMysqlRecordset *recset,
+ GdaRow *row, gint cols[], gboolean where);
+void set_id (GdaMysqlRecordset *recset, GdaRow *row);
+
static GObjectClass *parent_class = NULL;
/*
@@ -257,6 +264,20 @@
return (const GdaRow *) fields;
}
+static GdaRow *
+gda_mysql_recordset_get_updatable_row (GdaDataModel *model, gint row)
+{
+ g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (model), NULL);
+ GdaMysqlRecordset *recset = (GdaMysqlRecordset*) model;
+
+ find_key_columns (recset);
+ if (recset->key[0]==0) return NULL; // not updatable
+ GdaRow *gda_row = (GdaRow*) gda_mysql_recordset_get_row (model, row);
+ if (gda_row && !gda_row_get_id (gda_row))
+ set_id (recset, gda_row);
+ return gda_row;
+}
+
static const GdaValue *
gda_mysql_recordset_get_value_at (GdaDataModel *model, gint col, gint row)
{
@@ -300,7 +321,6 @@
g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), NULL);
g_return_val_if_fail (values != NULL, NULL);
g_return_val_if_fail (gda_data_model_is_editable (model), NULL);
- g_return_val_if_fail (gda_data_model_is_editing (model), NULL);
cols = mysql_num_fields (recset->mysql_res);
if (cols != g_list_length ((GList *) values)) {
@@ -354,7 +374,7 @@
sql = g_string_append (sql, ")");
/* execute the UPDATE command */
- rc = mysql_real_query (recset->mysql_res->handle, sql->str, strlen (sql->str));
+ rc = mysql_real_query (recset->mysql_res->handle, sql->str, sql->len);
g_string_free (sql, TRUE);
if (rc != 0) {
gda_connection_add_error (
@@ -370,15 +390,90 @@
}
static gboolean
-gda_mysql_recordset_remove_row (GdaDataModel *model, const GdaRow *row)
+gda_mysql_recordset_remove_row (GdaDataModel *model, GdaRow *row)
{
- return FALSE;
+ GString *str;
+ const gchar *id;
+ gint rc;
+
+ g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (model), FALSE);
+ g_return_val_if_fail (model == gda_row_get_model(row), FALSE);
+
+ GdaMysqlRecordset *recset = (GdaMysqlRecordset*) model;
+ id = gda_row_get_id(row);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ str = g_string_sized_new (200);
+ g_string_sprintf (str, "DELETE from %s WHERE %s", recset->table_name, id);
+
+ g_printerr ("\nquery: %s\n", str->str); //FIXME: just debugging
+ rc = mysql_real_query (recset->mysql, str->str, str->len);
+ g_string_free (str, TRUE);
+ if (rc!=0 || mysql_affected_rows(recset->mysql)!=1) {
+ gda_connection_add_error (
+ recset->cnc, gda_mysql_make_error (recset->mysql_res->handle));
+ return FALSE;
+ }
+ // FIXME what to do with the record now?
+ return TRUE;
}
static gboolean
-gda_mysql_recordset_update_row (GdaDataModel *model, const GdaRow *row)
+gda_mysql_recordset_update_row (GdaDataModel *model, GdaRow *row)
{
- return FALSE;
+ GString *str;
+ const gchar *id;
+ gint n;
+ gint rc;
+ gint *all;
+
+ g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (model), FALSE);
+ g_return_val_if_fail (model == gda_row_get_model(row), FALSE);
+
+ GdaMysqlRecordset *recset = (GdaMysqlRecordset*) model;
+ id = gda_row_get_id (row);
+ g_return_val_if_fail (id != NULL, FALSE);
+
+ str = g_string_sized_new (200);
+ g_string_sprintf (str, "UPDATE %s SET ", recset->table_name);
+ n = gda_row_get_length (row);
+ all = g_new (gint, n+1);
+ all[0] = n;
+ int i;
+ for (i=0; i<n; i++) all[i+1] = i;
+ printfa_cols (str, recset, row, all, FALSE);
+ g_free (all);
+ g_string_sprintfa (str, " WHERE %s", id);
+
+ g_printerr ("\nquery: %s\n", str->str); //FIXME: just debugging
+ rc = mysql_real_query (recset->mysql, str->str, str->len);
+ g_string_free (str, TRUE);
+ if (rc!=0 || mysql_affected_rows(recset->mysql)!=1) {
+ gda_connection_add_error (
+ recset->cnc, gda_mysql_make_error (recset->mysql_res->handle));
+ return FALSE;
+ }
+
+ // In NOT NULL columns, MySQL quietly converts NULL to 0, 0.0, or "".
+ // Our column is UNIQUE so this probably won't happen often, but handle
+ // it anyway.
+ for (i=1; i<=recset->key[0]; i++) {
+ gint c = recset->key[i];
+ GdaValue *value = gda_row_get_updatable_value (row, c);
+ if (value->type != GDA_VALUE_TYPE_NULL) continue;
+ MYSQL_FIELD *field = mysql_fetch_field_direct (recset->mysql_res, i);
+ GdaValueType type = gda_mysql_type_to_gda (field->type);
+ if (!gda_value_set_from_string (value, "", type) &&
+ !gda_value_set_from_string (value, "0", type))
+ // should never get to here, but reluctant to use g_assert()
+ g_printerr ("You've just found a bug. Please let us know how to get to this message. -- gnome-db-list gnome org");
+ // note that we'd never get TIMESTAMP in our key[] since it's always
+ // a NULL-ok column.
+ }
+
+ // FIXME: should we refetch this record for the new AUTO INCREMENT, TIMESTAMP values?
+ set_id (recset, row); // our key column might have changed
+ return TRUE;
}
static void
@@ -394,6 +489,7 @@
model_class->get_n_columns = gda_mysql_recordset_get_n_columns;
model_class->describe_column = gda_mysql_recordset_describe_column;
model_class->get_row = gda_mysql_recordset_get_row;
+ model_class->get_updatable_row = gda_mysql_recordset_get_updatable_row;
model_class->get_value_at = gda_mysql_recordset_get_value_at;
model_class->is_editable = gda_mysql_recordset_is_editable;
model_class->append_row = gda_mysql_recordset_append_row;
@@ -420,6 +516,8 @@
mysql_free_result (recset->mysql_res);
recset->mysql_res = NULL;
+ g_free (recset->table_name);
+ g_free (recset->key);
while (recset->rows->len > 0) {
GdaRow * row = (GdaRow *) g_ptr_array_index (recset->rows, 0);
@@ -469,10 +567,13 @@
recset = g_object_new (GDA_TYPE_MYSQL_RECORDSET, NULL);
recset->cnc = cnc;
recset->mysql_res = mysql_res;
+ recset->mysql = mysql;
if (mysql_res == NULL) {
recset->affected_rows = mysql_affected_rows (mysql);
return recset;
}
+ recset->key = NULL;
+ recset->table_name = NULL;
mysql_fields = mysql_fetch_fields (recset->mysql_res);
if (mysql_fields != NULL) {
@@ -485,4 +586,150 @@
}
return recset;
+}
+
+
+
+
+
+
+
+/*
+ * initialize recset->key
+ *
+ * We can't simply look at unique, non_null, or primary_key flags because
+ * a key might contain more than one column.
+ */
+void find_key_columns (GdaMysqlRecordset *recset)
+{
+ if (recset->key) return; // do it only once
+
+ MYSQL_RES *mysql_res;
+ const char *table;
+ gint i, n;
+
+
+ {// check if all columns come from the same table
+ MYSQL_FIELD *mysql_fields = mysql_fetch_fields (recset->mysql_res);
+ // use char and strcmp (not glib's equivalences) so they match mysql api
+ table = mysql_fields[0].table;
+ n = mysql_num_fields (recset->mysql_res);
+ for (i=0; i<n; i++)
+ if (!mysql_fields[i].table || strcmp (table, mysql_fields[i].table))
+ break;
+ if (i<n) {
+ recset->key = g_new0 (gint, 1); // {0}
+ return;
+ }
+ recset->table_name = g_strdup (table);
+ }
+
+ {// query for all keys
+ gchar *cmd_str = g_strdup_printf ("SHOW INDEX FROM %s", table);
+ gint rc = mysql_real_query (recset->mysql, cmd_str, strlen (cmd_str));
+ g_free (cmd_str);
+ if (rc != 0) {
+ gda_connection_add_error (recset->cnc, gda_mysql_make_error (recset->mysql));
+ return;
+ }
+ mysql_res = mysql_store_result (recset->mysql);
+ }
+
+ {// look for usable key
+ GdaDataModel *model = (GdaDataModel*) recset;
+ gboolean usable = FALSE;
+ char *key_name = "";
+ int i0 = 0;
+ n = mysql_num_rows (mysql_res);
+ for (i=0; i<n; i++) {
+ MYSQL_ROW row;
+
+ mysql_data_seek (mysql_res, i);
+ row = mysql_fetch_row (mysql_res);
+ if (strcmp (key_name, row[2])) { // 'Key_name' column
+ if (usable) break;
+ key_name = row[2];
+ usable = TRUE;
+ i0 = i;
+ }
+ if (strcmp (row[1], "0") // not unique
+ || (row[9] && 0==strcmp (row[9], "YES")) // allow null
+ || -1==gda_data_model_get_column_position (model, row[4]) ) // column not selected
+ usable = FALSE ;
+ }
+ if (usable) {
+ gint *t = g_new(int, i-i0+1);
+ t[0] = i-i0;
+ int j;
+ for (j=0; j<t[0]; j++) {
+ mysql_data_seek (mysql_res, i0+j);
+ MYSQL_ROW row = mysql_fetch_row (mysql_res);
+ t[j+1] = gda_data_model_get_column_position (model, row[4]);
+ }
+ recset->key = t;
+ } else
+ recset->key = g_new0 (gint, 1); // {0}
+ }
+
+ mysql_free_result (mysql_res);
+}
+
+
+
+/* append str with
+ *
+ * cols[1]="...", cols[2]="...", ... cols[n]="..."
+ *
+ * with n:=cols[0], and using row's data
+ *
+ * @where: TRUE, delimiter = " AND " use " IS NULL"
+ * FALSE, delimiter = ", " use "=NULL"
+ */
+void
+printfa_cols (GString *str, GdaMysqlRecordset *recset, GdaRow *row, gint cols[], gboolean where)
+{
+ MYSQL_FIELD *fields = mysql_fetch_fields (recset->mysql_res);
+ int i;
+ for (i = 1; i <= cols[0]; i++) {
+ int c = cols[i];
+ const GdaValue *value = gda_row_get_value (row, c);
+ gchar *val, *val2;
+ glong len;
+
+ g_string_append (str, fields[c].name);
+
+ switch (gda_value_get_type (value)) {
+ case GDA_VALUE_TYPE_NULL:
+ g_string_sprintfa (str, where?" IS NULL":"=NULL");
+ break;
+ case GDA_VALUE_TYPE_BINARY:
+ val = gda_value_get_binary (value, &len);
+ // size according to mysql_real_escape_string doc
+ val2 = g_new(gchar, 2*len+1);
+ mysql_real_escape_string (recset->mysql, val2, val, len);
+ g_string_sprintfa (str, "='%s'", val2);
+ g_free (val2);
+ break;
+ // FIXME: haven't figured out what to do with GDA_VALUE_TYPE_BLOB
+ default:
+ val = gda_value_stringify (value);
+ len = strlen(val);
+ val2 = g_new(gchar, 2*len+1);
+ mysql_real_escape_string (recset->mysql, val2, val, len);
+ g_free (val);
+ g_string_sprintfa (str, "='%s'", val2);
+ g_free (val2);
+ }
+
+ if (i < cols[0]) g_string_append (str, where?" AND ":", ");
+ }
+}
+
+void
+set_id (GdaMysqlRecordset *recset, GdaRow *row)
+{
+ GString *str = g_string_sized_new (100);
+ printfa_cols (str, recset, row, recset->key, TRUE);
+ gda_row_set_id (row, str->str);
+ g_string_free (str, TRUE);
}
Index: providers/mysql/gda-mysql-recordset.h
===================================================================
RCS file: /cvs/gnome/libgda/providers/mysql/gda-mysql-recordset.h,v
retrieving revision 1.7
diff -u -r1.7 gda-mysql-recordset.h
--- providers/mysql/gda-mysql-recordset.h 15 Aug 2003 12:53:40 -0000 1.7
+++ providers/mysql/gda-mysql-recordset.h 26 Oct 2003 00:49:27 -0000
@@ -44,7 +44,15 @@
GPtrArray *rows;
GdaConnection *cnc;
MYSQL_RES *mysql_res;
+ MYSQL *mysql;
gint affected_rows; /* when mysql_res is NULL, get_n_rows returns this number */
+
+ // these are set only if the table is updatable
+ gchar *table_name;
+ // FIXME: better use prepared statement if both server and C api's versions >= 4.1.0
+ gint *key; // column(s) of a non-null unique key. Used for update, delete.
+ // keys[0] == number of columns in that key == size of key[]-1
+ // NULL means uninitialized, {0} means can't update
};
struct _GdaMysqlRecordsetClass {
Index: providers/oracle/gda-oracle-recordset.c
===================================================================
RCS file: /cvs/gnome/libgda/providers/oracle/gda-oracle-recordset.c,v
retrieving revision 1.10
diff -u -r1.10 gda-oracle-recordset.c
--- providers/oracle/gda-oracle-recordset.c 3 Sep 2003 10:17:31 -0000 1.10
+++ providers/oracle/gda-oracle-recordset.c 26 Oct 2003 00:49:28 -0000
@@ -458,7 +458,6 @@
g_return_val_if_fail (GDA_IS_ORACLE_RECORDSET (recset), NULL);
g_return_val_if_fail (values != NULL, NULL);
g_return_val_if_fail (gda_data_model_is_editable (model), NULL);
- g_return_val_if_fail (gda_data_model_is_editing (model), NULL);
g_return_val_if_fail (recset->priv != NULL, 0);
priv_data = recset->priv;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]