[libgda] Cleaned GdaDataModelIter implementations
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Cleaned GdaDataModelIter implementations
- Date: Sat, 17 Sep 2011 14:27:01 +0000 (UTC)
commit 751c7027d653716bfafdb9295691b78ad50cb93f
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Sep 14 23:09:43 2011 +0200
Cleaned GdaDataModelIter implementations
doc/C/prov-writing-recordsets.xml | 19 ++-
libgda/gda-data-model-import.c | 38 ++----
libgda/gda-data-model-iter.c | 152 +++++++++++---------
libgda/gda-data-select.c | 127 +++++++----------
libgda/sqlite/gda-sqlite-recordset.c | 37 ++---
providers/firebird/gda-firebird-recordset.c | 73 +++++-----
providers/jdbc/gda-jdbc-recordset.c | 39 +++---
providers/ldap/gdaprov-data-model-ldap.c | 6 +-
providers/mysql/gda-mysql-recordset.c | 96 +++++--------
providers/oracle/gda-oracle-recordset.c | 129 +++--------------
providers/postgres/gda-postgres-recordset.c | 35 +----
.../skel-implementation/capi/gda-capi-recordset.c | 74 +++++-----
12 files changed, 332 insertions(+), 493 deletions(-)
---
diff --git a/doc/C/prov-writing-recordsets.xml b/doc/C/prov-writing-recordsets.xml
index 04bbd40..6231779 100644
--- a/doc/C/prov-writing-recordsets.xml
+++ b/doc/C/prov-writing-recordsets.xml
@@ -53,8 +53,11 @@
<title>fetch_random()</title>
<para>
This method is called when the user calls <link linkend="gda-data-model-get-value-at">gda_data_model_get_value_at ()</link>,
- and in available only when the data access mode for the data model is random (that is not cursor based). When data
- access is cursor based, this method will not be called.
+ and is used only when the data access mode for the data model is random (that is not cursor based) (i.e. when data
+ access is cursor based, this method will not be called).
+ </para>
+ <para>Also it is safe to assume that when called, the
+ <parameter>prow</parameter> parameter will not be NULL, and that <parameter>*prow</parameter> is actually NULL.
</para>
</sect2>
@@ -75,6 +78,9 @@
<parameter>rownum</parameter> is an indication of what the row number will be once the next row has been fetched (it can
safely be discarded if that information is not necessary).
</para>
+ <para>This method is not used when data is accessed in a random way. Also it is safe to assume that when called, the
+ <parameter>prow</parameter> parameter will not be NULL, and that <parameter>*prow</parameter> is actually NULL.
+ </para>
</sect2>
<sect2>
@@ -82,14 +88,19 @@
<para>
This method is called when data access is cursor based and a data model iterator is moved one position backward. The
<parameter>rownum</parameter> is an indication of what the row number will be once the previous row has been fetched (it can
- safely be discarded if that information is not necessary).
+ safely be discarded if that information is not necessary). Implementing this method is not necessary if the data model
+ does not support moving iterators backward.
+ </para>
+ <para>This method is not used when data is accessed in a random way. Also it is safe to assume that when called, the
+ <parameter>prow</parameter> parameter will not be NULL, and that <parameter>*prow</parameter> is actually NULL.
</para>
</sect2>
<sect2>
<title>fetch_at()</title>
<para>
- This method can be implemented when data access is cursor based and there is a shorter way of getting to a
+ This method can be implemented (but it is not required) when data access is cursor based
+ and there is a shorter way of getting to a
specific row than having to call the fetch_next() or fetch_prev() methods several times.
</para>
</sect2>
diff --git a/libgda/gda-data-model-import.c b/libgda/gda-data-model-import.c
index 68f5b77..127f6a6 100644
--- a/libgda/gda-data-model-import.c
+++ b/libgda/gda-data-model-import.c
@@ -1932,8 +1932,10 @@ gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
break;
case FORMAT_CSV:
- if (! imodel->priv->extract.csv.rows_read)
+ if (! imodel->priv->extract.csv.rows_read) {
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
+ }
if (gda_data_model_iter_is_valid (iter) &&
(imodel->priv->extract.csv.rows_read->len > 0)) {
@@ -1962,7 +1964,6 @@ gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
GSList *plist;
GSList *vlist;
gboolean update_model;
- gboolean allok = TRUE;
g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL);
g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
@@ -1971,18 +1972,10 @@ gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
plist = plist->next, vlist = vlist->next) {
GError *lerror = NULL;
if (! gda_holder_set_value (GDA_HOLDER (plist->data),
- (GValue *) vlist->data, &lerror)) {
- gchar *tmp;
- tmp = g_strdup_printf (_("Could not set iterator's value: %s"),
- lerror && lerror->message ? lerror->message : _("No detail"));
- add_error (imodel, tmp);
- g_free (tmp);
- allok = FALSE;
- }
+ (GValue *) vlist->data, &lerror))
+ gda_holder_force_invalid_e (GDA_HOLDER (plist->data), lerror);
}
if (plist || vlist) {
- if (imodel->priv->strict)
- allok = FALSE;
if (plist) {
add_error_too_few_values (imodel);
for (; plist; plist = plist->next) {
@@ -2003,11 +1996,12 @@ gda_data_model_import_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
g_object_set (G_OBJECT (iter), "current-row", imodel->priv->iter_row,
"update-model", update_model, NULL);
- return allok;
+ return TRUE;
}
else {
- g_signal_emit_by_name (iter, "end-of-data");
+ gda_data_model_iter_invalidate_contents (iter);
g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
+ g_signal_emit_by_name (iter, "end-of-data");
return FALSE;
}
}
@@ -2040,7 +2034,6 @@ gda_data_model_import_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
GSList *plist;
GSList *vlist;
gboolean update_model;
- gboolean allok = TRUE;
g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL);
g_object_set (G_OBJECT (iter), "update-model", FALSE, NULL);
@@ -2049,18 +2042,10 @@ gda_data_model_import_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
plist = plist->next, vlist = vlist->next) {
GError *lerror = NULL;
if (! gda_holder_set_value (GDA_HOLDER (plist->data),
- (GValue *) vlist->data, &lerror)) {
- gchar *tmp;
- tmp = g_strdup_printf (_("Could not set iterator's value: %s"),
- lerror && lerror->message ? lerror->message : _("No detail"));
- add_error (imodel, tmp);
- g_free (tmp);
- allok = FALSE;
- }
+ (GValue *) vlist->data, &lerror))
+ gda_holder_force_invalid_e (GDA_HOLDER (plist->data), lerror);
}
if (plist || vlist) {
- if (imodel->priv->strict)
- allok = FALSE;
if (plist) {
add_error_too_few_values (imodel);
for (; plist; plist = plist->next) {
@@ -2080,9 +2065,10 @@ gda_data_model_import_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
g_assert (imodel->priv->iter_row >= 0);
g_object_set (G_OBJECT (iter), "current-row", imodel->priv->iter_row,
"update-model", update_model, NULL);
- return allok;
+ return TRUE;
}
else {
+ gda_data_model_iter_invalidate_contents (iter);
g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
return FALSE;
}
diff --git a/libgda/gda-data-model-iter.c b/libgda/gda-data-model-iter.c
index e2da293..087a635 100644
--- a/libgda/gda-data-model-iter.c
+++ b/libgda/gda-data-model-iter.c
@@ -577,14 +577,18 @@ gda_data_model_iter_get_property (GObject *object,
*
* Synchronizes the values of the parameters in @iter with the values at the @row row.
*
- * If @row is not a valid row, then the returned value is FALSE, and the "current-row"
- * property is set to -1 (which means that gda_data_model_iter_is_valid() would return FALSE)
+ * If @row is not a valid row, then the returned value is %FALSE, and the "current-row"
+ * property is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE),
+ * with the exception that if @row is -1, then the returned value is %TRUE.
*
- * If any other error occurred then the returned value is FALSE, but the "current-row"
- * property is set to the @row row. In this case
- * each #GdaHolder composing @iter for which an error occurred will be invalid (see gda_holder_is_valid()).
+ * This function can return %FALSE if it was not allowed to be moved (as it emits the
+ * "validate-set" signal before being moved).
*
- * Returns: TRUE if no error occurred
+ * When this function returns %TRUE, then @iter has actually been moved to the next row,
+ * but some values may not have been read correctly in the row, in which case the
+ * correcsponding #GdaHolder will be left invalid.
+ *
+ * Returns: %TRUE if no error occurred
*/
gboolean
gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row)
@@ -592,8 +596,15 @@ gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row)
g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE);
g_return_val_if_fail (iter->priv, FALSE);
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ (gda_data_model_iter_get_row (iter) == row))
+ return TRUE; /* nothing to do! */
+
if (row < 0) {
- if (iter->priv->row != -1) {
+ if (gda_data_model_iter_get_row (iter) >= 0) {
+ if (! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
+
iter->priv->row = -1;
g_signal_emit (G_OBJECT (iter),
gda_data_model_iter_signals[ROW_CHANGED],
@@ -603,44 +614,18 @@ gda_data_model_iter_move_to_row (GdaDataModelIter *iter, gint row)
}
else {
GdaDataModel *model;
- if ((gda_data_model_iter_get_row (iter) >= 0) &&
- (gda_data_model_iter_get_row (iter) != row) &&
- ! _gda_set_validate ((GdaSet*) iter, NULL)) {
- return FALSE;
- }
-
- gboolean *null_oks = NULL;
- if (GDA_SET (iter)->holders) {
- gint i;
- GSList *list;
-
- null_oks = g_new (gboolean, g_slist_length (GDA_SET (iter)->holders));
- for (i = 0, list = GDA_SET (iter)->holders; list; i++, list = list->next) {
- null_oks[i] = gda_holder_get_not_null ((GdaHolder*) list->data);
- gda_holder_set_not_null ((GdaHolder*) list->data, FALSE);
- }
- }
-
- gboolean move_ok;
model = iter->priv->data_model;
g_return_val_if_fail (iter->priv->data_model, FALSE);
- if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_at_row)
- move_ok = (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_at_row) (model, iter, row);
- else {
- /* default method */
- move_ok = gda_data_model_iter_move_to_row_default (model, iter, row);
+ if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_at_row) {
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
+ return (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_at_row) (model, iter,
+ row);
}
-
- if (null_oks) {
- gint i;
- GSList *list;
- for (i = 0, list = GDA_SET (iter)->holders; list; i++, list = list->next)
- gda_holder_set_not_null ((GdaHolder*) list->data, null_oks[i]);
- g_free (null_oks);
- }
-
- return move_ok;
+ else
+ return gda_data_model_iter_move_to_row_default (model, iter, row);
}
}
@@ -658,6 +643,13 @@ set_param_attributes (GdaHolder *holder, GdaValueAttribute flags)
/**
* gda_data_model_iter_move_to_row_default: (skip)
+ * @model: a #GdaDataModel
+ * @iter: a #GdaDataModelIter iterating in @model
+ * @row: the requested row
+ *
+ * Method reserved to #GdaDataModelIter implementations, should not be called directly.
+ *
+ * Returns: %TRUE if @iter was moved correctly.
*/
gboolean
gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *iter, gint row)
@@ -668,7 +660,9 @@ gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *
GdaDataModel *test;
gboolean update_model;
- g_return_val_if_fail (GDA_IS_DATA_MODEL (model), FALSE);
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM))
return FALSE;
@@ -713,14 +707,17 @@ gda_data_model_iter_move_to_row_default (GdaDataModel *model, GdaDataModelIter *
* (synchronizes the values of the parameters in @iter with the values at the new row).
*
* If the iterator was on the data model's last row, then it can't be moved forward
- * anymore, and the returned value is FALSE; nore also that the "current-row" property
- * is set to -1 (which means that gda_data_model_iter_is_valid() would return FALSE)
+ * anymore, and the returned value is %FALSE; note also that the "current-row" property
+ * is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE)
+ *
+ * This function can return %FALSE if it was not allowed to be moved (as it emits the
+ * "validate-set" signal before being moved).
*
- * If any other error occurred then the returned value is FALSE, but the "current-row"
- * property is set to the new current row (one row more than it was before the call). In this case
- * each #GdaHolder composing @iter for which an error occurred will be invalid (see gda_holder_is_valid()).
+ * When this function returns %TRUE, then @iter has actually been moved to the next row,
+ * but some values may not have been read correctly in the row, in which case the
+ * correcsponding #GdaHolder will be left invalid.
*
- * Returns: TRUE if the iterator is now at the next row
+ * Returns: %TRUE if the iterator is now at the next row
*/
gboolean
gda_data_model_iter_move_next (GdaDataModelIter *iter)
@@ -730,13 +727,13 @@ gda_data_model_iter_move_next (GdaDataModelIter *iter)
g_return_val_if_fail (iter->priv, FALSE);
g_return_val_if_fail (iter->priv->data_model, FALSE);
- if ((gda_data_model_iter_get_row (iter) >= 0) &&
- ! _gda_set_validate ((GdaSet*) iter, NULL))
- return FALSE;
-
model = iter->priv->data_model;
- if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_next)
+ if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_next) {
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
return (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_next) (model, iter);
+ }
else
/* default method */
return gda_data_model_iter_move_next_default (model, iter);
@@ -744,6 +741,12 @@ gda_data_model_iter_move_next (GdaDataModelIter *iter)
/**
* gda_data_model_iter_move_next_default: (skip)
+ * @model: a #GdaDataModel
+ * @iter: a #GdaDataModelIter iterating in @model
+ *
+ * Method reserved to #GdaDataModelIter implementations, should not be called directly.
+ *
+ * Returns: %TRUE if @iter was moved correctly.
*/
gboolean
gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *iter)
@@ -753,8 +756,11 @@ gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *it
gint row;
GdaDataModel *test;
gboolean update_model;
-
- /* validity tests */
+
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
+
if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM))
return FALSE;
@@ -799,14 +805,17 @@ gda_data_model_iter_move_next_default (GdaDataModel *model, GdaDataModelIter *it
* with the values at the new row).
*
* If the iterator was on the data model's first row, then it can't be moved backwards
- * anymore, and the returned value is FALSE; note also that the "current-row" property
- * is set to -1 (which means that gda_data_model_iter_is_valid() would return FALSE).
+ * anymore, and the returned value is %FALSE; note also that the "current-row" property
+ * is set to -1 (which means that gda_data_model_iter_is_valid() would return %FALSE).
+ *
+ * This function can return %FALSE if it was not allowed to be moved (as it emits the
+ * "validate-set" signal before being moved).
*
- * If any other error occurred then the returned value is FALSE, but the "current-row"
- * property is set to the new current row (one row less than it was before the call). In this case
- * each #GdaHolder composing @iter for which an error occurred will be invalid (see gda_holder_is_valid()).
+ * When this function returns %TRUE, then @iter has actually been moved to the next row,
+ * but some values may not have been read correctly in the row, in which case the
+ * correcsponding #GdaHolder will be left invalid.
*
- * Returns: TRUE if the iterator is now at the previous row
+ * Returns: %TRUE if the iterator is now at the previous row
*/
gboolean
gda_data_model_iter_move_prev (GdaDataModelIter *iter)
@@ -817,13 +826,13 @@ gda_data_model_iter_move_prev (GdaDataModelIter *iter)
g_return_val_if_fail (iter->priv, FALSE);
g_return_val_if_fail (iter->priv->data_model, FALSE);
- if ((gda_data_model_iter_get_row (iter) >= 0) &&
- ! _gda_set_validate ((GdaSet*) iter, NULL))
- return FALSE;
-
model = iter->priv->data_model;
- if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_prev)
+ if (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_prev) {
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
return (GDA_DATA_MODEL_GET_CLASS (model)->i_iter_prev) (model, iter);
+ }
else
/* default method */
return gda_data_model_iter_move_prev_default (model, iter);
@@ -831,6 +840,12 @@ gda_data_model_iter_move_prev (GdaDataModelIter *iter)
/**
* gda_data_model_iter_move_prev_default: (skip)
+ * @model: a #GdaDataModel
+ * @iter: a #GdaDataModelIter iterating in @model
+ *
+ * Method reserved to #GdaDataModelIter implementations, should not be called directly.
+ *
+ * Returns: %TRUE if @iter was moved correctly.
*/
gboolean
gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *iter)
@@ -841,7 +856,10 @@ gda_data_model_iter_move_prev_default (GdaDataModel *model, GdaDataModelIter *it
GdaDataModel *test;
gboolean update_model;
- /* validity tests */
+ if ((gda_data_model_iter_get_row (iter) >= 0) &&
+ ! _gda_set_validate ((GdaSet*) iter, NULL))
+ return FALSE;
+
if (! (gda_data_model_get_access_flags (model) & GDA_DATA_MODEL_ACCESS_RANDOM))
return FALSE;
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index 83cdf72..f45f5b9 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -1923,20 +1923,12 @@ gda_data_select_get_value_at (GdaDataModel *model, gint col, gint row, GError **
prow = dstmt->row;
}
else {
- gint *ptr;
- irow = int_row;
- ptr = g_hash_table_lookup (imodel->priv->sh->index, &irow);
- if (!ptr) {
- prow = NULL;
- if (CLASS (model)->fetch_random &&
- !CLASS (model)->fetch_random (imodel, &prow, int_row, error))
- return NULL;
- }
- else
- prow = g_array_index (imodel->priv->sh->rows, GdaRow *, *ptr);
+ prow = gda_data_select_get_stored_row (imodel, int_row);
+ if (!prow && CLASS (model)->fetch_random)
+ CLASS (model)->fetch_random (imodel, &prow, int_row, error);
}
-
- g_assert (prow);
+ if (!prow)
+ return NULL;
GValue *retval = gda_row_get_value (prow, col);
if (gda_row_value_is_valid_e (prow, retval, error))
@@ -2012,7 +2004,7 @@ gda_data_select_create_iter (GdaDataModel *model)
}
}
-static gboolean update_iter (GdaDataSelect *imodel, GdaRow *prow);
+static void update_iter (GdaDataSelect *imodel, GdaRow *prow);
static gboolean
gda_data_select_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
{
@@ -2028,37 +2020,33 @@ gda_data_select_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
return gda_data_model_iter_move_next_default (model, iter);
g_return_val_if_fail (CLASS (model)->fetch_next, FALSE);
-
g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (imodel->priv->iter == iter, FALSE);
- if (imodel->priv->sh->iter_row == G_MAXINT)
+ if (imodel->priv->sh->iter_row == G_MAXINT) {
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
+ }
else if (imodel->priv->sh->iter_row == G_MININT)
target_iter_row = 0;
else
target_iter_row = imodel->priv->sh->iter_row + 1;
- int_row = external_to_internal_row (imodel, target_iter_row, NULL);
- gint *ptr;
- irow = int_row;
- ptr = g_hash_table_lookup (imodel->priv->sh->index, &irow);
- if (ptr)
- prow = g_array_index (imodel->priv->sh->rows, GdaRow *, *ptr);
- else if (!CLASS (model)->fetch_next (imodel, &prow, int_row, NULL)) {
- /* an error occurred */
- g_object_set (G_OBJECT (iter), "current-row", target_iter_row, NULL);
- return FALSE;
- }
+ int_row = external_to_internal_row (imodel, target_iter_row, NULL);
+ prow = gda_data_select_get_stored_row (model, int_row);
+ if (!prow)
+ CLASS (model)->fetch_next (imodel, &prow, int_row, NULL);
if (prow) {
imodel->priv->sh->iter_row = target_iter_row;
- return update_iter (imodel, prow);
+ update_iter (imodel, prow);
+ return TRUE;
}
else {
- g_signal_emit_by_name (iter, "end-of-data");
- g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
+ gda_data_model_iter_invalidate_contents (iter);
imodel->priv->sh->iter_row = G_MAXINT;
+ g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
+ g_signal_emit_by_name (iter, "end-of-data");
return FALSE;
}
}
@@ -2077,8 +2065,10 @@ gda_data_select_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
if (imodel->priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)
return gda_data_model_iter_move_prev_default (model, iter);
- if (! CLASS (model)->fetch_prev)
+ if (! CLASS (model)->fetch_prev) {
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
+ }
g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (imodel->priv->iter == iter, FALSE);
@@ -2093,26 +2083,21 @@ gda_data_select_iter_prev (GdaDataModel *model, GdaDataModelIter *iter)
else
target_iter_row = imodel->priv->sh->iter_row - 1;
- gint *ptr;
int_row = external_to_internal_row (imodel, target_iter_row, NULL);
- irow = int_row;
- ptr = g_hash_table_lookup (imodel->priv->sh->index, &irow);
- if (ptr)
- prow = g_array_index (imodel->priv->sh->rows, GdaRow *, *ptr);
- else if (!CLASS (model)->fetch_prev (imodel, &prow, int_row, NULL)) {
- /* an error occurred */
- g_object_set (G_OBJECT (iter), "current-row", target_iter_row, NULL);
- return FALSE;
- }
+ prow = gda_data_select_get_stored_row (model, int_row);
+ if (!prow)
+ CLASS (model)->fetch_prev (imodel, &prow, int_row, NULL);
if (prow) {
imodel->priv->sh->iter_row = target_iter_row;
- return update_iter (imodel, prow);
+ update_iter (imodel, prow);
+ return TRUE;
}
prev_error:
g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
imodel->priv->sh->iter_row = G_MININT;
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
}
@@ -2126,39 +2111,34 @@ gda_data_select_iter_at_row (GdaDataModel *model, GdaDataModelIter *iter, gint r
imodel = (GdaDataSelect *) model;
g_return_val_if_fail (imodel->priv, FALSE);
- int_row = external_to_internal_row (imodel, row, NULL);
if (imodel->priv->sh->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)
return gda_data_model_iter_move_to_row_default (model, iter, row);
g_return_val_if_fail (iter, FALSE);
g_return_val_if_fail (imodel->priv->iter == iter, FALSE);
- irow = int_row;
- ptr = g_hash_table_lookup (imodel->priv->sh->index, &irow);
- if (ptr)
- prow = g_array_index (imodel->priv->sh->rows, GdaRow *, *ptr);
-
- if (CLASS (model)->fetch_at) {
- if (!CLASS (model)->fetch_at (imodel, &prow, int_row, NULL)) {
- /* an error occurred */
- g_object_set (G_OBJECT (iter), "current-row", row, NULL);
- return FALSE;
- }
+ int_row = external_to_internal_row (imodel, row, NULL);
+ prow = gda_data_select_get_stored_row (model, int_row);
- if (prow) {
- imodel->priv->sh->iter_row = row;
- return update_iter (imodel, prow);
- }
- else {
- g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
- imodel->priv->sh->iter_row = G_MININT;
- return FALSE;
- }
+ if (prow) {
+ imodel->priv->sh->iter_row = row;
+ update_iter (imodel, prow);
+ return TRUE;
}
else {
- if (prow) {
- imodel->priv->sh->iter_row = row;
- return update_iter (imodel, prow);
+ if (CLASS (model)->fetch_at) {
+ CLASS (model)->fetch_at (imodel, &prow, int_row, NULL);
+ if (prow) {
+ imodel->priv->sh->iter_row = row;
+ update_iter (imodel, prow);
+ return TRUE;
+ }
+ else {
+ g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
+ imodel->priv->sh->iter_row = G_MININT;
+ gda_data_model_iter_invalidate_contents (iter);
+ return FALSE;
+ }
}
else {
/* implementation of fetch_at() is optional */
@@ -2182,14 +2162,13 @@ gda_data_select_iter_at_row (GdaDataModel *model, GdaDataModelIter *iter, gint r
}
}
-static gboolean
+static void
update_iter (GdaDataSelect *imodel, GdaRow *prow)
{
gint i;
GdaDataModelIter *iter = imodel->priv->iter;
GSList *plist;
gboolean update_model;
- gboolean retval = TRUE;
g_object_get (G_OBJECT (iter), "update-model", &update_model, NULL);
if (update_model)
@@ -2200,7 +2179,6 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
i++, plist = plist->next) {
GValue *value;
GError *lerror = NULL;
- gboolean pok = TRUE;
value = gda_row_get_value (prow, i);
if (!gda_row_value_is_valid_e (prow, value, &lerror)) {
@@ -2214,7 +2192,7 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
gda_value_is_null (value)) {
gda_holder_set_not_null ((GdaHolder*) plist->data, FALSE);
if (! gda_holder_set_value ((GdaHolder*) plist->data, value, NULL)) {
- pok = FALSE;
+ gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror);
g_warning (_("Could not change iter's value for column %d: %s"), i,
lerror && lerror->message ? lerror->message : _("No detail"));
gda_holder_set_not_null ((GdaHolder*) plist->data, TRUE);
@@ -2224,23 +2202,18 @@ update_iter (GdaDataSelect *imodel, GdaRow *prow)
"to be updated"));
}
else {
- pok = FALSE;
+ gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror);
g_warning (_("Could not change iter's value for column %d: %s"), i,
lerror && lerror->message ? lerror->message : _("No detail"));
}
}
- if (!pok) {
- retval = FALSE;
- gda_holder_force_invalid_e ((GdaHolder*) plist->data, lerror);
- }
}
g_object_set (G_OBJECT (iter), "current-row", imodel->priv->sh->iter_row, NULL);
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;
+ g_print ("%s(%p), current-row =>%d advertized_nrows => %d\n", __FUNCTION__, imodel, imodel->priv->sh->iter_row, imodel->advertized_nrows);
}
/*
diff --git a/libgda/sqlite/gda-sqlite-recordset.c b/libgda/sqlite/gda-sqlite-recordset.c
index c07945c..5fa4b35 100644
--- a/libgda/sqlite/gda-sqlite-recordset.c
+++ b/libgda/sqlite/gda-sqlite-recordset.c
@@ -641,35 +641,24 @@ gda_sqlite_recordset_fetch_nb_rows (GdaDataSelect *model)
/*
* Create a new filled #GdaRow object for the row at position @rownum.
*
- * Each new #GdaRow created is "given" to the #GdaDataSelect implementation using gda_data_select_take_row ().
+ * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using
+ * gda_data_select_take_row() because backward iterating is not supported.
*/
static gboolean
gda_sqlite_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
GdaSqliteRecordset *imodel;
- if (*prow)
- return TRUE;
-
imodel = GDA_SQLITE_RECORDSET (model);
- for (; imodel->priv->next_row_num <= rownum; ) {
- *prow = fetch_next_sqlite_row (imodel, TRUE, error);
- if (!*prow) {
- /*if (GDA_DATA_SELECT (model)->advertized_nrows >= 0), it's not an error */
- if ((GDA_DATA_SELECT (model)->advertized_nrows >= 0) &&
- (imodel->priv->next_row_num < rownum)) {
- g_set_error (error, 0,
- GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
- _("Row %d not found"), rownum);
- }
- return FALSE;
- }
- }
- if (! *prow) {
- *prow = gda_data_select_get_stored_row (model, rownum);
- if (!*prow)
- return FALSE;
+ if (imodel->priv->next_row_num >= rownum) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+ "%s", _("Requested row could not be found"));
+ return TRUE;
}
+ for (*prow = fetch_next_sqlite_row (imodel, TRUE, error);
+ *prow && (imodel->priv->next_row_num < rownum);
+ *prow = fetch_next_sqlite_row (imodel, TRUE, error));
return TRUE;
}
@@ -678,16 +667,16 @@ gda_sqlite_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint row
* Create a new filled #GdaRow object for the next cursor row
*
* Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
- * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ * never keeps a reference to it).
+ * Before a new #GdaRow gets created, the previous one, if set, is discarded.
*/
static gboolean
gda_sqlite_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, G_GNUC_UNUSED gint rownum, GError **error)
{
GdaSqliteRecordset *imodel = (GdaSqliteRecordset*) model;
- if (imodel->priv->tmp_row)
+ if (imodel->priv->tmp_row)
g_object_unref (imodel->priv->tmp_row);
-
*prow = fetch_next_sqlite_row (imodel, FALSE, error);
imodel->priv->tmp_row = *prow;
diff --git a/providers/firebird/gda-firebird-recordset.c b/providers/firebird/gda-firebird-recordset.c
index cfd8745..9ccce03 100644
--- a/providers/firebird/gda-firebird-recordset.c
+++ b/providers/firebird/gda-firebird-recordset.c
@@ -241,17 +241,15 @@ gda_firebird_recordset_fetch_nb_rows (GdaDataSelect *model)
/*
* Create a new filled #GdaRow object for the row at position @rownum, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row(). If new row objects are "given" to the GdaDataSelect implemantation
- * using that method, then this method should detect when all the data model rows have been analyzed
- * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
- * as it won't be used anymore to fetch rows.
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is MANDATORY if the data model supports random access
+ * - this method is only called when data model is used in random access mode
*/
static gboolean
gda_firebird_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
@@ -288,14 +286,15 @@ gda_firebird_recordset_store_all (GdaDataSelect *model, GError **error)
/*
* Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is MANDATORY
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_firebird_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
@@ -310,14 +309,16 @@ gda_firebird_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint row
/*
* Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is OPTIONAL (in this case the data model is assumed not to
+ * support moving iterators backward)
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_firebird_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
@@ -332,14 +333,16 @@ gda_firebird_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint row
/*
* Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is OPTIONAL and usefull only if there is a method quicker
+ * than iterating one step at a time to the correct position.
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_firebird_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
diff --git a/providers/jdbc/gda-jdbc-recordset.c b/providers/jdbc/gda-jdbc-recordset.c
index bb0722d..ceb7760 100644
--- a/providers/jdbc/gda-jdbc-recordset.c
+++ b/providers/jdbc/gda-jdbc-recordset.c
@@ -413,11 +413,13 @@ fetch_next_jdbc_row (GdaJdbcRecordset *model, JNIEnv *jenv, gboolean do_store, G
prow = gda_row_new (_GDA_PSTMT (ps)->ncols);
jexec_res = jni_wrapper_method_call (jenv, GdaJResultSet__fillNextRow,
- model->priv->rs_value, &error_code, &sql_state, &lerror, (jlong)GPOINTER_TO_INT(prow));
+ model->priv->rs_value, &error_code, &sql_state, &lerror,
+ (jlong)GPOINTER_TO_INT(prow));
if (!jexec_res) {
if (error && lerror)
*error = g_error_copy (lerror);
_gda_jdbc_make_error (model->priv->cnc, error_code, sql_state, lerror);
+ g_object_unref ((GObject*) prow);
return NULL;
}
@@ -425,6 +427,7 @@ fetch_next_jdbc_row (GdaJdbcRecordset *model, JNIEnv *jenv, gboolean do_store, G
gda_value_free (jexec_res);
if (! row_found) {
GDA_DATA_SELECT (model)->advertized_nrows = model->priv->next_row_num;
+ g_object_unref ((GObject*) prow);
return NULL;
}
@@ -468,7 +471,8 @@ gda_jdbc_recordset_fetch_nb_rows (GdaDataSelect *model)
/*
* Create a new filled #GdaRow object for the row at position @rownum.
*
- * Each new #GdaRow created is "given" to the #GdaDataSelect implementation using gda_data_select_take_row ().
+ * Each new #GdaRow created is "given" to the #GdaDataSelect implementation
+ * using gda_data_select_take_row ().
*/
static gboolean
gda_jdbc_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
@@ -479,23 +483,18 @@ gda_jdbc_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownu
jenv = _gda_jdbc_get_jenv (&jni_detach, NULL);
if (!jenv)
- return FALSE;
+ return TRUE;
imodel = GDA_JDBC_RECORDSET (model);
- for (; imodel->priv->next_row_num <= rownum; ) {
- *prow = fetch_next_jdbc_row (imodel, jenv, TRUE, error);
- if (!*prow) {
- /*if (GDA_DATA_SELECT (model)->advertized_nrows >= 0), it's not an error */
- if ((GDA_DATA_SELECT (model)->advertized_nrows >= 0) &&
- (imodel->priv->next_row_num < rownum)) {
- g_set_error (error, 0,
- GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
- _("Row %d not found"), rownum);
- }
- _gda_jdbc_release_jenv (jni_detach);
- return FALSE;
- }
- }
+ if (imodel->priv->next_row_num >= rownum) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+ "%s", _("Requested row could not be found"));
+ return TRUE;
+ }
+ for (*prow = fetch_next_jdbc_row (imodel, jenv, TRUE, error);
+ *prow && (imodel->priv->next_row_num < rownum);
+ *prow = fetch_next_jdbc_row (imodel, jenv, TRUE, error));
_gda_jdbc_release_jenv (jni_detach);
return TRUE;
@@ -505,7 +504,8 @@ gda_jdbc_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownu
* Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
*
* Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
- * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ * never keeps a reference to it). Before a new #GdaRow gets created, the previous one,
+ * if set, is discarded.
*/
static gboolean
gda_jdbc_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, G_GNUC_UNUSED gint rownum, GError **error)
@@ -518,9 +518,6 @@ gda_jdbc_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, G_GNUC_UNUSE
if (!jenv)
return FALSE;
- if (*prow)
- return TRUE;
-
if (imodel->priv->tmp_row)
g_object_unref (imodel->priv->tmp_row);
diff --git a/providers/ldap/gdaprov-data-model-ldap.c b/providers/ldap/gdaprov-data-model-ldap.c
index 4c6f8a3..a4ff290 100644
--- a/providers/ldap/gdaprov-data-model-ldap.c
+++ b/providers/ldap/gdaprov-data-model-ldap.c
@@ -1045,12 +1045,14 @@ gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
if (! imodel->priv->cnc) {
/* error */
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
}
cdata = (LdapConnectionData*) gda_virtual_connection_internal_get_provider_data (GDA_VIRTUAL_CONNECTION (imodel->priv->cnc));
if (!cdata) {
/* error */
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
}
@@ -1071,6 +1073,7 @@ gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
cpart = imodel->priv->current_exec;
if (! cpart->ldap_msg) {
/* error somewhere */
+ gda_data_model_iter_invalidate_contents (iter);
return FALSE;
}
@@ -1101,7 +1104,7 @@ gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
if (!imodel->priv->current_exec) {
/* execution is over */
- g_signal_emit_by_name (iter, "end-of-data");
+ gda_data_model_iter_invalidate_contents (iter);
g_object_set (G_OBJECT (iter), "current-row", -1, NULL);
if (imodel->priv->truncated) {
GError *e;
@@ -1110,6 +1113,7 @@ gda_data_model_ldap_iter_next (GdaDataModel *model, GdaDataModelIter *iter)
_("Truncated result because LDAP server limit encountered"));
add_exception (imodel, e);
}
+ g_signal_emit_by_name (iter, "end-of-data");
return FALSE;
}
diff --git a/providers/mysql/gda-mysql-recordset.c b/providers/mysql/gda-mysql-recordset.c
index 3211dae..4b86109 100644
--- a/providers/mysql/gda-mysql-recordset.c
+++ b/providers/mysql/gda-mysql-recordset.c
@@ -1004,17 +1004,7 @@ new_row_from_mysql_stmt (GdaMysqlRecordset *imodel, G_GNUC_UNUSED gint rownum, G
/*
* Create a new filled #GdaRow object for the row at position @rownum, and put it into *row.
*
- * WARNING: @row will NOT be NULL, but *row may or may not be NULL:
- * - If *row is NULL then a new #GdaRow object has to be created,
- * - and otherwise *row contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row(). If new row objects are "given" to the GdaDataSelect implemantation
- * using that method, then this method should detect when all the data model rows have been analyzed
- * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
- * as it won't be used anymore to fetch rows.
+ * Each new GdaRow is given to @model using gda_data_select_take_row().
*/
static gboolean
gda_mysql_recordset_fetch_random (GdaDataSelect *model,
@@ -1026,12 +1016,9 @@ gda_mysql_recordset_fetch_random (GdaDataSelect *model,
imodel = GDA_MYSQL_RECORDSET (model);
- if (*row)
- return TRUE;
-
*row = new_row_from_mysql_stmt (imodel, rownum, error);
if (!*row)
- return FALSE;
+ return TRUE;
gda_data_select_take_row (model, *row, rownum);
@@ -1047,14 +1034,9 @@ gda_mysql_recordset_fetch_random (GdaDataSelect *model,
/*
* Create a new filled #GdaRow object for the next cursor row, and put it into *row.
*
- * WARNING: @row will NOT be NULL, but *row may or may not be NULL:
- * - If *row is NULL then a new #GdaRow object has to be created,
- * - and otherwise *row contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
+ * never keeps a reference to it).
+ * Before a new #GdaRow gets created, the previous one, if set, is discarded.
*/
static gboolean
gda_mysql_recordset_fetch_next (GdaDataSelect *model,
@@ -1064,43 +1046,33 @@ gda_mysql_recordset_fetch_next (GdaDataSelect *model,
{
GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
- // TO_IMPLEMENT;
-
- // gda_data_select_iter_next () increments rownum
-
- if (imodel->priv->tmp_row != NULL) {
+ if (imodel->priv->tmp_row)
g_object_unref (G_OBJECT(imodel->priv->tmp_row));
- imodel->priv->tmp_row = NULL;
- }
-
*row = new_row_from_mysql_stmt (imodel, rownum, error);
-
imodel->priv->tmp_row = *row;
- return *row ? TRUE : FALSE;
+ return TRUE;
}
/*
- * Create a new filled #GdaRow object for the previous cursor row, and put it into *row.
- *
- * WARNING: @row will NOT be NULL, but *row may or may not be NULL:
- * - If *row is NULL then a new #GdaRow object has to be created,
- * - and otherwise *row contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
+ * Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
*
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
+ * never keeps a reference to it).
+ * Before a new #GdaRow gets created, the previous one, if set, is discarded.
*/
static gboolean
-gda_mysql_recordset_fetch_prev (G_GNUC_UNUSED GdaDataSelect *model,
- G_GNUC_UNUSED GdaRow **row,
- G_GNUC_UNUSED gint rownum,
- G_GNUC_UNUSED GError **error)
+gda_mysql_recordset_fetch_prev (GdaDataSelect *model,
+ GdaRow **row,
+ gint rownum,
+ GError **error)
{
- /*GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;*/
+ GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
- TO_IMPLEMENT;
+ if (imodel->priv->tmp_row)
+ g_object_unref (G_OBJECT(imodel->priv->tmp_row));
+ *row = new_row_from_mysql_stmt (imodel, rownum, error);
+ imodel->priv->tmp_row = *row;
return TRUE;
}
@@ -1108,24 +1080,22 @@ gda_mysql_recordset_fetch_prev (G_GNUC_UNUSED GdaDataSelect *model,
/*
* Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *row.
*
- * WARNING: @row will NOT be NULL, but *row may or may not be NULL:
- * - If *row is NULL then a new #GdaRow object has to be created,
- * - and otherwise *row contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
+ * never keeps a reference to it).
+ * Before a new #GdaRow gets created, the previous one, if set, is discarded.
*/
static gboolean
-gda_mysql_recordset_fetch_at (G_GNUC_UNUSED GdaDataSelect *model,
- G_GNUC_UNUSED GdaRow **row,
- G_GNUC_UNUSED gint rownum,
- G_GNUC_UNUSED GError **error)
+gda_mysql_recordset_fetch_at (GdaDataSelect *model,
+ GdaRow **row,
+ gint rownum,
+ GError **error)
{
- /*GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;*/
-
- TO_IMPLEMENT;
+ GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
+
+ if (imodel->priv->tmp_row)
+ g_object_unref (G_OBJECT(imodel->priv->tmp_row));
+ *row = new_row_from_mysql_stmt (imodel, rownum, error);
+ imodel->priv->tmp_row = *row;
return TRUE;
}
diff --git a/providers/oracle/gda-oracle-recordset.c b/providers/oracle/gda-oracle-recordset.c
index f91b3c0..54f2a8c 100644
--- a/providers/oracle/gda-oracle-recordset.c
+++ b/providers/oracle/gda-oracle-recordset.c
@@ -48,8 +48,6 @@ static void gda_oracle_recordset_dispose (GObject *object);
static gint gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model);
static gboolean gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
static gboolean gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
-static gboolean gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
-static gboolean gda_oracle_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
static GdaRow *new_row (GdaDataSelect *imodel, GdaConnection *cnc, GdaOraclePStmt *ps);
@@ -88,8 +86,8 @@ gda_oracle_recordset_class_init (GdaOracleRecordsetClass *klass)
pmodel_class->fetch_random = gda_oracle_recordset_fetch_random;
pmodel_class->fetch_next = gda_oracle_recordset_fetch_next;
- pmodel_class->fetch_prev = gda_oracle_recordset_fetch_prev;
- pmodel_class->fetch_at = gda_oracle_recordset_fetch_at;
+ pmodel_class->fetch_prev = NULL;
+ pmodel_class->fetch_at = NULL;
}
static void
@@ -505,7 +503,7 @@ gda_oracle_recordset_new (GdaConnection *cnc, GdaOraclePStmt *ps, GdaSet *exec_p
}
static GdaRow *
-fetch_next_oracle_row (GdaOracleRecordset *model, gboolean do_store, GError **error)
+fetch_next_oracle_row (GdaOracleRecordset *model, G_GNUC_UNUSED gboolean do_store, GError **error)
{
int result;
GdaRow *prow = NULL;
@@ -586,17 +584,8 @@ gda_oracle_recordset_fetch_nb_rows (GdaDataSelect *model)
/*
* Create a new filled #GdaRow object for the row at position @rownum, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row(). If new row objects are "given" to the GdaDataSelect implemantation
- * using that method, then this method should detect when all the data model rows have been analyzed
- * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
- * as it won't be used anymore to fetch rows.
+ * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using
+ * gda_data_select_take_row() because backward iterating is not supported.
*/
static gboolean
gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
@@ -605,120 +594,38 @@ gda_oracle_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint row
OracleConnectionData *cdata;
GdaConnection *cnc;
- if (*prow)
- return TRUE;
-
imodel = GDA_ORACLE_RECORDSET (model);
cnc = gda_data_select_get_connection (model);
cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
if (!cdata)
- return FALSE;
-
- for (; imodel->priv->next_row_num <= rownum; ) {
- *prow = fetch_next_oracle_row (imodel, TRUE, error);
- if (!*prow) {
- /*if (GDA_DATA_SELECT (model)->advertized_nrows >= 0), it's not an error */
- if ((GDA_DATA_SELECT (model)->advertized_nrows >= 0) &&
- (imodel->priv->next_row_num < rownum)) {
- g_set_error (error, 0,
- GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
- _("Row %d not found"), rownum);
- }
- return FALSE;
- }
- }
- return TRUE;
-}
+ return TRUE;
-/*
- * Create and "give" filled #GdaRow object for all the rows in the model
- */
-static gboolean
-gda_oracle_recordset_store_all (GdaDataSelect *model, GError **error)
-{
- GdaOracleRecordset *imodel;
- gint i;
-
- imodel = GDA_ORACLE_RECORDSET (model);
-
- /* default implementation */
- for (i = 0; i < model->advertized_nrows; i++) {
- GdaRow *prow;
- if (! gda_oracle_recordset_fetch_random (model, &prow, i, error))
- return FALSE;
+ if (imodel->priv->next_row_num >= rownum) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+ "%s", _("Requested row could not be found"));
+ return TRUE;
}
+ for (*prow = fetch_next_oracle_row (imodel, TRUE, error);
+ *prow && (imodel->priv->next_row_num < rownum);
+ *prow = fetch_next_oracle_row (imodel, TRUE, error));
+
return TRUE;
}
/*
* Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * Each new #GdaRow created needs to be "given" to the #GdaDataSelect implementation using
+ * gda_data_select_take_row() because backward iterating is not supported.
*/
static gboolean
gda_oracle_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
- if (*prow)
- return TRUE;
-
*prow = fetch_next_oracle_row ((GdaOracleRecordset*) model, TRUE, error);
- return *prow ? TRUE : FALSE;
-}
-
-/*
- * Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
- *
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
- */
-static gboolean
-gda_oracle_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
-{
- OracleConnectionData *cdata;
- GdaConnection *cnc;
-
- if (*prow)
- return TRUE;
-
- cnc = gda_data_select_get_connection (model);
- cdata = (OracleConnectionData*) gda_connection_internal_get_provider_data (cnc);
- if (!cdata)
- return FALSE;
-
- g_warning ("Internal implementation error: non scrollable cursor requested to go backward!\n");
- return FALSE;
+ return TRUE;
}
-/*
- * Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
- *
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
- */
-static gboolean
-gda_oracle_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
-{
- return gda_oracle_recordset_fetch_random (model, prow, rownum, error);
-}
/* create a new GdaRow from the last read row */
static GdaRow *
diff --git a/providers/postgres/gda-postgres-recordset.c b/providers/postgres/gda-postgres-recordset.c
index 524b0a3..087048d 100644
--- a/providers/postgres/gda-postgres-recordset.c
+++ b/providers/postgres/gda-postgres-recordset.c
@@ -440,13 +440,10 @@ gda_postgres_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint r
{
GdaPostgresRecordset *imodel = (GdaPostgresRecordset *) model;
- if (*prow)
- return TRUE;
-
if (!imodel->priv->pg_res) {
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_INTERNAL_ERROR,
"%s", _("Internal error"));
- return FALSE;
+ return TRUE;
}
*prow = new_row_from_pg_res (imodel, rownum, error);
@@ -489,23 +486,19 @@ gda_postgres_recordset_store_all (GdaDataSelect *model, GError **error)
* Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
*
* Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
- * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ * never keeps a reference to it).
*/
static gboolean
gda_postgres_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
- if (*prow)
- return TRUE;
-
if (row_is_in_current_pg_res (imodel, rownum)) {
if (imodel->priv->tmp_row)
set_prow_with_pg_res (imodel, imodel->priv->tmp_row, rownum - imodel->priv->pg_res_inf, error);
else
imodel->priv->tmp_row = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
*prow = imodel->priv->tmp_row;
- return TRUE;
}
else {
gboolean fetch_error = FALSE;
@@ -515,34 +508,28 @@ gda_postgres_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint row
else
imodel->priv->tmp_row = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
*prow = imodel->priv->tmp_row;
- return TRUE;
}
- else
- return !fetch_error;
}
+ return TRUE;
}
/*
* Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
*
* Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
- * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ * never keeps a reference to it).
*/
static gboolean
gda_postgres_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
- if (*prow)
- return TRUE;
-
if (row_is_in_current_pg_res (imodel, rownum)) {
if (imodel->priv->tmp_row)
set_prow_with_pg_res (imodel, imodel->priv->tmp_row, rownum - imodel->priv->pg_res_inf, error);
else
imodel->priv->tmp_row = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
*prow = imodel->priv->tmp_row;
- return TRUE;
}
else {
gboolean fetch_error = FALSE;
@@ -552,27 +539,22 @@ gda_postgres_recordset_fetch_prev (GdaDataSelect *model, GdaRow **prow, gint row
else
imodel->priv->tmp_row = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
*prow = imodel->priv->tmp_row;
- return TRUE;
}
- else
- return !fetch_error;
}
+ return TRUE;
}
/*
* Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
*
* Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
- * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ * never keeps a reference to it).
*/
static gboolean
gda_postgres_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
{
GdaPostgresRecordset *imodel = (GdaPostgresRecordset*) model;
- if (*prow)
- return TRUE;
-
if (imodel->priv->tmp_row) {
g_object_unref (imodel->priv->tmp_row);
imodel->priv->tmp_row = NULL;
@@ -581,18 +563,15 @@ gda_postgres_recordset_fetch_at (GdaDataSelect *model, GdaRow **prow, gint rownu
if (row_is_in_current_pg_res (imodel, rownum)) {
*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
imodel->priv->tmp_row = *prow;
- return TRUE;
}
else {
gboolean fetch_error = FALSE;
if (fetch_row_number_chunk (imodel, rownum, &fetch_error, error)) {
*prow = new_row_from_pg_res (imodel, rownum - imodel->priv->pg_res_inf, error);
imodel->priv->tmp_row = *prow;
- return TRUE;
}
- else
- return !fetch_error;
}
+ return TRUE;
}
diff --git a/providers/skel-implementation/capi/gda-capi-recordset.c b/providers/skel-implementation/capi/gda-capi-recordset.c
index 2334b2b..5079737 100644
--- a/providers/skel-implementation/capi/gda-capi-recordset.c
+++ b/providers/skel-implementation/capi/gda-capi-recordset.c
@@ -247,17 +247,15 @@ gda_capi_recordset_fetch_nb_rows (GdaDataSelect *model)
/*
* Create a new filled #GdaRow object for the row at position @rownum, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row(). If new row objects are "given" to the GdaDataSelect implemantation
- * using that method, then this method should detect when all the data model rows have been analyzed
- * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
- * as it won't be used anymore to fetch rows.
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is MANDATORY if the data model supports random access
+ * - this method is only called when data model is used in random access mode
*/
static gboolean
gda_capi_recordset_fetch_random (GdaDataSelect *model, G_GNUC_UNUSED GdaRow **prow, G_GNUC_UNUSED gint rownum,
@@ -298,14 +296,15 @@ gda_capi_recordset_store_all (GdaDataSelect *model, GError **error)
/*
* Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is MANDATORY
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_capi_recordset_fetch_next (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED GdaRow **prow,
@@ -321,14 +320,16 @@ gda_capi_recordset_fetch_next (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED
/*
* Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is OPTIONAL (in this case the data model is assumed not to
+ * support moving iterators backward)
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_capi_recordset_fetch_prev (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED GdaRow **prow,
@@ -344,14 +345,16 @@ gda_capi_recordset_fetch_prev (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED
/*
* Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
*
- * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
- * - If *prow is NULL then a new #GdaRow object has to be created,
- * - and otherwise *prow contains a #GdaRow object which has already been created
- * (through a call to this very function), and in this case it should not be modified
- * but the function may return FALSE if an error occurred.
- *
- * Memory management for that new GdaRow object is left to the implementation, which
- * can use gda_data_select_take_row().
+ * NOTES:
+ * - @prow will NOT be NULL, but *prow WILL be NULL.
+ * - a new #GdaRow object has to be created.
+ * - memory management for that new GdaRow object is left to the implementation, which
+ * can use gda_data_select_take_row() to "give" the GdaRow to @model (in this case
+ * this method won't be called anymore for the same @rownum), or may decide to
+ * keep a cache of GdaRow object and "recycle" them.
+ * - implementing this method is OPTIONAL and usefull only if there is a method quicker
+ * than iterating one step at a time to the correct position.
+ * - this method is only called when data model is used in cursor access mode
*/
static gboolean
gda_capi_recordset_fetch_at (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED GdaRow **prow,
@@ -363,4 +366,3 @@ gda_capi_recordset_fetch_at (G_GNUC_UNUSED GdaDataSelect *model, G_GNUC_UNUSED G
return TRUE;
}
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]