[libgda/LIBGDA_4.2] Added GdaRow and GdaHolder error reporting APIs
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda/LIBGDA_4.2] Added GdaRow and GdaHolder error reporting APIs
- Date: Wed, 21 Sep 2011 16:05:25 +0000 (UTC)
commit 3821341162b9bc8905408ce9cec92ecfdebae2a9
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Sep 21 16:15:04 2011 +0200
Added GdaRow and GdaHolder error reporting APIs
gda_row_invalidate_value_e()
gda_row_value_is_valid_e()
gda_holder_force_invalid_e()
gda_holder_is_valid_e()
gda_data_model_iter_get_value_at_e()
libgda/gda-data-model-iter.c | 66 ++++--
libgda/gda-data-model-iter.h | 1 +
libgda/gda-data-select.c | 39 ++--
libgda/gda-holder.c | 91 ++++++++-
libgda/gda-holder.h | 2 +
libgda/gda-row.c | 99 +++++++++-
libgda/gda-row.h | 2 +
libgda/sql-parser/gda-statement-struct-parts.c | 9 +-
libgda/sqlite/gda-sqlite-recordset.c | 65 ++++--
libgda/sqlite/gda-sqlite.h | 2 +
libgda/sqlite/virtual/gda-vprovider-data-model.c | 10 +-
tests/data-models/check_model_errors.c | 239 +++++++++++++++++++++-
12 files changed, 536 insertions(+), 89 deletions(-)
---
diff --git a/libgda/gda-data-model-iter.c b/libgda/gda-data-model-iter.c
index 4214ea2..e2da293 100644
--- a/libgda/gda-data-model-iter.c
+++ b/libgda/gda-data-model-iter.c
@@ -667,7 +667,6 @@ gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *
gint col;
GdaDataModel *test;
gboolean update_model;
- gboolean retval = TRUE;
g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
@@ -692,18 +691,17 @@ gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *
g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
for (col = 0, list = ((GdaSet *) iter)->holders; list; col++, list = list->next) {
const GValue *cvalue;
- cvalue = gda_data_model_get_value_at (model, col, row, NULL);
+ GError *lerror = NULL;
+ cvalue = gda_data_model_get_value_at (model, col, row, &lerror);
if (!cvalue ||
- !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL)) {
- gda_holder_force_invalid ((GdaHolder*) list->data);
- retval = FALSE;
- }
+ !gda_holder_set_value ((GdaHolder*) list->data, cvalue, &lerror))
+ gda_holder_force_invalid_e ((GdaHolder*) list->data, lerror);
else
set_param_attributes ((GdaHolder*) list->data,
gda_data_model_get_attributes_at (model, col, row));
}
g_object_set (G_OBJECT (iter), "current-row", row, "update-model", update_model, NULL);
- return retval;
+ return TRUE;
}
@@ -755,7 +753,6 @@ gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *it
gint row;
GdaDataModel *test;
gboolean update_model;
- gboolean retval = TRUE;
/* validity tests */
if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM))
@@ -780,19 +777,18 @@ gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *it
g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
for (col = 0, list = ((GdaSet *) iter)->holders; list; col++, list = list->next) {
const GValue *cvalue;
- cvalue = gda_data_model_get_value_at (model, col, row, NULL);
+ GError *lerror = NULL;
+ cvalue = gda_data_model_get_value_at (model, col, row, &lerror);
if (!cvalue ||
- !gda_holder_set_value ((GdaHolder *) list->data, cvalue, NULL)) {
- gda_holder_force_invalid ((GdaHolder *) list->data);
- retval = FALSE;
- }
+ !gda_holder_set_value ((GdaHolder *) list->data, cvalue, &lerror))
+ gda_holder_force_invalid_e ((GdaHolder *) list->data, lerror);
else
set_param_attributes ((GdaHolder *) list->data,
gda_data_model_get_attributes_at (model, col, row));
}
g_object_set (G_OBJECT (iter), "current-row", row,
"update-model", update_model, NULL);
- return retval;
+ return TRUE;
}
/**
@@ -844,7 +840,6 @@ gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *it
gint row;
GdaDataModel *test;
gboolean update_model;
- gboolean retval = TRUE;
/* validity tests */
if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM))
@@ -869,19 +864,18 @@ gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *it
g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
for (col = 0, list = ((GdaSet *) iter)->holders; list; col++, list = list->next) {
const GValue *cvalue;
- cvalue = gda_data_model_get_value_at (model, col, row, NULL);
+ GError *lerror = NULL;
+ cvalue = gda_data_model_get_value_at (model, col, row, &lerror);
if (!cvalue ||
- !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL)) {
- gda_holder_force_invalid ((GdaHolder*) list->data);
- retval = FALSE;
- }
+ !gda_holder_set_value ((GdaHolder*) list->data, cvalue, &lerror))
+ gda_holder_force_invalid_e ((GdaHolder*) list->data, lerror);
else
set_param_attributes ((GdaHolder*) list->data,
gda_data_model_get_attributes_at (model, col, row));
}
g_object_set (G_OBJECT (iter), "current-row", row,
"update-model", update_model, NULL);
- return retval;
+ return TRUE;
}
@@ -1006,6 +1000,36 @@ gda_data_model_iter_get_value_at (GdaDataModelIter *iter, gint col)
}
/**
+ * gda_data_model_iter_get_value_at:
+ * @iter: a #GdaDataModelIter object
+ * @col: the requested column
+ * @error: (allow-none): a place to store errors, or %NULL
+ *
+ * Get the value stored at the column @col in @iter. The returned value must not be modified.
+ *
+ * Returns: (transfer none): the #GValue, or %NULL if the value could not be fetched
+ *
+ * Since: 4.2.10
+ */
+const GValue *
+gda_data_model_iter_get_value_at_e (GdaDataModelIter *iter, gint col, GError **error)
+{
+ GdaHolder *param;
+
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), NULL);
+ g_return_val_if_fail (iter->priv, NULL);
+
+ param = (GdaHolder *) g_slist_nth_data (((GdaSet *) iter)->holders, col);
+ if (param) {
+ if (error)
+ gda_holder_is_valid_e (param, error);
+ return gda_holder_get_value (param);
+ }
+ else
+ return NULL;
+}
+
+/**
* gda_data_model_iter_set_value_at:
* @iter: a #GdaDataModelIter object
* @col: the column number
diff --git a/libgda/gda-data-model-iter.h b/libgda/gda-data-model-iter.h
index cc2b8f9..c893135 100644
--- a/libgda/gda-data-model-iter.h
+++ b/libgda/gda-data-model-iter.h
@@ -68,6 +68,7 @@ struct _GdaDataModelIterClass
GType gda_data_model_iter_get_type (void) G_GNUC_CONST;
const GValue *gda_data_model_iter_get_value_at (GdaDataModelIter *iter, gint col);
+const GValue *gda_data_model_iter_get_value_at_e (GdaDataModelIter *iter, gint col, GError **error);
const GValue *gda_data_model_iter_get_value_for_field (GdaDataModelIter *iter, const gchar *field_name);
gboolean gda_data_model_iter_set_value_at (GdaDataModelIter *iter, gint col,
const GValue *value, GError **error);
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index df4a359..01e735f 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -1939,16 +1939,10 @@ gda_data_select_get_value_at (GdaDataModel *model, gint col, gint row, GError **
g_assert (prow);
GValue *retval = gda_row_get_value (prow, col);
- if (gda_row_value_is_valid (prow, retval))
+ if (gda_row_value_is_valid_e (prow, retval, error))
return retval;
- else {
- gchar *str;
- str = g_strdup_printf (_("Unable to get value for row %d and column %d"), row, col);
- g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
- "%s", str);
- g_free (str);
+ else
return NULL;
- }
}
static GdaValueAttribute
@@ -2204,22 +2198,24 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
plist;
i++, plist = plist->next) {
GValue *value;
- GError *error = NULL;
+ GError *lerror = NULL;
+ gboolean pok = TRUE;
value = gda_row_get_value (prow, i);
- if (!gda_row_value_is_valid (prow, value)) {
- retval = FALSE;
- g_warning (_("Could not change iter's value for column %d: %s"), i,
- error && error->message ? error->message : _("No detail"));
+ if (!gda_row_value_is_valid_e (prow, value, &lerror)) {
+ g_warning (_("%s(%p) [%d] Could not change iter's value for column %d: %s"),
+ __FUNCTION__, iter, imodel->priv->sh->iter_row, i,
+ lerror && lerror->message ? lerror->message : _("No detail"));
+ gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror);
}
- else if (! gda_holder_set_value ((GdaHolder*) plist->data, value, &error)) {
+ else if (! gda_holder_set_value ((GdaHolder*) plist->data, value, &lerror)) {
if (gda_holder_get_not_null ((GdaHolder*) plist->data) &&
gda_value_is_null (value)) {
gda_holder_set_not_null ((GdaHolder*) plist->data, FALSE);
if (! gda_holder_set_value ((GdaHolder*) plist->data, value, NULL)) {
- retval = FALSE;
+ pok = FALSE;
g_warning (_("Could not change iter's value for column %d: %s"), i,
- error && error->message ? error->message : _("No detail"));
+ lerror && lerror->message ? lerror->message : _("No detail"));
gda_holder_set_not_null ((GdaHolder*) plist->data, TRUE);
}
else
@@ -2227,12 +2223,14 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
"to be updated"));
}
else {
- retval = FALSE;
+ pok = FALSE;
g_warning (_("Could not change iter's value for column %d: %s"), i,
- error && error->message ? error->message : _("No detail"));
+ lerror && lerror->message ? lerror->message : _("No detail"));
}
- if (error)
- g_error_free (error);
+ }
+ if (!pok) {
+ retval = FALSE;
+ gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror);
}
}
@@ -2240,6 +2238,7 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
if (update_model)
g_object_set (G_OBJECT (iter), "update-model", update_model, NULL);
+ g_print ("%s(%p) => %d, current-row =>%d advertized_nrows => %d\n", __FUNCTION__, imodel, retval, imodel->priv->sh->iter_row, imodel->advertized_nrows);
return retval;
}
diff --git a/libgda/gda-holder.c b/libgda/gda-holder.c
index 59e25a6..1290280 100644
--- a/libgda/gda-holder.c
+++ b/libgda/gda-holder.c
@@ -101,6 +101,7 @@ struct _GdaHolderPrivate
gulong simple_bind_notify_signal_id;
gboolean invalid_forced;
+ GError *invalid_error;
gboolean valid;
gboolean is_freeable;
@@ -313,6 +314,7 @@ gda_holder_init (GdaHolder *holder)
holder->priv->simple_bind_notify_signal_id = 0;
holder->priv->invalid_forced = FALSE;
+ holder->priv->invalid_error = NULL;
holder->priv->valid = TRUE;
holder->priv->default_forced = FALSE;
holder->priv->is_freeable = TRUE;
@@ -379,6 +381,8 @@ gda_holder_copy (GdaHolder *orig)
if (allok) {
/* direct settings */
holder->priv->invalid_forced = orig->priv->invalid_forced;
+ if (orig->priv->invalid_error)
+ holder->priv->invalid_error = g_error_copy (orig->priv->invalid_error);
holder->priv->valid = orig->priv->valid;
holder->priv->is_freeable = TRUE;
holder->priv->default_forced = orig->priv->default_forced;
@@ -530,6 +534,11 @@ gda_holder_dispose (GObject *object)
gda_value_free (holder->priv->default_value);
holder->priv->default_value = NULL;
}
+
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
}
/* parent class */
@@ -975,6 +984,10 @@ real_gda_holder_set_value (GdaHolder *holder, GValue *value, gboolean do_copy, G
if (!do_copy && value)
gda_value_free (value);
holder->priv->invalid_forced = FALSE;
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
holder->priv->valid = newvalid;
return TRUE;
}
@@ -996,6 +1009,10 @@ real_gda_holder_set_value (GdaHolder *holder, GValue *value, gboolean do_copy, G
/* new valid status */
holder->priv->invalid_forced = FALSE;
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
holder->priv->valid = newvalid;
/* we're setting a non-static value, so be sure to flag is as freeable */
holder->priv->is_freeable = TRUE;
@@ -1105,6 +1122,10 @@ real_gda_holder_set_const_value (GdaHolder *holder, const GValue *value,
/* end of procedure if the value has not been changed, after calculating the holder's validity */
if (!changed) {
holder->priv->invalid_forced = FALSE;
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
holder->priv->valid = newvalid;
#ifdef DEBUG_HOLDER
g_print ("Holder is not changed");
@@ -1127,6 +1148,10 @@ real_gda_holder_set_const_value (GdaHolder *holder, const GValue *value,
/* new valid status */
holder->priv->invalid_forced = FALSE;
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
holder->priv->valid = newvalid;
/* we're setting a static value, so be sure to flag is as unfreeable */
holder->priv->is_freeable = FALSE;
@@ -1229,12 +1254,35 @@ void
gda_holder_force_invalid (GdaHolder *holder)
{
g_return_if_fail (GDA_IS_HOLDER (holder));
+ gda_holder_force_invalid_e (holder, NULL);
+}
+
+/**
+ * gda_holder_force_invalid_e:
+ * @holder: a #GdaHolder object
+ * @error: (allow-none) (transfer full): a #GError explaining why @holder is declared invalid, or %NULL
+ *
+ * Forces a holder to be invalid; to set it valid again, a new value must be assigned
+ * to it using gda_holder_set_value() or gda_holder_take_value().
+ *
+ * @holder's value is set to %NULL.
+ *
+ * Since: 4.2.10
+ */
+void
+gda_holder_force_invalid_e (GdaHolder *holder, GError *error)
+{
+ g_return_if_fail (GDA_IS_HOLDER (holder));
g_return_if_fail (holder->priv);
#ifdef GDA_DEBUG_NO
g_print ("Holder %p (%s): declare invalid\n", holder, holder->priv->id);
#endif
+ if (holder->priv->invalid_error)
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = error;
+
if (holder->priv->invalid_forced)
return;
@@ -1253,7 +1301,6 @@ gda_holder_force_invalid (GdaHolder *holder)
g_signal_emit (holder, gda_holder_signals[CHANGED], 0);
}
-
/**
* gda_holder_is_valid:
* @holder: a #GdaHolder object
@@ -1266,18 +1313,41 @@ gboolean
gda_holder_is_valid (GdaHolder *holder)
{
g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE);
+ return gda_holder_is_valid_e (holder, NULL);
+}
+
+/**
+ * gda_holder_is_valid_e:
+ * @holder: a #GdaHolder object
+ * @error: (allow-none): a place to store invalid error, or %NULL
+ *
+ * Get the validity of @holder (that is, of the value held by @holder)
+ *
+ * Returns: TRUE if @holder's value can safely be used
+ *
+ * Since: 4.2.10
+ */
+gboolean
+gda_holder_is_valid_e (GdaHolder *holder, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_HOLDER (holder), FALSE);
g_return_val_if_fail (holder->priv, FALSE);
if (holder->priv->full_bind)
- return gda_holder_is_valid (holder->priv->full_bind);
+ return gda_holder_is_valid_e (holder->priv->full_bind, error);
else {
+ gboolean retval;
if (holder->priv->invalid_forced)
- return FALSE;
-
- if (holder->priv->default_forced)
- return holder->priv->default_value ? TRUE : FALSE;
- else
- return holder->priv->valid;
+ retval = FALSE;
+ else {
+ if (holder->priv->default_forced)
+ retval = holder->priv->default_value ? TRUE : FALSE;
+ else
+ retval = holder->priv->valid;
+ }
+ if (!retval && holder->priv->invalid_error)
+ g_propagate_error (error, g_error_copy (holder->priv->invalid_error));
+ return retval;
}
}
@@ -1303,6 +1373,11 @@ gda_holder_set_value_to_default (GdaHolder *holder)
else {
holder->priv->default_forced = TRUE;
holder->priv->invalid_forced = FALSE;
+ if (holder->priv->invalid_error) {
+ g_error_free (holder->priv->invalid_error);
+ holder->priv->invalid_error = NULL;
+ }
+
if (holder->priv->value) {
if (holder->priv->is_freeable)
gda_value_free (holder->priv->value);
diff --git a/libgda/gda-holder.h b/libgda/gda-holder.h
index ef55d84..e1362a4 100644
--- a/libgda/gda-holder.h
+++ b/libgda/gda-holder.h
@@ -124,7 +124,9 @@ gboolean gda_holder_set_value_to_default (GdaHolder *holder);
gboolean gda_holder_value_is_default (GdaHolder *holder);
void gda_holder_force_invalid (GdaHolder *holder);
+void gda_holder_force_invalid_e (GdaHolder *holder, GError *error);
gboolean gda_holder_is_valid (GdaHolder *holder);
+gboolean gda_holder_is_valid_e (GdaHolder *holder, GError **error);
void gda_holder_set_not_null (GdaHolder *holder, gboolean not_null);
diff --git a/libgda/gda-row.c b/libgda/gda-row.c
index ce4cb3b..74ce93f 100644
--- a/libgda/gda-row.c
+++ b/libgda/gda-row.c
@@ -7,7 +7,7 @@
* Copyright (C) 2003 Xabier Rodríez Calvar <xrcalvar igalia com>
* Copyright (C) 2004 Paisa Seeluangsawat <paisa users sf net>
* Copyright (C) 2004 Szalai Ferenc <szferi einstein ki iif hu>
- * Copyright (C) 2005 - 2010 Vivien Malerba <malerba gnome-db org>
+ * Copyright (C) 2005 - 2011 Vivien Malerba <malerba gnome-db org>
* Copyright (C) 2006 - 2008 Murray Cumming <murrayc murrayc com>
* Copyright (C) 2007 Leonardo Boshell <lb kmc com co>
* Copyright (C) 2010 David King <davidk openismus com>
@@ -30,6 +30,7 @@
#include "gda-row.h"
#include <string.h>
+#include <glib/gi18n-lib.h>
#include "gda-data-model.h"
#define PARENT_TYPE G_TYPE_OBJECT
@@ -37,7 +38,8 @@
struct _GdaRowPrivate {
GdaDataModel *model; /* can be NULL */
- GValue *fields; /* GValue for each column */
+ GValue *fields; /* GValues */
+ GError **errors; /* GError for each invalid value at the same position */
gint nfields;
};
@@ -92,6 +94,7 @@ gda_row_init (GdaRow *row, G_GNUC_UNUSED GdaRowClass *klass)
row->priv = g_new0 (GdaRowPrivate, 1);
row->priv->model = NULL;
row->priv->fields = NULL;
+ row->priv->errors = NULL;
row->priv->nfields = 0;
}
@@ -115,9 +118,13 @@ gda_row_finalize (GObject *object)
if (row->priv) {
gint i;
- for (i = 0; i < row->priv->nfields; i++)
+ for (i = 0; i < row->priv->nfields; i++) {
gda_value_set_null (&(row->priv->fields [i]));
+ if (row->priv->errors && row->priv->errors [i])
+ g_error_free (row->priv->errors [i]);
+ }
g_free (row->priv->fields);
+ g_free (row->priv->errors);
g_free (row->priv);
row->priv = NULL;
@@ -247,8 +254,56 @@ gda_row_get_value (GdaRow *row, gint num)
void
gda_row_invalidate_value (G_GNUC_UNUSED GdaRow *row, GValue *value)
{
+ return gda_row_invalidate_value_e (row, value, NULL);
+}
+
+/**
+ * gda_row_invalidate_value_e:
+ * @row: a #GdaRow
+ * @value: a #GValue belonging to @row (obtained with gda_row_get_value()).
+ * @error: (allow-none) (transfer full): the error which lead to the invalidation
+ *
+ * Marks @value as being invalid. This method is mainly used by database
+ * providers' implementations to report any error while reading a value from the database.
+ *
+ * Since: 4.2.10
+ */
+void
+gda_row_invalidate_value_e (GdaRow *row, GValue *value, GError *error)
+{
gda_value_set_null (value);
G_VALUE_TYPE (value) = G_TYPE_NONE;
+ if (error) {
+ guint i;
+ if (! row->priv->errors)
+ row->priv->errors = g_new0 (GError*, row->priv->nfields);
+ for (i = 0; i < row->priv->nfields; i++) {
+ if (& (row->priv->fields[i]) == value) {
+ if (row->priv->errors [i])
+ g_error_free (row->priv->errors [i]);
+ row->priv->errors [i] = error;
+ break;
+ }
+ }
+ if (i == row->priv->nfields) {
+ g_error_free (error);
+ g_warning (_("Value not found in row!"));
+ }
+ }
+ else if (row->priv->errors) {
+ guint i;
+ for (i = 0; i < row->priv->nfields; i++) {
+ if (& (row->priv->fields[i]) == value) {
+ if (row->priv->errors [i]) {
+ g_error_free (row->priv->errors [i]);
+ row->priv->errors [i] = NULL;
+ }
+ break;
+ }
+ }
+ if (i == row->priv->nfields)
+ g_warning (_("Value not found in row!"));
+ }
}
/**
@@ -263,9 +318,43 @@ gda_row_invalidate_value (G_GNUC_UNUSED GdaRow *row, GValue *value)
* Returns: %TRUE if @value is valid
*/
gboolean
-gda_row_value_is_valid (G_GNUC_UNUSED GdaRow *row, GValue *value)
+gda_row_value_is_valid (GdaRow *row, GValue *value)
{
- return (G_VALUE_TYPE (value) == G_TYPE_NONE) ? FALSE : TRUE;
+ return gda_row_value_is_valid_e (row, value, NULL);
+}
+
+/**
+ * gda_row_value_is_valid:
+ * @row: a #GdaRow.
+ * @value: a #GValue belonging to @row (obtained with gda_row_get_value()).
+ * @error: (allow-none): a place to store the invalid error, or %NULL
+ *
+ * Tells if @value has been marked as being invalid by gda_row_invalidate_value().
+ * This method is mainly used by database
+ * providers' implementations to report any error while reading a value from the database.
+ *
+ * Returns: %TRUE if @value is valid
+ *
+ * Since: 4.2.10
+ */
+gboolean
+gda_row_value_is_valid_e (GdaRow *row, GValue *value, GError **error)
+{
+ gboolean valid;
+ valid = (G_VALUE_TYPE (value) == G_TYPE_NONE) ? FALSE : TRUE;
+ if (!valid && row->priv->errors && error) {
+ guint i;
+ for (i = 0; i < row->priv->nfields; i++) {
+ if (& (row->priv->fields[i]) == value) {
+ if (row->priv->errors [i])
+ g_propagate_error (error, g_error_copy (row->priv->errors [i]));
+ break;
+ }
+ }
+ if (i == row->priv->nfields)
+ g_warning (_("Value not found in row!"));
+ }
+ return valid;
}
/**
diff --git a/libgda/gda-row.h b/libgda/gda-row.h
index 21a9fbd..67be339 100644
--- a/libgda/gda-row.h
+++ b/libgda/gda-row.h
@@ -65,7 +65,9 @@ GValue *gda_row_get_value (GdaRow *row, gint num);
/* for database providers mainly */
void gda_row_invalidate_value (GdaRow *row, GValue *value);
+void gda_row_invalidate_value_e (GdaRow *row, GValue *value, GError *error);
gboolean gda_row_value_is_valid (GdaRow *row, GValue *value);
+gboolean gda_row_value_is_valid_e (GdaRow *row, GValue *value, GError **error);
diff --git a/libgda/sql-parser/gda-statement-struct-parts.c b/libgda/sql-parser/gda-statement-struct-parts.c
index 9cb24f9..c5bc138 100644
--- a/libgda/sql-parser/gda-statement-struct-parts.c
+++ b/libgda/sql-parser/gda-statement-struct-parts.c
@@ -1134,10 +1134,15 @@ void
gda_sql_select_field_take_expr (GdaSqlSelectField *field, GdaSqlExpr *expr)
{
field->expr = expr;
+ g_assert (GDA_SQL_ANY_PART (expr)->type == GDA_SQL_ANY_EXPR);
gda_sql_any_part_set_parent (field->expr, field);
- if (expr && expr->value)
- _split_identifier_string (g_value_dup_string (expr->value), &(field->table_name), &(field->field_name));
+ if (expr && expr->value) {
+ const gchar *dup;
+ dup = g_value_get_string (expr->value);
+ if (dup && *dup)
+ _split_identifier_string (g_strdup (dup), &(field->table_name), &(field->field_name));
+ }
}
/**
diff --git a/libgda/sqlite/gda-sqlite-recordset.c b/libgda/sqlite/gda-sqlite-recordset.c
index 55f477a..5663ff8 100644
--- a/libgda/sqlite/gda-sqlite-recordset.c
+++ b/libgda/sqlite/gda-sqlite-recordset.c
@@ -59,6 +59,7 @@ struct _GdaSqliteRecordsetPrivate {
GdaRow *tmp_row; /* used in cursor mode */
};
static GObjectClass *parent_class = NULL;
+GHashTable *error_blobs_hash = NULL;
/*
* Object init and finalize
@@ -88,6 +89,9 @@ gda_sqlite_recordset_class_init (GdaSqliteRecordsetClass *klass)
pmodel_class->fetch_next = gda_sqlite_recordset_fetch_next;
pmodel_class->fetch_prev = NULL;
pmodel_class->fetch_at = NULL;
+
+ g_assert (!error_blobs_hash);
+ error_blobs_hash = g_hash_table_new (NULL, NULL);
}
static void
@@ -330,7 +334,6 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
switch (rc) {
case SQLITE_ROW: {
gint col, real_col;
-
prow = gda_row_new (_GDA_PSTMT (ps)->ncols);
for (col = 0; col < _GDA_PSTMT (ps)->ncols; col++) {
GValue *value;
@@ -374,7 +377,14 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
/* fill GValue */
value = gda_row_get_value (prow, col);
- if (SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt, real_col) == NULL) {
+ GError *may_error;
+ may_error = (GError*) SQLITE3_CALL (sqlite3_column_blob) (ps->sqlite_stmt, real_col);
+ if (may_error && g_hash_table_lookup (error_blobs_hash, may_error)) {
+ g_print ("[[[%s]]]\n", may_error->message);
+ gda_row_invalidate_value_e (prow, value, may_error);
+ g_hash_table_remove (error_blobs_hash, may_error);
+ }
+ else if (SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt, real_col) == NULL) {
/* we have a NULL value */
gda_value_set_null (value);
}
@@ -388,10 +398,11 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
gint64 i;
i = SQLITE3_CALL (sqlite3_column_int64) (ps->sqlite_stmt, real_col);
if ((i > G_MAXINT) || (i < G_MININT)) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
"%s", _("Integer value is too big"));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
g_value_set_int (value, (gint) i);
@@ -400,10 +411,11 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
guint64 i;
i = (gint64) SQLITE3_CALL (sqlite3_column_int64) (ps->sqlite_stmt, real_col);
if (i > G_MAXUINT) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
"%s", _("Integer value is too big"));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
g_value_set_uint (value, (gint) i);
@@ -465,10 +477,11 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
rowid);
}
if (!bop) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
"%s", _("Unable to open BLOB"));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else {
GdaBlob *blob;
@@ -485,11 +498,12 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
if (!gda_parse_iso8601_date (&date,
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt,
real_col))) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
_("Invalid date '%s' (date format should be YYYY-MM-DD)"),
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt, real_col));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
g_value_set_boxed (value, &date);
@@ -499,11 +513,12 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
if (!gda_parse_iso8601_time (&timegda,
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt,
real_col))) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
_("Invalid time '%s' (time format should be HH:MM:SS[.ms])"),
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt, real_col));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
gda_value_set_time (value, &timegda);
@@ -513,11 +528,12 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
if (!gda_parse_iso8601_timestamp (×tamp,
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt,
real_col))) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
_("Invalid timestamp '%s' (format should be YYYY-MM-DD HH:MM:SS[.ms])"),
(gchar *) SQLITE3_CALL (sqlite3_column_text) (ps->sqlite_stmt, real_col));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
gda_value_set_timestamp (value, ×tamp);
@@ -526,10 +542,11 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
gint64 i;
i = SQLITE3_CALL (sqlite3_column_int64) (ps->sqlite_stmt, real_col);
if ((i > G_MAXINT8) || (i < G_MININT8)) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
"%s", _("Integer value is too big"));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
g_value_set_char (value, (gchar) i);
@@ -538,17 +555,23 @@ fetch_next_sqlite_row (GdaSqliteRecordset *model, gboolean do_store, GError **er
guint64 i;
i = (gint64) SQLITE3_CALL (sqlite3_column_int64) (ps->sqlite_stmt, real_col);
if (i > G_MAXUINT8) {
- g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
GDA_SERVER_PROVIDER_DATA_ERROR,
"%s", _("Integer value is too big"));
- gda_row_invalidate_value (prow, value);
+ gda_row_invalidate_value_e (prow, value, lerror);
}
else
g_value_set_uchar (value, (guchar) i);
}
- else
- g_error ("Unhandled GDA type %s in SQLite recordset",
- gda_g_type_to_string (_GDA_PSTMT (ps)->types [col]));
+ else {
+ GError *lerror = NULL;
+ g_set_error (&lerror, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_DATA_ERROR,
+ "Unhandled type '%s' in SQLite recordset",
+ gda_g_type_to_string (_GDA_PSTMT (ps)->types [col]));
+ gda_row_invalidate_value_e (prow, value, lerror);
+ }
}
}
diff --git a/libgda/sqlite/gda-sqlite.h b/libgda/sqlite/gda-sqlite.h
index 3605faf..5bf569d 100644
--- a/libgda/sqlite/gda-sqlite.h
+++ b/libgda/sqlite/gda-sqlite.h
@@ -62,4 +62,6 @@ typedef struct {
GType *types_array;/* holds GType values, pointed by @types_hash */
} SqliteConnectionData;
+extern GHashTable *error_blobs_hash;
+
#endif
diff --git a/libgda/sqlite/virtual/gda-vprovider-data-model.c b/libgda/sqlite/virtual/gda-vprovider-data-model.c
index 61478b5..50ffb2a 100644
--- a/libgda/sqlite/virtual/gda-vprovider-data-model.c
+++ b/libgda/sqlite/virtual/gda-vprovider-data-model.c
@@ -691,14 +691,18 @@ virtualColumn (sqlite3_vtab_cursor *cur, sqlite3_context *ctx, int i)
param = gda_data_model_iter_get_holder_for_field (cursor->iter, i);
if (!param) {
- SQLITE3_CALL (sqlite3_result_error) (ctx, _("Column not found"), -1);
+ SQLITE3_CALL (sqlite3_result_text) (ctx, _("Column not found"), -1, SQLITE_TRANSIENT);
return SQLITE_EMPTY;
}
else {
const GValue *value;
+ GError *lerror = NULL;
value = gda_holder_get_value (param);
-
- if (!value || gda_value_is_null (value))
+ if (! gda_holder_is_valid_e (param, &lerror)) {
+ g_hash_table_insert (error_blobs_hash, lerror, GINT_TO_POINTER (1));
+ SQLITE3_CALL (sqlite3_result_blob) (ctx, lerror, sizeof (GError), NULL);
+ }
+ else if (!value || gda_value_is_null (value))
SQLITE3_CALL (sqlite3_result_null) (ctx);
else if (G_VALUE_TYPE (value) == G_TYPE_INT)
SQLITE3_CALL (sqlite3_result_int) (ctx, g_value_get_int (value));
diff --git a/tests/data-models/check_model_errors.c b/tests/data-models/check_model_errors.c
index d19e138..e879ea2 100644
--- a/tests/data-models/check_model_errors.c
+++ b/tests/data-models/check_model_errors.c
@@ -25,6 +25,7 @@
#include <glib/gstdio.h>
#include "../test-cnc-utils.h"
#include "../data-model-errors.h"
+#include <virtual/libgda-virtual.h>
#define fail(x) g_warning (x)
#define fail_if(x,y) if (x) g_warning (y)
@@ -36,9 +37,11 @@ static void dump_data_model (GdaDataModel *model);
typedef gboolean (*TestFunc) (GdaConnection *);
static gint test1 (GdaConnection *cnc);
+static gint test2 (GdaConnection *cnc);
TestFunc tests[] = {
test1,
+ test2
};
int
@@ -93,24 +96,66 @@ check_iter_contents (GdaDataModel *model, GdaDataModelIter *iter)
for (i = 0; i < gda_data_model_get_n_columns (model); i++) {
GdaHolder *holder;
const GValue *vi, *vm;
+ GError *lerror1 = NULL, *lerror2 = NULL;
holder = gda_set_get_nth_holder (GDA_SET (iter), i);
- if (gda_holder_is_valid (holder))
+ if (gda_holder_is_valid_e (holder, &lerror1))
vi = gda_holder_get_value (holder);
else
vi = NULL;
- vm = gda_data_model_get_value_at (model, i, row, NULL);
- if ((vi == vm) ||
- (vi && vm && !gda_value_differ (vi, vm)))
- return TRUE;
- else {
+ vm = gda_data_model_get_value_at (model, i, row, &lerror2);
+ if (vi == vm) {
+ if (!vi) {
+ if (! lerror1 || !lerror1->message) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Iterator reported invalid value without any error set\n");
+#endif
+ return FALSE;
+ }
+ else if (! lerror2 || !lerror2->message) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Data model reported invalid value without any error set\n");
+#endif
+ return FALSE;
+ }
+ else if (lerror1->code != lerror2->code) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error codes differ!\n");
+#endif
+ return FALSE;
+ }
+ else if (lerror1->domain != lerror2->domain) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error domains differ!\n");
+#endif
+ return FALSE;
+ }
+ else if (strcmp (lerror1->message, lerror2->message)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error messages differ:\n\t%s\t%s",
+ lerror1->message, lerror2->message);
+#endif
+ return FALSE;
+ }
+ }
+ else if (gda_value_differ (vi, vm)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Iter's contents at (%d,%d) is wrong: expected [%s], got [%s]\n",
+ i, row,
+ vm ? gda_value_stringify (vm) : "ERROR",
+ vi ? gda_value_stringify (vi) : "ERROR");
+#endif
+ return FALSE;
+ }
+ }
+ else if (gda_value_differ (vi, vm)) {
#ifdef CHECK_EXTRA_INFO
g_print ("Iter's contents at (%d,%d) is wrong: expected [%s], got [%s]\n",
i, row,
vm ? gda_value_stringify (vm) : "ERROR",
vi ? gda_value_stringify (vi) : "ERROR");
#endif
- return FALSE;
+ return FALSE;
}
}
return TRUE;
@@ -160,13 +205,14 @@ test1 (GdaConnection *cnc)
goto out;
}
}
+ g_print ("Now at row %d\n", gda_data_model_iter_get_row (iter));
/* iterate backward */
i--;
- if (gda_data_model_iter_move_to_row (iter, i)) {
+ if (!gda_data_model_iter_move_to_row (iter, i)) {
nfailed++;
#ifdef CHECK_EXTRA_INFO
- g_print ("Error iterating: move to last row (%d) should have reported an error\n", i);
+ g_print ("Error iterating: move to last row (%d) failed\n", i);
#endif
goto out;
}
@@ -198,6 +244,7 @@ test1 (GdaConnection *cnc)
goto out;
}
}
+ g_print ("Now at row %d\n", gda_data_model_iter_get_row (iter));
out:
g_object_unref (model);
@@ -260,3 +307,177 @@ compare_data_models (GdaDataModel *model1, GdaDataModel *model2, GError **error)
return FALSE;
}
*/
+
+/*
+ * check modifications statements' setting
+ *
+ * Returns the number of failures
+ */
+static gint
+test2 (GdaConnection *cnc)
+{
+#define TABLE_NAME "data"
+ GdaDataModel *model;
+ gint nfailed = 0;
+
+ model = data_model_errors_new ();
+ if (!model) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not create DataModelErrors!\n");
+#endif
+ goto out;
+ }
+ dump_data_model (model);
+
+ GdaVirtualProvider *virtual_provider;
+ GError *lerror = NULL;
+ GdaConnection *vcnc;
+ GdaDataModelIter *iter = NULL;
+ GdaStatement *stmt;
+ virtual_provider = gda_vprovider_data_model_new ();
+ vcnc = gda_virtual_connection_open (virtual_provider, &lerror);
+ if (!vcnc) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Virtual ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+#endif
+ nfailed++;
+ g_clear_error (&lerror);
+ goto out;
+ }
+
+ if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (vcnc), model,
+ TABLE_NAME, &lerror)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Add model as table ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+#endif
+ nfailed++;
+ g_clear_error (&lerror);
+ goto out;
+ }
+ g_object_unref (model);
+
+ /* Execute SELECT */
+ stmt = gda_connection_parse_sql_string (vcnc, "SELECT * FROM " TABLE_NAME, NULL, NULL);
+ g_assert (stmt);
+ model = gda_connection_statement_execute_select (vcnc, stmt, NULL, &lerror);
+ g_object_unref (stmt);
+ if (!model) {
+ #ifdef CHECK_EXTRA_INFO
+ g_print ("SELECT ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+#endif
+ nfailed++;
+ g_clear_error (&lerror);
+ goto out;
+ }
+
+ /* iterate forward */
+ gint i, row;
+ iter = gda_data_model_create_iter (model);
+ for (i = 0, gda_data_model_iter_move_next (iter);
+ gda_data_model_iter_is_valid (iter);
+ i++, gda_data_model_iter_move_next (iter)) {
+ row = gda_data_model_iter_get_row (iter);
+ if (i != row) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to be at row %d and reported row is %d!\n",
+ i, row);
+#endif
+ goto out;
+ }
+ g_print ("Now at row %d\n", i);
+
+ if (! check_iter_contents (model, iter)) {
+ nfailed++;
+ goto out;
+ }
+ }
+ if (i != 4) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to have read %d rows, and read %d\n", 3,
+ i - 1);
+ nfailed++;
+ goto out;
+#endif
+ }
+ if (gda_data_model_iter_get_row (iter) != -1) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to be at row -1 and reported row is %d!\n",
+ gda_data_model_iter_get_row (iter));
+#endif
+ nfailed++;
+ goto out;
+ }
+
+ /* bind as another table */
+ if (!gda_vconnection_data_model_add_model (GDA_VCONNECTION_DATA_MODEL (vcnc), model,
+ TABLE_NAME "2", &lerror)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Add model as table2 ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+#endif
+ nfailed++;
+ g_clear_error (&lerror);
+ goto out;
+ }
+ g_object_unref (model);
+
+ stmt = gda_connection_parse_sql_string (vcnc, "SELECT * FROM " TABLE_NAME "2", NULL, NULL);
+ g_assert (stmt);
+ model = gda_connection_statement_execute_select (vcnc, stmt, NULL, &lerror);
+ g_object_unref (stmt);
+ if (!model) {
+ #ifdef CHECK_EXTRA_INFO
+ g_print ("SELECT ERROR: %s\n", lerror && lerror->message ? lerror->message : "No detail");
+#endif
+ nfailed++;
+ g_clear_error (&lerror);
+ goto out;
+ }
+
+ /* iterate forward */
+ iter = gda_data_model_create_iter (model);
+ for (i = 0, gda_data_model_iter_move_next (iter);
+ gda_data_model_iter_is_valid (iter);
+ i++, gda_data_model_iter_move_next (iter)) {
+ row = gda_data_model_iter_get_row (iter);
+ if (i != row) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to be at row %d and reported row is %d!\n",
+ i, row);
+#endif
+ goto out;
+ }
+ g_print ("Now at row %d\n", i);
+
+ if (! check_iter_contents (model, iter)) {
+ nfailed++;
+ goto out;
+ }
+ }
+ if (i != 4) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to have read %d rows, and read %d\n", 3,
+ i - 1);
+ nfailed++;
+ goto out;
+#endif
+ }
+ if (gda_data_model_iter_get_row (iter) != -1) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Error iterating: expected to be at row -1 and reported row is %d!\n",
+ gda_data_model_iter_get_row (iter));
+#endif
+ nfailed++;
+ goto out;
+ }
+
+ out:
+ g_object_unref (iter);
+ g_object_unref (model);
+ g_object_unref (vcnc);
+ g_object_unref (virtual_provider);
+
+ return nfailed;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]