libgda r3202 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite/virtual tests/data-models
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3202 - in trunk: . doc/C doc/C/tmpl libgda libgda/sqlite/virtual tests/data-models
- Date: Sun, 7 Sep 2008 19:06:38 +0000 (UTC)
Author: vivien
Date: Sun Sep 7 19:06:38 2008
New Revision: 3202
URL: http://svn.gnome.org/viewvc/libgda?rev=3202&view=rev
Log:
2008-09-07 Vivien Malerba <malerba gnome-db org>
* libgda/gda-data-select.[ch]:
* tests/data-models/check_pmodel.c: correctly handle the situation where the value
of the primary key (or the column which composes the unique row condition) is modified,
and added a "safety lock" feature which prevents further modification to the data model
if the unique row condition is incorrect
* doc/C: documentation improvements, and now the generated file when running "make PDF"
is libgda-4.0-doc.pdf (for the V4 ABI).
* libgda/sqlite/virtual/gda-vconnection-hub.c: no need anymore to use a GdaDataModelQuery
object
* libgda/Makefile.am:
* libgda/gda-data-select-extra.h:
* libgda/gda-data-select.[ch]: enable "exporting" all the statements and other information
computed while the object was being used to be used by the new GdaDataModelQuery
implementation
* libgda/gda-data-model-query.[ch]: re-wrote the object to use the GdaDataSelect's features
instead or re-implementing them in the object
* libgda/tests/data-models/Makefile.am:
* libgda/tests/data-models/check_model_query.c: new GdaDataModelQuery test
* libgda/tests/data-models/check_pmodel.c: new tests
Added:
trunk/doc/C/writable_data_model.dia (contents, props changed)
trunk/doc/C/writable_data_model.png (contents, props changed)
trunk/libgda/gda-data-select-extra.h
trunk/tests/data-models/check_model_query.c
Modified:
trunk/ChangeLog
trunk/doc/C/Makefile.am
trunk/doc/C/tmpl/gda-data-model-query.sgml
trunk/doc/C/tmpl/gda-data-select.sgml
trunk/libgda/Makefile.am
trunk/libgda/gda-data-model-iter.c
trunk/libgda/gda-data-model-query.c
trunk/libgda/gda-data-model-query.h
trunk/libgda/gda-data-model.c
trunk/libgda/gda-data-select.c
trunk/libgda/gda-data-select.h
trunk/libgda/sqlite/virtual/gda-vconnection-hub.c
trunk/tests/data-models/ (props changed)
trunk/tests/data-models/Makefile.am
trunk/tests/data-models/check_pmodel.c
Modified: trunk/doc/C/Makefile.am
==============================================================================
--- trunk/doc/C/Makefile.am (original)
+++ trunk/doc/C/Makefile.am Sun Sep 7 19:06:38 2008
@@ -49,7 +49,8 @@
HTML_IMAGES = DataModels.png \
architecture.png parts.png stmt-unknown.png stmt-select.png stmt-insert1.png stmt-insert2.png \
stmt-update.png stmt-compound.png information_schema.png \
- MetaStore1.png MetaStore2.png i_s_data_types.png
+ MetaStore1.png MetaStore2.png i_s_data_types.png \
+ writable_data_model.png
# Extra options to supply to gtkdoc-fixref
FIXXREF_OPTIONS=
@@ -67,7 +68,7 @@
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
-DISTCLEANFILES = $(DOC_MODULE)-docs.sgml.pdf
+DISTCLEANFILES = $(DOC_MODULE)-doc.pdf
DOC_STAMPS += pdf-build.stamp
CLEANFILES += $(DOC_STAMPS)
@@ -76,6 +77,6 @@
PDF: pdf-build.stamp
pdf-build.stamp:
if test -f $(srcdir)/$(DOC_MAIN_SGML_FILE); then \
- dblatex $(srcdir)/$(DOC_MAIN_SGML_FILE); \
+ dblatex $(srcdir)/$(DOC_MAIN_SGML_FILE) -o $(DOC_MODULE)-doc.pdf ; \
fi
touch pdf-build.stamp
Modified: trunk/doc/C/tmpl/gda-data-model-query.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-data-model-query.sgml (original)
+++ trunk/doc/C/tmpl/gda-data-model-query.sgml Sun Sep 7 19:06:38 2008
@@ -30,38 +30,16 @@
</para>
-<!-- ##### ARG GdaDataModelQuery:delete-query ##### -->
+<!-- ##### ARG GdaDataModelQuery:exec-params ##### -->
<para>
</para>
-<!-- ##### ARG GdaDataModelQuery:insert-query ##### -->
+<!-- ##### ARG GdaDataModelQuery:statement ##### -->
<para>
</para>
-<!-- ##### ARG GdaDataModelQuery:query ##### -->
-<para>
-
-</para>
-
-<!-- ##### ARG GdaDataModelQuery:update-query ##### -->
-<para>
-
-</para>
-
-<!-- ##### ARG GdaDataModelQuery:use-transaction ##### -->
-<para>
-
-</para>
-
-<!-- ##### ENUM GdaDataModelQueryOptions ##### -->
-<para>
-
-</para>
-
- GDA_DATA_MODEL_QUERY_OPTION_USE_ALL_FIELDS_IF_NO_PK:
-
<!-- ##### STRUCT GdaDataModelQueryClass ##### -->
<para>
@@ -82,15 +60,7 @@
@cnc:
@select_stmt:
- Returns:
-
-
-<!-- ##### FUNCTION gda_data_model_query_get_parameter_list ##### -->
-<para>
-
-</para>
-
- model:
+ params:
@Returns:
@@ -104,26 +74,3 @@
@Returns:
-<!-- ##### FUNCTION gda_data_model_query_set_modification_query ##### -->
-<para>
-
-</para>
-
- model:
- mod_stmt:
- error:
- Returns:
-
-
-<!-- ##### FUNCTION gda_data_model_query_compute_modification_queries ##### -->
-<para>
-
-</para>
-
- model:
- target:
- options:
- error:
- Returns:
-
-
Modified: trunk/doc/C/tmpl/gda-data-select.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-data-select.sgml (original)
+++ trunk/doc/C/tmpl/gda-data-select.sgml Sun Sep 7 19:06:38 2008
@@ -15,7 +15,23 @@
The default behaviour however is to disallow modifications, and this section documents how to characterize
a <link linkend="GdaDataSelect">GdaDataSelect</link> to allow modifications. Once this is done, any modification
done to the data model whill be propagated to the modified table in the database using INSERT, UPDATE or DELETE
- statements, while the data in the data model will always be kept up to date with the modifications done.
+ statements.
+</para>
+<para>
+ After any modification, it is still possible to read values from the data model (even values for rows which have
+ been modified or inserted). The data model might then execute some SELECT statement to fetch some actualized values.
+ Note: there is a corner case where a modification made to a row would make the row not selected at first in the data model
+ (for example is the original SELECT statement included a clause <![CDATA["WHERE id < 100"]]> and the modification sets the
+ <![CDATA["id"]]> value to 110), then the row will still be in the data model even though it would not be if the SELECT statement
+ which execution created the data model in the first place was re-run. This is illustrated in the schema below:
+ <mediaobject>
+ <imageobject role="html">
+ <imagedata fileref="writable_data_model.png" format="PNG" contentwidth="100mm"/>
+ </imageobject>
+ <textobject>
+ <phrase>GdaDataSelect data model's contents after some modifications</phrase>
+ </textobject>
+ </mediaobject>
</para>
<!-- ##### SECTION See_Also ##### -->
Added: trunk/doc/C/writable_data_model.dia
==============================================================================
Binary file. No diff available.
Added: trunk/doc/C/writable_data_model.png
==============================================================================
Binary file. No diff available.
Modified: trunk/libgda/Makefile.am
==============================================================================
--- trunk/libgda/Makefile.am (original)
+++ trunk/libgda/Makefile.am Sun Sep 7 19:06:38 2008
@@ -100,6 +100,7 @@
gda-data-access-wrapper.c \
gda-data-proxy.c \
gda-data-select.c \
+ gda-data-select-extra.h \
gda-easy.c \
gda-holder.c \
gda-init.c \
Modified: trunk/libgda/gda-data-model-iter.c
==============================================================================
--- trunk/libgda/gda-data-model-iter.c (original)
+++ trunk/libgda/gda-data-model-iter.c Sun Sep 7 19:06:38 2008
@@ -527,9 +527,13 @@
* @iter: a #GdaDataModelIter object
* @row: the row to set @iter to
*
- * Synchronizes the values of the parameters in @iter with the values at the @row row
+ * Synchronizes the values of the parameters in @iter with the values at the @row row.
*
- * If @row < 0 then @iter is not bound to any row of the data model it iters through.
+ * If @row is not a valid row, then the returned value is FALSE, and the "current-row"
+ * property is set to -1.
+ *
+ * If any other error occurred then the returned value is FALSE, but the "current-row"
+ * property is set to the @row row.
*
* Returns: TRUE if no error occurred
*/
@@ -556,10 +560,17 @@
* gda_data_model_iter_move_next
* @iter: a #GdaDataModelIter object
*
- * Moves @iter one row further than where it already is (synchronizes the values of the parameters in @iter
- * with the values at the new row).
+ * Moves @iter one row further than where it already is
+ * (synchronizes the values of the parameters in @iter with the values at the new row).
*
- * Returns: TRUE if no error occurred
+ * 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).
+ *
+ * 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).
+ *
+ * Returns: TRUE if the iterator is now at the next row
*/
gboolean
gda_data_model_iter_move_next (GdaDataModelIter *iter)
@@ -577,7 +588,14 @@
* Moves @iter one row before where it already is (synchronizes the values of the parameters in @iter
* with the values at the new row).
*
- * Returns: TRUE if no error occurred
+ * 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 (nore also that the "current-row" property
+ * is set to -1).
+ *
+ * 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).
+ *
+ * Returns: TRUE if the iterator is now at the previous row
*/
gboolean
gda_data_model_iter_move_prev (GdaDataModelIter *iter)
Modified: trunk/libgda/gda-data-model-query.c
==============================================================================
--- trunk/libgda/gda-data-model-query.c (original)
+++ trunk/libgda/gda-data-model-query.c Sun Sep 7 19:06:38 2008
@@ -27,57 +27,42 @@
#include <libgda/gda-data-model-query.h>
#include <libgda/gda-data-model-private.h>
#include <libgda/gda-data-model-extra.h>
-#include <libgda/gda-data-model-iter.h>
-#include <libgda/gda-statement.h>
-#include <libgda/gda-meta-struct.h>
+#include <libgda/gda-data-select-extra.h>
#include <libgda/gda-set.h>
-#include <libgda/gda-holder.h>
-#include <libgda/gda-util.h>
-#include <sql-parser/gda-sql-statement.h>
+#include <libgda/gda-statement.h>
+#include <libgda/gda-data-select.h>
struct _GdaDataModelQueryPrivate {
GdaConnection *cnc;
- GdaStatement *statements[4]; /* indexed by SEL_* */
- GdaSet *params[4]; /* parameters required to execute @query, indexed by SEL_* */
-
GdaDataModel *data;
- GError *refresh_error; /* if @data is NULL, then can contain the error */
+ GdaDataSelectInternals *inter;
- gboolean multiple_updates;
- gboolean needs_refresh;
- GSList *columns;
+ GError *exec_error;
+ GdaStatement *select_stmt;
+ GdaSet *params;
- gboolean transaction_allowed;
- gboolean transaction_started; /* true if we have started a transaction here */
- gboolean transaction_needs_commit;
guint svp_id; /* counter for savepoints */
+ gboolean transaction_needs_commit;
+ gboolean transaction_allowed;
+ gboolean transaction_started; /* true if we have started a transaction here */
gchar *svp_name; /* non NULL if we have created a savepoint here */
- /* note: transaction_started and svp_name are mutually exclusive */
-
- gboolean emit_reset;
+ /* note: transaction_started and svp_name are mutually exclusive */
};
/* properties */
enum
{
PROP_0,
- PROP_SEL_QUERY,
- PROP_INS_QUERY,
- PROP_UPD_QUERY,
- PROP_DEL_QUERY,
- PROP_USE_TRANSACTION,
- PROP_CNC
+ PROP_CNC,
+ PROP_STMT,
+ PROP_PARAMS
};
-enum
-{
- SEL_QUERY = 0,
- INS_QUERY = 1,
- UPD_QUERY = 2,
- DEL_QUERY = 3
-};
static void gda_data_model_query_class_init (GdaDataModelQueryClass *klass);
+static GObject *gda_data_model_query_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties);
static void gda_data_model_query_init (GdaDataModelQuery *model,
GdaDataModelQueryClass *klass);
static void gda_data_model_query_dispose (GObject *object);
@@ -101,27 +86,18 @@
static const GValue *gda_data_model_query_get_value_at (GdaDataModel *model, gint col, gint row, GError **error);
static GdaValueAttribute gda_data_model_query_get_attributes_at (GdaDataModel *model, gint col, gint row);
-static GdaDataModelIter *gda_data_model_query_create_iter (GdaDataModel *model);
-
static gboolean gda_data_model_query_set_value_at (GdaDataModel *model, gint col, gint row,
const GValue *value, GError **error);
static gboolean gda_data_model_query_set_values (GdaDataModel *model, gint row,
GList *values, GError **error);
static gint gda_data_model_query_append_values (GdaDataModel *model, const GList *values, GError **error);
-static gint gda_data_model_query_append_row (GdaDataModel *model, GError **error);
static gboolean gda_data_model_query_remove_row (GdaDataModel *model, gint row,
GError **error);
static void gda_data_model_query_send_hint (GdaDataModel *model, GdaDataModelHint hint,
const GValue *hint_value);
-static void create_columns (GdaDataModelQuery *model);
-static void forget_statement (GdaDataModelQuery *model, GdaStatement *stmt);
static void holder_changed_cb (GdaSet *paramlist, GdaHolder *param, GdaDataModelQuery *model);
-static void opt_start_transaction_or_svp (GdaDataModelQuery *selmodel);
-static void opt_end_transaction_or_svp (GdaDataModelQuery *selmodel);
-
-
static GObjectClass *parent_class = NULL;
/* module error */
@@ -189,41 +165,27 @@
g_param_spec_object ("connection", "Connection to use",
"Connection to use to execute statements",
GDA_TYPE_CONNECTION,
- G_PARAM_READABLE | G_PARAM_WRITABLE));
+ G_PARAM_READABLE | G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class, PROP_SEL_QUERY,
- g_param_spec_object ("query", "SELECT query",
- "SELECT Query to be executed to populate "
+ g_object_class_install_property (object_class, PROP_STMT,
+ g_param_spec_object ("statement", "SELECT statement",
+ "SELECT statement to be executed to populate "
"the model with data",
GDA_TYPE_STATEMENT,
G_PARAM_READABLE | G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class, PROP_INS_QUERY,
- g_param_spec_object ("insert_query", "INSERT query",
- "INSERT Query to be executed to add data",
- GDA_TYPE_STATEMENT,
- G_PARAM_READABLE | G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_UPD_QUERY,
- g_param_spec_object ("update_query", "UPDATE query",
- "UPDATE Query to be executed to update data",
- GDA_TYPE_STATEMENT,
- G_PARAM_READABLE | G_PARAM_WRITABLE));
+ g_object_class_install_property (object_class, PROP_PARAMS,
+ g_param_spec_object ("exec-params", "SELECT statement's parameters",
+ "Parameters used with the SELECT statement",
+ GDA_TYPE_SET,
+ G_PARAM_READABLE | G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY));
- g_object_class_install_property (object_class, PROP_DEL_QUERY,
- g_param_spec_object ("delete_query", "DELETE query",
- "DELETE Query to be executed to remove data",
- GDA_TYPE_STATEMENT,
- G_PARAM_READABLE | G_PARAM_WRITABLE));
-
- g_object_class_install_property (object_class, PROP_USE_TRANSACTION,
- g_param_spec_boolean ("use_transaction", "Use transaction",
- "Run modification statements within a transaction",
- FALSE,
- G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT));
/* virtual functions */
+ object_class->constructor = gda_data_model_query_constructor;
object_class->dispose = gda_data_model_query_dispose;
object_class->finalize = gda_data_model_query_finalize;
}
@@ -238,7 +200,7 @@
iface->i_get_value_at = gda_data_model_query_get_value_at;
iface->i_get_attributes_at = gda_data_model_query_get_attributes_at;
- iface->i_create_iter = gda_data_model_query_create_iter;
+ iface->i_create_iter = NULL;
iface->i_iter_at_row = NULL;
iface->i_iter_next = NULL;
iface->i_iter_prev = NULL;
@@ -246,7 +208,7 @@
iface->i_set_value_at = gda_data_model_query_set_value_at;
iface->i_set_values = gda_data_model_query_set_values;
iface->i_append_values = gda_data_model_query_append_values;
- iface->i_append_row = gda_data_model_query_append_row;
+ iface->i_append_row = NULL;
iface->i_remove_row = gda_data_model_query_remove_row;
iface->i_find_row = NULL;
@@ -261,20 +223,27 @@
g_return_if_fail (GDA_IS_DATA_MODEL_QUERY (model));
model->priv = g_new0 (GdaDataModelQueryPrivate, 1);
model->priv->data = NULL;
- model->priv->refresh_error = NULL;
- model->priv->columns = NULL;
+ model->priv->inter = NULL;
+ model->priv->exec_error = NULL;
+ model->priv->select_stmt = NULL;
+ model->priv->params = NULL;
+}
+
+static GObject *
+gda_data_model_query_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_properties)
+{
+ GObject *object;
+ GdaDataModelQuery *model;
- /* model refreshing is performed as soon as any modification is done */
- model->priv->multiple_updates = FALSE;
- model->priv->needs_refresh = FALSE;
-
- model->priv->transaction_allowed = FALSE;
- model->priv->transaction_started = FALSE;
- model->priv->transaction_needs_commit = FALSE;
- model->priv->svp_id = 0;
- model->priv->svp_name = NULL;
+ object = G_OBJECT_CLASS (parent_class)->constructor (type,
+ n_construct_properties,
+ construct_properties);
+ model = (GdaDataModelQuery *) object;
+ gda_data_model_query_refresh (model, NULL);
- model->priv->emit_reset = FALSE;
+ return object;
}
static void
@@ -286,38 +255,24 @@
/* free memory */
if (model->priv) {
- gint i;
-
if (model->priv->cnc) {
g_object_unref (model->priv->cnc);
model->priv->cnc = NULL;
}
- if (model->priv->transaction_started || model->priv->svp_name)
- opt_end_transaction_or_svp (model);
-
- if (model->priv->columns) {
- g_slist_foreach (model->priv->columns, (GFunc) g_object_unref, NULL);
- g_slist_free (model->priv->columns);
- model->priv->columns = NULL;
+ if (model->priv->data) {
+ g_object_unref (model->priv->data);
+ model->priv->data = NULL;
}
- for (i = SEL_QUERY; i <= DEL_QUERY; i++) {
- if (model->priv->statements[i])
- forget_statement (model, model->priv->statements[i]);
-
- if (model->priv->params[i]) {
- if (i == SEL_QUERY)
- g_signal_handlers_disconnect_by_func (model->priv->params[i],
- G_CALLBACK (holder_changed_cb), model);
- g_object_unref (model->priv->params[i]);
- model->priv->params[i] = NULL;
- }
+ if (model->priv->select_stmt) {
+ g_object_unref (model->priv->select_stmt);
+ model->priv->select_stmt = NULL;
}
- if (model->priv->data) {
- g_object_unref (model->priv->data);
- model->priv->data = NULL;
+ if (model->priv->params) {
+ g_object_unref (model->priv->params);
+ model->priv->params = NULL;
}
}
@@ -334,9 +289,12 @@
/* free memory */
if (model->priv) {
- if (model->priv->refresh_error)
- g_error_free (model->priv->refresh_error);
+ g_free (model->priv->svp_name);
+ if (model->priv->inter)
+ _gda_data_select_internals_free (model->priv->inter);
+ if (model->priv->exec_error)
+ g_error_free (model->priv->exec_error);
g_free (model->priv);
model->priv = NULL;
}
@@ -345,48 +303,6 @@
parent_class->finalize (object);
}
-/*
- * converts "[+-]<num>" to <num> and returns FALSE if @pname is not like
- * "[+-]<num>". <num> is stored in @result, and the +/- signed is stored in @old_val
- * (@old_val is set to TRUE if there is a "-")
- */
-static gboolean
-param_name_to_int (const gchar *pname, gint *result, gboolean *old_val)
-{
- gint sum = 0;
- const gchar *ptr;
-
- if (!pname || ((*pname != '-') && (*pname != '+')))
- return FALSE;
-
- ptr = pname + 1;
- while (*ptr) {
- if ((*ptr > '9') || (*ptr < '0'))
- return FALSE;
- sum = sum * 10 + *ptr - '0';
- ptr++;
- }
-
- if (result)
- *result = sum;
- if (old_val)
- *old_val = (*pname == '-') ? TRUE : FALSE;
-
- return TRUE;
-}
-
-static void
-check_param_type (GdaHolder *param, GType type)
-{
- if ((type != 0) && (type != gda_holder_get_g_type (param))) {
- g_warning (_("Type of parameter '%s' is '%s' when it should be '%s', "
- "GdaDataModelQuery object will not work correctly"),
- gda_holder_get_id (param),
- g_type_name (gda_holder_get_g_type (param)),
- g_type_name (type));
- }
-}
-
static void
gda_data_model_query_set_property (GObject *object,
guint param_id,
@@ -394,118 +310,24 @@
GParamSpec *pspec)
{
GdaDataModelQuery *model;
- gint qindex = param_id - 1;
model = GDA_DATA_MODEL_QUERY (object);
if (model->priv) {
switch (param_id) {
case PROP_CNC:
- if (model->priv->cnc) {
- g_object_unref (model->priv->cnc);
- model->priv->cnc = NULL;
- }
model->priv->cnc = g_value_get_object (value);
if (model->priv->cnc)
g_object_ref (model->priv->cnc);
break;
- case PROP_SEL_QUERY:
- case PROP_INS_QUERY:
- case PROP_UPD_QUERY:
- case PROP_DEL_QUERY:
- if (model->priv->statements[qindex])
- forget_statement (model, model->priv->statements[qindex]);
- if (model->priv->params[qindex]) {
- g_signal_handlers_disconnect_by_func (model->priv->params[qindex],
- G_CALLBACK (holder_changed_cb), model);
- g_object_unref (model->priv->params[qindex]);
- model->priv->params[qindex] = NULL;
- }
-
- model->priv->statements[qindex] = (GdaStatement *) g_value_get_object (value);
- if (model->priv->statements[qindex]) {
- /* make a copy of statement */
- model->priv->statements[qindex] = gda_statement_copy (model->priv->statements[qindex]);
-
- if (!gda_statement_get_parameters (model->priv->statements[qindex],
- &(model->priv->params[qindex]), NULL)) {
- g_warning (_("Could not get statement's parameters, "
- "expect some problems with the GdaDataModelQuery"));
- model->priv->params[qindex] = NULL;
- }
-
- if (qindex == SEL_QUERY) {
- /* SELECT statement */
- if (model->priv->params[qindex])
- g_signal_connect (model->priv->params[qindex], "holder_changed",
- G_CALLBACK (holder_changed_cb), model);
- }
- else {
- /* other statements: for all the parameters in the param list,
- * if some have a name like "[+-]<num>", then they will be filled with
- * the value at the new/old <num>th column before being run, or, if the name is
- * the same as a parameter for the SELECT query, then bind them to that parameter */
- gint num;
-
- if (model->priv->params [qindex]) {
- GSList *params;
- for (params = model->priv->params [qindex]->holders;
- params; params = params->next) {
- GdaHolder *holder = GDA_HOLDER (params->data);
- const gchar *pname = gda_holder_get_id (holder);
- gboolean old_val;
-
- if (param_name_to_int (pname, &num, &old_val)) {
- if (old_val)
- g_object_set_data ((GObject*) holder, "-num",
- GINT_TO_POINTER (num + 1));
- else
- g_object_set_data ((GObject*) holder, "+num",
- GINT_TO_POINTER (num + 1));
- g_object_set_data ((GObject*) holder, "_num",
- GINT_TO_POINTER (num + 1));
- GdaColumn *col;
- col = gda_data_model_describe_column ((GdaDataModel *) model,
- num);
- if (col) {
- check_param_type (holder, gda_column_get_g_type (col));
- gda_holder_set_not_null (holder,
- !gda_column_get_allow_null (col));
- if (gda_column_get_auto_increment (col) ||
- gda_column_get_default_value (col)) {
- GValue *value;
- value = gda_value_new_null ();
- gda_holder_set_default_value (holder, value);
- gda_value_free (value);
- }
- }
- }
- else {
- if (pname && model->priv->params [SEL_QUERY]) {
- GdaHolder *bind_to;
- bind_to = gda_set_get_holder
- (model->priv->params [SEL_QUERY],
- pname);
- if (bind_to) {
- check_param_type (holder,
- gda_holder_get_g_type (bind_to));
- if (! gda_holder_set_bind (holder, bind_to, NULL))
- TO_IMPLEMENT;
- }
- else
- g_warning (_("Could not find a parameter named "
- "'%s' among the SELECT query's "
- "parameters, the specified "
- "modification query will not be executable"),
- pname);
- }
- }
- }
- }
- }
- }
+ case PROP_STMT:
+ model->priv->select_stmt = g_value_get_object (value);
+ if (model->priv->select_stmt)
+ g_object_ref (model->priv->select_stmt);
break;
- case PROP_USE_TRANSACTION:
- model->priv->transaction_allowed = g_value_get_boolean (value);
+ case PROP_PARAMS:
+ model->priv->params = g_value_get_object (value);
+ if (model->priv->params)
+ g_object_ref (model->priv->params);
break;
default:
g_assert_not_reached ();
@@ -521,7 +343,6 @@
GParamSpec *pspec)
{
GdaDataModelQuery *model;
- gint qindex = param_id - 1;
model = GDA_DATA_MODEL_QUERY (object);
if (model->priv) {
@@ -529,14 +350,11 @@
case PROP_CNC:
g_value_set_object (value, model->priv->cnc);
break;
- case PROP_SEL_QUERY:
- case PROP_INS_QUERY:
- case PROP_UPD_QUERY:
- case PROP_DEL_QUERY:
- g_value_set_object (value, G_OBJECT (model->priv->statements[qindex]));
+ case PROP_STMT:
+ g_value_set_object (value, model->priv->select_stmt);
break;
- case PROP_USE_TRANSACTION:
- g_value_set_boolean (value, model->priv->transaction_allowed);
+ case PROP_PARAMS:
+ g_value_set_object (value, model->priv->params);
break;
default:
g_assert_not_reached ();
@@ -545,97 +363,77 @@
}
}
-static void
-forget_statement (GdaDataModelQuery *model, GdaStatement *stmt)
-{
- gint i;
- gint qindex = -1;
-
- for (i = SEL_QUERY; (i <= DEL_QUERY) && (qindex < 0); i++)
- if (stmt == model->priv->statements [i])
- qindex = i;
- g_assert (qindex >= 0);
-
- model->priv->statements [qindex] = NULL;
- g_object_unref (stmt);
-}
static void
holder_changed_cb (GdaSet *paramlist, GdaHolder *param, GdaDataModelQuery *model)
{
- /* first: sync the parameters which are bound */
- gboolean allok = TRUE;
- if (model->priv->params [SEL_QUERY]) {
- gint i;
- for (i = INS_QUERY; i <= DEL_QUERY; i++) {
- if (model->priv->params [i]) {
- GSList *params;
- for (params = model->priv->params [i]->holders; params; params = params->next) {
- GdaHolder *bind_to;
- bind_to = gda_holder_get_bind (GDA_HOLDER (params->data));
- if (bind_to == param)
- if (!gda_holder_set_value (GDA_HOLDER (params->data),
- gda_holder_get_value (bind_to), NULL))
- allok = FALSE;
- }
- }
- }
- }
-
- /* second: do a refresh */
- if (allok && gda_set_is_valid (paramlist))
- gda_data_model_query_refresh (model, NULL);
- else {
- if (model->priv->data) {
- g_object_unref (model->priv->data);
- model->priv->data = NULL;
- }
- gda_data_model_reset ((GdaDataModel *) model);
- }
}
/**
* gda_data_model_query_new
- * @cnc: a #GdaConnection object, or %NULL
+ * @cnc: a #GdaConnection object
* @select_stmt: a SELECT statement
+ * @params: a #GdaSet object containing @select_stmt's execution parameters (see gda_statement_get_parameters()), or %NULL
*
* Creates a new #GdaDataModel object using the data returned by the execution of the
* @select_stmt SELECT statement.
*
- * If @cnc is %NULL, then a real connection will have to be set before anything usefull can be done
- *
* Returns: a pointer to the newly created #GdaDataModel.
*/
-GdaDataModel *
-gda_data_model_query_new (GdaConnection *cnc, GdaStatement *select_stmt)
+GdaDataModelQuery *
+gda_data_model_query_new (GdaConnection *cnc, GdaStatement *select_stmt, GdaSet *params)
{
- GdaDataModelQuery *model;
-
- g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (GDA_IS_STATEMENT (select_stmt), NULL);
+ g_return_val_if_fail (!params || GDA_IS_SET (params), NULL);
- model = g_object_new (GDA_TYPE_DATA_MODEL_QUERY, "connection", cnc,
- "query", select_stmt, NULL);
+ return (GdaDataModelQuery*) g_object_new (GDA_TYPE_DATA_MODEL_QUERY,
+ "connection", cnc,
+ "statement", select_stmt,
+ "exec-params", params, NULL);
+}
- return GDA_DATA_MODEL (model);
+static gboolean
+do_notify_changes (GdaDataModel *model)
+{
+ gboolean notify_changes = TRUE;
+ if (GDA_DATA_MODEL_GET_CLASS (model)->i_get_notify)
+ notify_changes = (GDA_DATA_MODEL_GET_CLASS (model)->i_get_notify) (model);
+ return notify_changes;
}
-/**
- * gda_data_model_query_get_parameter_list
- * @model: a #GdaDataModelQuery data model
- *
- * If some parameters are required to execute the SELECT query used in the @model data model, then
- * returns the #GdaSet used; otherwise does nothing and returns %NULL.
- *
- * Returns: a #GdaSet object, or %NULL
- */
-GdaSet *
-gda_data_model_query_get_parameter_list (GdaDataModelQuery *model)
+static void
+data_select_changed_cb (GdaDataModel *priv, GdaDataModelQuery *model)
{
- g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), NULL);
- g_return_val_if_fail (model->priv, NULL);
+ if (do_notify_changes ((GdaDataModel*) model))
+ g_signal_emit_by_name (model, "changed");
+}
+
+static void
+data_select_reset_cb (GdaDataModel *priv, GdaDataModelQuery *model)
+{
+ g_signal_emit_by_name (model, "reset");
+}
+
+static void
+data_select_row_inserted_cb (GdaDataModel *priv, gint row, GdaDataModelQuery *model)
+{
+ if (do_notify_changes ((GdaDataModel*) model))
+ g_signal_emit_by_name (model, "row-inserted", row);
+}
- return model->priv->params [SEL_QUERY];
+static void
+data_select_row_removed_cb (GdaDataModel *priv, gint row, GdaDataModelQuery *model)
+{
+ if (do_notify_changes ((GdaDataModel*) model))
+ g_signal_emit_by_name (model, "row-removed", row);
+}
+
+static void
+data_select_row_updated_cb (GdaDataModel *priv, gint row, GdaDataModelQuery *model)
+{
+ if (do_notify_changes ((GdaDataModel*) model))
+ g_signal_emit_by_name (model, "row-updated", row);
}
/**
@@ -654,89 +452,264 @@
g_return_val_if_fail (model->priv, FALSE);
if (model->priv->data) {
+ /* copy the internals of the GdaDataSelect object */
+ model->priv->inter = _gda_data_select_internals_steal ((GdaDataSelect*) model->priv->data);
g_object_unref (model->priv->data);
model->priv->data = NULL;
}
- if (model->priv->refresh_error) {
- g_error_free (model->priv->refresh_error);
- model->priv->refresh_error = NULL;
- }
- if (! model->priv->statements[SEL_QUERY])
- return TRUE;
+ if (model->priv->exec_error) {
+ g_error_free (model->priv->exec_error);
+ model->priv->exec_error = NULL;
+ }
if (! model->priv->cnc) {
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
+ g_set_error (&(model->priv->exec_error), GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
_("No connection specified"));
+ g_propagate_error (error, g_error_copy (model->priv->exec_error));
return FALSE;
}
if (! gda_connection_is_opened (model->priv->cnc)) {
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
+ g_set_error (&(model->priv->exec_error), GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
_("Specified connection is closed"));
+ g_propagate_error (error, g_error_copy (model->priv->exec_error));
return FALSE;
}
model->priv->data = gda_connection_statement_execute_select (model->priv->cnc,
- model->priv->statements[SEL_QUERY],
- model->priv->params [SEL_QUERY],
- &model->priv->refresh_error);
+ model->priv->select_stmt,
+ model->priv->params, &(model->priv->exec_error));
if (!model->priv->data) {
- if (model->priv->refresh_error && error)
- *error = g_error_copy (model->priv->refresh_error);
+ g_propagate_error (error, g_error_copy (model->priv->exec_error));
return FALSE;
}
-
+
+ /* if there were some internals from a previous GdaDataSelect, then set the there */
+ if (model->priv->inter) {
+ _gda_data_select_internals_paste ((GdaDataSelect*) model->priv->data, model->priv->inter);
+ model->priv->inter = NULL;
+ }
+
+ /* be ready to propagate signals */
+ g_signal_connect (model->priv->data, "changed",
+ G_CALLBACK (data_select_changed_cb), model);
+ g_signal_connect (model->priv->data, "reset",
+ G_CALLBACK (data_select_reset_cb), model);
+ g_signal_connect (model->priv->data, "row-inserted",
+ G_CALLBACK (data_select_row_inserted_cb), model);
+ g_signal_connect (model->priv->data, "row-removed",
+ G_CALLBACK (data_select_row_removed_cb), model);
+ g_signal_connect (model->priv->data, "row-updated",
+ G_CALLBACK (data_select_row_updated_cb), model);
+
gda_data_model_reset ((GdaDataModel *) model);
return TRUE;
}
/**
- * gda_data_model_query_set_modification_query
- * @model: a #GdaDataModelQuery data model
- * @mod_stmt: a #GdaStatement object
+ * gda_data_model_query_set_row_selection_condition
+ * @model: a #GdaDataSelect data model
+ * @expr: a #GdaSqlExpr expression
+ * @error: a place to store errors, or %NULL
+ *
+ * Offers the same features as gda_data_model_query_set_row_selection_condition_sql() but using a #GdaSqlExpr
+ * structure instead of an SQL syntax.
+ *
+ * Returns: TRUE if no error occurred
+ */
+gboolean
+gda_data_model_query_set_row_selection_condition (GdaDataModelQuery *model, GdaSqlExpr *expr, GError **error)
+{
+ GdaDataModelQuery *selmodel;
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
+
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
+ return FALSE;
+ }
+ else
+ return gda_data_select_set_row_selection_condition (GDA_DATA_SELECT (selmodel->priv->data), expr, error);
+}
+
+/**
+ * gda_data_model_query_set_row_selection_condition_sql
+ * @model: a #GdaDataSelect data model
+ * @sql_where: an SQL condition (withouth the WHERE keyword)
+ * @error: a place to store errors, or %NULL
+ *
+ * Specifies the SQL condition corresponding to the WHERE part of a SELECT statement which would
+ * return only 1 row (the expression of the primary key).
+ *
+ * For example for a table created as <![CDATA["CREATE TABLE mytable (part1 int NOT NULL, part2 string NOT NULL,
+ * name string, PRIMARY KEY (part1, part2))"]]>, and if @pmodel corresponds to the execution of the
+ * <![CDATA["SELECT name, part1, part2 FROM mytable"]]>, then the sensible value for @sql_where would be
+ * <![CDATA["part1 = ##-1::int AND part2 = ##-2::string"]]> because the values of the 'part1' field are located
+ * in @pmodel's column number 1 and the values of the 'part2' field are located
+ * in @pmodel's column number 2 and the primary key is composed of (part1, part2).
+ *
+ * For more information about the syntax of the parameters (named <![CDATA["##-1::int"]]> for example), see the
+ * <link linkend="GdaSqlParser.description">GdaSqlParser</link> documentation, and
+ * gda_data_model_query_set_modification_statement().
+ *
+ * Returns: TRUE if no error occurred
+ */
+gboolean
+gda_data_model_query_set_row_selection_condition_sql (GdaDataModelQuery *model, const gchar *sql_where, GError **error)
+{
+ GdaDataModelQuery *selmodel;
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
+
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
+ return FALSE;
+ }
+ else
+ return gda_data_select_set_row_selection_condition_sql (GDA_DATA_SELECT (selmodel->priv->data), sql_where, error);
+}
+
+/**
+ * gda_data_model_query_compute_row_selection_condition
+ * @model: a #GdaDataSelect object
* @error: a place to store errors, or %NULL
*
- * Sets the modification statement to be used by @model to actually perform any change
- * to the dataset in the database.
+ * Offers the same features as gda_data_model_query_set_row_selection_condition() but the expression
+ * is computed from the meta data associated to the connection being used when @model was created.
*
- * The provided @mod_stmt statement must be either a INSERT, UPDATE or DELETE query. It can contain
- * parameters, and the parameters named '[+-]<num>' will be replaced when the query is run:
+ * NOTE1: make sure the meta data associated to the connection is up to date before using this
+ * method, see gda_connection_update_meta_store().
+ *
+ * NOTE2: if the SELECT statement from which @model has been created uses more than one table, or
+ * if the table used does not have any primary key, then this method will fail
+ *
+ * Returns: TRUE if no error occurred.
+ */
+gboolean
+gda_data_model_query_compute_row_selection_condition (GdaDataModelQuery *model, GError **error)
+{
+ GdaDataModelQuery *selmodel;
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
+
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
+ return FALSE;
+ }
+ else
+ return gda_data_select_compute_row_selection_condition (GDA_DATA_SELECT (selmodel->priv->data), error);
+}
+
+/**
+ * gda_data_model_query_set_modification_statement
+ * @model: a #GdaDataSelect data model
+ * @mod_stmt: a #GdaStatement (INSERT, UPDATE or DELETE)
+ * @error: a place to store errors, or %NULL
+ *
+ * Informs @model that it should allow modifications to the data in some columns and some rows
+ * using @mod_stmt to propagate those modifications into the database.
+ *
+ * If @mod_stmt is:
* <itemizedlist>
- * <listitem><para>a parameter named +<num> will take the new value set at the
- * <num>th column in @model</para></listitem>
- * <listitem><para>a parameter named -<num> will take the old value set at the
- * <num>th column in @model</para></listitem>
+ * <listitem><para>an UPDATE statement, then all the rows in @model will be modifyable</para></listitem>
+ * <listitem><para>a DELETE statement, then it will be possible to delete rows in @model</para></listitem>
+ * <listitem><para>in INSERT statement, then it will be possible to add some rows to @model</para></listitem>
+ * <listitem><para>any other statement, then this method will return an error</para></listitem>
* </itemizedlist>
- * Please note that the "+0" and "-0" parameters names are valid and will respectively
- * take the new and old values of the first column of @model.
*
- * Examples of statements are: "INSERT INTO orders (customer, creation_date, delivery_before, delivery_date) VALUES (## / *name:'Customer' type:integer* /, date('now'), ## / *name:"+2" type:date nullok:TRUE * /, NULL)", "DELETE FROM orders WHERE id = ## / *name:"-0" type:integer* /" and "UPDATE orders set id=## / *name:"+0" type:integer* /, delivery_before=## / *name:"+2" type:date nullok:TRUE* /, delivery_date=## / *name:"+3" type:date nullok:TRUE* / WHERE id=## / *name:"-0" type:integer* /"
+ * This method can be called several times to specify different types of modification.
+ *
+ * If @mod_stmt is an UPDATE or DELETE statement then it should have a WHERE part which identifies
+ * a unique row in @model (please note that this property can't be checked but may result
+ * in @model behaving in an unpredictable way).
+ *
+ * NOTE1: However, if the gda_data_model_query_set_row_selection_condition()
+ * or gda_data_model_query_set_row_selection_condition_sql() have been successfully be called before, the WHERE
+ * part of @mod_stmt <emphasis>WILL</emphasis> be modified to use the row selection condition specified through one of
+ * these methods (please not that it is then possible to avoid specifying a WHERE part in @mod_stmt then).
+ *
+ * NOTE2: if gda_data_model_query_set_row_selection_condition()
+ * or gda_data_model_query_set_row_selection_condition_sql() have not yet been successfully be called before, then
+ * the WHERE part of @mod_stmt will be used as if one of these functions had been called.
*
* Returns: TRUE if no error occurred.
*/
gboolean
-gda_data_model_query_set_modification_query (GdaDataModelQuery *model, GdaStatement *mod_stmt, GError **error)
+gda_data_model_query_set_modification_statement (GdaDataModelQuery *model, GdaStatement *mod_stmt, GError **error)
{
+ GdaDataModelQuery *selmodel;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
- g_return_val_if_fail (model->priv, FALSE);
- g_return_val_if_fail (GDA_IS_STATEMENT (mod_stmt), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
- switch (gda_statement_get_statement_type (mod_stmt)) {
- case GDA_SQL_STATEMENT_INSERT:
- g_object_set (model, "insert_query", mod_stmt, NULL);
- break;
- case GDA_SQL_STATEMENT_UPDATE:
- g_object_set (model, "update_query", mod_stmt, NULL);
- break;
- case GDA_SQL_STATEMENT_DELETE:
- g_object_set (model, "delete_query", mod_stmt, NULL);
- break;
- default:
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_MODIF_STATEMENT_ERROR,
- _("Wrong type of query"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return FALSE;
}
- return TRUE;
+ else
+ return gda_data_select_set_modification_statement (GDA_DATA_SELECT (selmodel->priv->data), mod_stmt, error);
+}
+
+/**
+ * gda_data_model_query_set_modification_statement_sql
+ * @model: a #GdaDataSelect data model
+ * @sql: an SQL text
+ * @error: a place to store errors, or %NULL
+ *
+ * Offers the same feature as gda_data_model_query_set_modification_statement() but using an SQL statement
+ *
+ * Returns: TRUE if no error occurred.
+ */
+gboolean
+gda_data_model_query_set_modification_statement_sql (GdaDataModelQuery *model, const gchar *sql, GError **error)
+{
+ GdaDataModelQuery *selmodel;
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
+
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
+ return FALSE;
+ }
+ else
+ return gda_data_select_set_modification_statement_sql (GDA_DATA_SELECT (selmodel->priv->data), sql, error);
+}
+
+/**
+ * gda_data_model_query_compute_modification_statements
+ * @model: a #GdaDataSelect data model
+ * @error: a place to store errors, or %NULL
+ *
+ * Makes @model try to compute INSERT, UPDATE and DELETE statements to be used when modifying @model's contents.
+ * Note: any modification statement set using gda_data_model_query_set_modification_statement() will first be unset
+ *
+ * Returns: TRUE if no error occurred. If FALSE is returned, then some modification statement may still have been
+ * computed
+ */
+gboolean
+gda_data_model_query_compute_modification_statements (GdaDataModelQuery *model, GError **error)
+{
+ GdaDataModelQuery *selmodel;
+ g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
+ selmodel = (GdaDataModelQuery*) model;
+ g_return_val_if_fail (selmodel->priv, FALSE);
+
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
+ return FALSE;
+ }
+ else
+ return gda_data_select_compute_modification_statements (GDA_DATA_SELECT (selmodel->priv->data), error);
}
/*
@@ -747,16 +720,13 @@
{
GdaDataModelQuery *selmodel;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), 0);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, 0);
- if (!selmodel->priv->data && !selmodel->priv->refresh_error)
- gda_data_model_query_refresh (selmodel, NULL);
-
- if (selmodel->priv->data)
- return gda_data_model_get_n_rows (selmodel->priv->data);
+ if (!selmodel->priv->data)
+ return -1;
else
- return 0;
+ return gda_data_model_get_n_rows (selmodel->priv->data);
}
static gint
@@ -764,171 +734,41 @@
{
GdaDataModelQuery *selmodel;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), 0);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, 0);
- if (!selmodel->priv->data && !selmodel->priv->refresh_error) {
- if (!gda_data_model_query_refresh (selmodel, NULL))
- return 0;
- }
-
- create_columns (selmodel);
-
- if (selmodel->priv->columns)
- return g_slist_length (selmodel->priv->columns);
+ if (selmodel->priv->data)
+ return gda_data_model_get_n_columns (selmodel->priv->data);
else
return 0;
}
-static void
-create_columns (GdaDataModelQuery *model)
-{
- if (model->priv->columns)
- return;
- if (! model->priv->statements[SEL_QUERY])
- return;
-
- /* we need to be able to get (or build) a list of column's title and GType. Scan through the
- * statement's GdaSqlSelectFields and if a name and GType can be determined, then use them, otherwise
- * use "column%d" and G_TYPE_STRING, and let the user modify that directly using gda_data_model_describe ()
- */
- GdaSqlStatement *sqlst;
- g_object_get (G_OBJECT (model->priv->statements[SEL_QUERY]), "structure", &sqlst, NULL);
-
- if (gda_sql_statement_normalize (sqlst, model->priv->cnc, NULL)) {
- GdaSqlStatementSelect *selst = (GdaSqlStatementSelect*) sqlst->contents;
- GSList *list;
-
- for (list = selst->expr_list; list; list = list->next) {
- GdaSqlSelectField *field = (GdaSqlSelectField*) list->data;
- GdaColumn *col;
-
- col = gda_column_new ();
- if (field->validity_meta_table_column) {
- gda_column_set_name (col, field->validity_meta_table_column->column_name);
- gda_column_set_title (col, field->validity_meta_table_column->column_name);
- gda_column_set_g_type (col, field->validity_meta_table_column->gtype);
- }
- else {
- gda_column_set_name (col, "col");
- gda_column_set_title (col, "col");
- gda_column_set_g_type (col, G_TYPE_STRING);
- }
- model->priv->columns = g_slist_append (model->priv->columns, col);
- }
- }
- else {
- if (model->priv->data) {
- /* copy model->priv->data's columns */
- gint i, nb_cols;
-
- nb_cols = gda_data_model_get_n_columns (model->priv->data);
- for (i = 0; i < nb_cols; i++) {
- GdaColumn *orig, *col;
-
- orig = gda_data_model_describe_column (model->priv->data, i);
- col = gda_column_copy (orig);
- gda_column_set_position (col, i);
- model->priv->columns = g_slist_append (model->priv->columns, col);
- }
- }
- else {
- /* Can't compute the list of columns because the SELECT query is not active
- * and the model does not contain any data;
- * next time we emit a "reset" signal */
- model->priv->emit_reset = TRUE;
- }
- }
- gda_sql_statement_free (sqlst);
-
- if (model->priv->columns && model->priv->emit_reset) {
- model->priv->emit_reset = FALSE;
- gda_data_model_reset (GDA_DATA_MODEL (model));
- }
-}
-
static GdaColumn *
gda_data_model_query_describe_column (GdaDataModel *model, gint col)
{
GdaDataModelQuery *selmodel;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), NULL);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, NULL);
- if (!selmodel->priv->data && !selmodel->priv->refresh_error) {
- if (!gda_data_model_query_refresh (selmodel, NULL))
- return NULL;
- }
-
- create_columns (selmodel);
- if (selmodel->priv->columns)
- return g_slist_nth_data (selmodel->priv->columns, col);
- else
+ if (!selmodel->priv->data)
return NULL;
+ else
+ return gda_data_model_describe_column (selmodel->priv->data, col);
}
static GdaDataModelAccessFlags
gda_data_model_query_get_access_flags (GdaDataModel *model)
{
GdaDataModelQuery *selmodel;
- GdaDataModelAccessFlags flags = GDA_DATA_MODEL_ACCESS_RANDOM;
-
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), 0);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, 0);
- if (!selmodel->priv->data && !selmodel->priv->refresh_error)
- gda_data_model_query_refresh (selmodel, NULL);
-
- if (selmodel->priv->data) {
- gint i;
- for (i = INS_QUERY; i <= DEL_QUERY; i++) {
- gboolean allok = TRUE;
-
- if (selmodel->priv->params [i]) {
- /* if all the parameters which are not named _[0-9]* are valid,
- * then we grant the corresponding flag */
- GSList *params;
- for (params = selmodel->priv->params [i]->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "_num")) - 1;
- if (num < 0)
- allok = gda_holder_is_valid ((GdaHolder*)(params->data));
- if (!allok) {
- break;
- g_print ("Not OK:\n");
- }
- }
-
- }
- else {
- if (!selmodel->priv->statements [i])
- allok = FALSE;
- }
-
- if (allok && selmodel->priv->params [i]) {
- switch (i) {
- case INS_QUERY:
- flags |= GDA_DATA_MODEL_ACCESS_INSERT;
- /* g_print ("INS flag\n"); */
- break;
- case UPD_QUERY:
- flags |= GDA_DATA_MODEL_ACCESS_UPDATE;
- /* g_print ("UPD flag\n"); */
- break;
- case DEL_QUERY:
- flags |= GDA_DATA_MODEL_ACCESS_DELETE;
- /* g_print ("DEL flag\n"); */
- break;
- default:
- g_assert_not_reached ();
- }
- }
- }
- }
-
- return flags;
+ if (!selmodel->priv->data)
+ return 0;
+ else
+ return gda_data_model_get_access_flags (selmodel->priv->data);
}
static const GValue *
@@ -936,112 +776,33 @@
{
GdaDataModelQuery *selmodel;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), NULL);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, NULL);
- if (!selmodel->priv->data && !selmodel->priv->refresh_error)
- gda_data_model_query_refresh (selmodel, NULL);
-
- if (selmodel->priv->data)
- return gda_data_model_get_value_at (selmodel->priv->data, col, row, error);
- else {
- g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ROW_NOT_FOUND_ERROR,
- _("Data model has no data"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return NULL;
}
+ else
+ return gda_data_model_get_value_at (selmodel->priv->data, col, row, error);
}
static GdaValueAttribute
gda_data_model_query_get_attributes_at (GdaDataModel *model, gint col, gint row)
{
- GdaValueAttribute flags = 0;
GdaDataModelQuery *selmodel;
- GdaHolder *p_used = NULL;
-
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), 0);
selmodel = (GdaDataModelQuery *) model;
g_return_val_if_fail (selmodel->priv, 0);
- if (selmodel->priv->data)
- flags = gda_data_model_get_attributes_at (selmodel->priv->data, col, row);
-
- if ((row >= 0) && selmodel->priv->statements[UPD_QUERY] && selmodel->priv->params[UPD_QUERY]) {
- GSList *params;
- for (params = selmodel->priv->params[UPD_QUERY]->holders; params; params = params->next) {
- if (GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1 == col) {
- p_used = (GdaHolder *) params->data;
- break;
- }
- }
- }
-
- if ((row < 0) && selmodel->priv->statements[INS_QUERY] && selmodel->priv->params[INS_QUERY]) {
- GSList *params;
- for (params = selmodel->priv->params[INS_QUERY]->holders; params; params = params->next) {
- if (GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1 == col) {
- p_used = (GdaHolder *) params->data;
- break;
- }
- }
- }
-
- if (!p_used)
- flags |= GDA_VALUE_ATTR_NO_MODIF;
- else {
- flags &= ~GDA_VALUE_ATTR_NO_MODIF;
- flags &= ~GDA_VALUE_ATTR_CAN_BE_NULL;
- flags &= ~GDA_VALUE_ATTR_CAN_BE_DEFAULT;
- if (! gda_holder_get_not_null (p_used))
- flags |= GDA_VALUE_ATTR_CAN_BE_NULL;
- if (gda_holder_get_default_value (p_used))
- flags |= GDA_VALUE_ATTR_CAN_BE_DEFAULT;
- }
-
- /*g_print ("%d,%d: %d\n", col, row, flags);*/
-
- return flags;
-}
-
-static GdaDataModelIter *
-gda_data_model_query_create_iter (GdaDataModel *model)
-{
- GdaDataModelIter *iter;
-
- iter = (GdaDataModelIter *) g_object_new (GDA_TYPE_DATA_MODEL_ITER,
- "data_model", model, NULL);
- /* set the "__gda_entry_plugin" property for all the parameters depending on the SELECT query field */
- static gboolean warned = FALSE;
- if (!warned) {
- warned = TRUE;
- TO_IMPLEMENT;
- }
- /*
- if (gda_query_is_select_query (GDA_DATA_MODEL_QUERY (model)->priv->statements[SEL_QUERY])) {
- GSList *list, *fields;
- GSList *params;
-
- fields = gda_entity_get_fields (GDA_ENTITY (GDA_DATA_MODEL_QUERY (model)->priv->statements[SEL_QUERY]));
- params = GDA_SET (iter)->holders;
-
- for (list = fields; list && params; list = list->next, params = params->next) {
- GdaEntityField *field = (GdaEntityField *) list->data;
- if (GDA_IS_QUERY_FIELD_FIELD (field)) {
- gchar *plugin;
-
- g_object_get (G_OBJECT (field), "__gda_entry_plugin", &plugin, NULL);
- if (plugin) {
- g_object_set (G_OBJECT (params->data), "__gda_entry_plugin", plugin, NULL);
- g_free (plugin);
- }
- }
- }
- g_slist_free (fields);
- }
- */
-
- return iter;
+ if (!selmodel->priv->data)
+ return 0;
+ else
+ return gda_data_model_get_attributes_at (selmodel->priv->data, col, row);
}
+
static gchar *try_add_savepoint (GdaDataModelQuery *selmodel);
static void try_remove_savepoint (GdaDataModelQuery *selmodel, const gchar *svp_name);
@@ -1073,302 +834,79 @@
gda_connection_delete_savepoint (selmodel->priv->cnc, svp_name, NULL);
}
-static gboolean
-run_modify_query (GdaDataModelQuery *selmodel, gint query_type, GError **error)
-{
- gboolean modify_done = FALSE;
- gchar *svp_name = NULL;
-
- /* try to add a savepoint if we are not doing multiple updates */
- if (!selmodel->priv->multiple_updates)
- svp_name = try_add_savepoint (selmodel);
-
- if (! selmodel->priv->cnc) {
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
- _("No connection specified"));
- return FALSE;
- }
- if (! gda_connection_is_opened (selmodel->priv->cnc)) {
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR, GDA_DATA_MODEL_QUERY_CONNECTION_ERROR,
- _("Specified connection is closed"));
- return FALSE;
- }
-
- if (gda_connection_statement_execute_non_select (selmodel->priv->cnc,
- selmodel->priv->statements[query_type],
- selmodel->priv->params [query_type], NULL, error) != -1)
- modify_done = TRUE;
-
- if (modify_done) {
- /* modif query executed without error */
- if (!selmodel->priv->multiple_updates)
- gda_data_model_query_refresh (selmodel, NULL);
- else
- selmodel->priv->needs_refresh = TRUE;
- }
- else {
- /* modif query did not execute correctly */
- if (!selmodel->priv->multiple_updates)
- /* nothing to do */;
- else
- selmodel->priv->transaction_needs_commit = FALSE;
- }
-
- /* try to remove the savepoint added above */
- if (svp_name) {
- try_remove_savepoint (selmodel, svp_name);
- g_free (svp_name);
- }
-
-#ifdef REMOVE
- if (modify_done && !selmodel->priv->multiple_updates)
- /* modifications were successfull => refresh needed */
- gda_data_model_query_refresh (selmodel, NULL);
- else
- /* the refresh is delayed */
- selmodel->priv->needs_refresh = TRUE;
-#endif
-
- return modify_done;
-}
static gboolean
gda_data_model_query_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *value, GError **error)
{
GdaDataModelQuery *selmodel;
- GdaSet *paramlist;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, FALSE);
/* make sure there is a UPDATE query */
- if (!selmodel->priv->statements[UPD_QUERY]) {
- g_set_error (error, 0, 0,
- _("No UPDATE query specified, can't update row"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return FALSE;
}
-
- /* set the values of the parameters in the paramlist if necessary */
- paramlist = selmodel->priv->params[UPD_QUERY];
- if (paramlist && paramlist->holders) {
- GSList *params;
- for (params = paramlist->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1;
- if (num >= 0) {
- /* new values */
- if (num == col) {
- if (!gda_holder_set_value (GDA_HOLDER (params->data), value, error))
- return FALSE;
- }
- else {
- if (! gda_holder_set_value (GDA_HOLDER (params->data), NULL, error))
- return FALSE;
- }
- }
- else {
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "-num")) - 1;
- if (num >= 0) {
- /* old values */
- const GValue *cvalue;
- cvalue = gda_data_model_get_value_at ((GdaDataModel*) selmodel, num, row, error);
- if (!cvalue || gda_holder_set_value (GDA_HOLDER (params->data), cvalue, error))
- return FALSE;
- }
- }
- }
- }
-
- /* render the SQL and run it */
- return run_modify_query (selmodel, UPD_QUERY, error);
+ else
+ return gda_data_model_set_value_at (selmodel->priv->data, col, row, value, error);
}
static gboolean
gda_data_model_query_set_values (GdaDataModel *model, gint row, GList *values, GError **error)
{
GdaDataModelQuery *selmodel;
- GdaSet *paramlist;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, FALSE);
- /* make sure there is a UPDATE query */
- if (!selmodel->priv->statements[UPD_QUERY]) {
- g_set_error (error, 0, 0,
- _("No UPDATE query specified, can't update row"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return FALSE;
}
-
- /* set the values of the parameters in the paramlist if necessary */
- paramlist = selmodel->priv->params[UPD_QUERY];
- if (paramlist && paramlist->holders) {
- GSList *params;
- for (params = paramlist->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1;
- if (num >= 0) {
- /* new values */
- GValue *value;
- value = g_list_nth_data ((GList *) values, num);
- if (value) {
- if (!gda_holder_set_value (GDA_HOLDER (params->data), value, error))
- return FALSE;
- }
- else {
- if (! gda_holder_set_value (GDA_HOLDER (params->data), NULL, error))
- return FALSE;
- }
- }
- else {
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "-num")) - 1;
- if (num >= 0) {
- /* old values */
- const GValue *cvalue;
- cvalue = gda_data_model_get_value_at ((GdaDataModel*) selmodel, num, row, error);
- if (!cvalue || gda_holder_set_value (GDA_HOLDER (params->data), cvalue, error))
- return FALSE;
- }
- }
- }
- }
-
- /* render the SQL and run it */
- return run_modify_query (selmodel, UPD_QUERY, error);
+ else
+ return gda_data_model_set_values (selmodel->priv->data, row, values, error);
}
static gint
gda_data_model_query_append_values (GdaDataModel *model, const GList *values, GError **error)
{
GdaDataModelQuery *selmodel;
- GdaSet *paramlist;
- gboolean retval;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), -1);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, -1);
- /* make sure there is a INSERT query */
- if (!selmodel->priv->statements[INS_QUERY]) {
- g_set_error (error, 0, 0,
- _("No INSERT query specified, can't insert row"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return -1;
}
-
- /* set the values of the parameters in the paramlist if necessary */
- paramlist = selmodel->priv->params[INS_QUERY];
- if (paramlist && paramlist->holders) {
- GSList *params;
- for (params = paramlist->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1;
- if (num >= 0) {
- /* new values only */
- GValue *value;
- value = g_list_nth_data ((GList *) values, num);
- if (value) {
- if (! gda_holder_set_value (GDA_HOLDER (params->data), value, error))
- return -1;
- }
- else
- g_object_set (G_OBJECT (params->data), "use-default-value", TRUE, NULL);
- }
- }
- }
-
- /* render the SQL and run it */
- retval = run_modify_query (selmodel, INS_QUERY, error);
-
- if (retval)
- return 0;
else
- return -1;
+ return gda_data_model_append_values (selmodel->priv->data, values, error);
}
-static gint
-gda_data_model_query_append_row (GdaDataModel *model, GError **error)
-{
- GdaDataModelQuery *selmodel;
- GdaSet *paramlist;
- gboolean retval;
-
- g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), -1);
- selmodel = GDA_DATA_MODEL_QUERY (model);
- g_return_val_if_fail (selmodel->priv, -1);
-
- /* make sure there is a INSERT query */
- if (!selmodel->priv->statements[INS_QUERY]) {
- g_set_error (error, 0, 0,
- _("No INSERT query specified, can't insert row"));
- return -1;
- }
-
- /* set the values of the parameters in the paramlist if necessary */
- paramlist = selmodel->priv->params[INS_QUERY];
- if (paramlist && paramlist->holders) {
- GSList *params;
- for (params = paramlist->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "+num")) - 1;
-
- if (num >= 0)
- /* new values only */
- if (! gda_holder_set_value (GDA_HOLDER (params->data), NULL, error))
- return -1;
- }
- }
-
- /* render the SQL and run it */
- retval = run_modify_query (selmodel, INS_QUERY, error);
-
- if (retval)
- return 0;
- else
- return -1;
-}
static gboolean
gda_data_model_query_remove_row (GdaDataModel *model, gint row, GError **error)
{
GdaDataModelQuery *selmodel;
- GdaSet *paramlist;
g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_val_if_fail (selmodel->priv, FALSE);
- /* make sure there is a REMOVE query */
- if (!selmodel->priv->statements[DEL_QUERY]) {
- g_set_error (error, 0, 0,
- _("No DELETE query specified, can't delete row"));
+ if (!selmodel->priv->data) {
+ g_assert (selmodel->priv->exec_error);
+ g_propagate_error (error, g_error_copy (selmodel->priv->exec_error));
return FALSE;
}
-
- /* set the values of the parameters in the paramlist if necessary */
- paramlist = selmodel->priv->params[DEL_QUERY];
- if (paramlist && paramlist->holders) {
- GSList *params;
- for (params = paramlist->holders; params; params = params->next) {
- gint num;
-
- num = GPOINTER_TO_INT (g_object_get_data ((GObject*) params->data, "-num")) - 1;
- if (num >= 0) {
- /* old values only */
- const GValue *cvalue;
- cvalue = gda_data_model_get_value_at ((GdaDataModel*) selmodel, num, row, error);
- if (!cvalue || gda_holder_set_value (GDA_HOLDER (params->data), cvalue, error))
- return FALSE;
- }
- }
- }
-
- /* render the SQL and run it */
- return run_modify_query (selmodel, DEL_QUERY, error);
+ else
+ return gda_data_model_remove_row (selmodel->priv->data, row, error);
}
static void
@@ -1421,127 +959,62 @@
g_print ("GdaDataModelQuery %p: added savepoint %s\n", selmodel, selmodel->priv->svp_name);
}
-static void
-opt_end_transaction_or_svp (GdaDataModelQuery *selmodel)
+static gboolean
+opt_end_transaction_or_svp (GdaDataModelQuery *selmodel, GError **error)
{
GdaConnection *cnc;
if (!selmodel->priv->transaction_started && !selmodel->priv->svp_name)
- return;
+ return TRUE;
- g_print ("GdaDataModelQuery %p (END1): %s\n", selmodel, selmodel->priv->needs_refresh ? "needs refresh" : "no refresh");
cnc = selmodel->priv->cnc;
if (selmodel->priv->transaction_started) {
g_assert (!selmodel->priv->svp_name);
if (selmodel->priv->transaction_needs_commit) {
/* try to commit transaction */
- if (!gda_connection_commit_transaction (cnc, NULL, NULL))
- selmodel->priv->needs_refresh = TRUE;
+ if (!gda_connection_commit_transaction (cnc, NULL, error))
+ return FALSE;
}
else {
/* rollback transaction */
- selmodel->priv->needs_refresh = gda_connection_rollback_transaction (cnc, NULL, NULL) ? FALSE : TRUE;
+ if (! gda_connection_rollback_transaction (cnc, NULL, error))
+ return FALSE;
}
selmodel->priv->transaction_started = FALSE;
+ return TRUE;
}
else {
if (!selmodel->priv->transaction_needs_commit) {
- selmodel->priv->needs_refresh = gda_connection_rollback_savepoint (cnc, selmodel->priv->svp_name, NULL) ?
- FALSE : TRUE;
+ if (!gda_connection_rollback_savepoint (cnc, selmodel->priv->svp_name, error))
+ return FALSE;
}
else
if (gda_connection_supports_feature (cnc, GDA_CONNECTION_FEATURE_SAVEPOINTS_REMOVE))
- if (!gda_connection_delete_savepoint (cnc, selmodel->priv->svp_name, NULL))
- selmodel->priv->needs_refresh = TRUE;
+ if (!gda_connection_delete_savepoint (cnc, selmodel->priv->svp_name, error))
+ return FALSE;
g_free (selmodel->priv->svp_name);
selmodel->priv->svp_name = NULL;
+ return TRUE;
}
- g_print ("GdaDataModelQuery %p (END2): %s\n", selmodel, selmodel->priv->needs_refresh ? "needs refresh" : "no refresh");
}
-
-
static void
gda_data_model_query_send_hint (GdaDataModel *model, GdaDataModelHint hint, const GValue *hint_value)
{
GdaDataModelQuery *selmodel;
g_return_if_fail (GDA_IS_DATA_MODEL_QUERY (model));
- selmodel = GDA_DATA_MODEL_QUERY (model);
+ selmodel = (GdaDataModelQuery*) model;
g_return_if_fail (selmodel->priv);
if (hint == GDA_DATA_MODEL_HINT_REFRESH)
gda_data_model_query_refresh (selmodel, NULL);
else {
- if (hint == GDA_DATA_MODEL_HINT_START_BATCH_UPDATE) {
+ if (hint == GDA_DATA_MODEL_HINT_START_BATCH_UPDATE)
opt_start_transaction_or_svp (selmodel);
- selmodel->priv->multiple_updates = TRUE;
- }
else {
- if (hint == GDA_DATA_MODEL_HINT_END_BATCH_UPDATE) {
- selmodel->priv->multiple_updates = FALSE;
- opt_end_transaction_or_svp (selmodel);
-
- if (selmodel->priv->needs_refresh)
- gda_data_model_query_refresh (selmodel, NULL);
- }
+ if (hint == GDA_DATA_MODEL_HINT_END_BATCH_UPDATE)
+ opt_end_transaction_or_svp (selmodel, NULL);
}
}
}
-/*
- * Computation of INSERT, DELETE and UPDATE statements
- */
-/**
- * gda_data_model_query_compute_modification_queries
- * @model: a GdaDataModelQuery object
- * @target: the target table to modify, or %NULL
- * @options: options to specify how the statements must be built in some special cases
- * @error: a place to store errors or %NULL
- *
- * Try to compute the INSERT, DELETE and UPDATE statements; any previous modification query
- * will be discarded.
- *
- * If specified, the table which will be updated is the one represented by the @target.
- *
- * If @target is %NULL, then an error will be returned if @model's SELECT query has more than
- * one target.
- *
- * Returns: TRUE at least one of the INSERT, DELETE and UPDATE statements has been computed
- */
-gboolean
-gda_data_model_query_compute_modification_queries (GdaDataModelQuery *model, const gchar *target,
- GdaDataModelQueryOptions options, GError **error)
-{
- gint i;
- gboolean require_pk = TRUE;
- GdaStatement *ins, *upd, *del;
- g_return_val_if_fail (GDA_IS_DATA_MODEL_QUERY (model), FALSE);
- g_return_val_if_fail (model->priv, FALSE);
-
- if (!model->priv->statements[SEL_QUERY]) {
- g_set_error (error, GDA_DATA_MODEL_QUERY_ERROR,
- GDA_DATA_MODEL_QUERY_COMPUTE_MODIF_STATEMENTS_ERROR,
- _("No SELECT query specified"));
- return FALSE;
- }
-
- for (i = SEL_QUERY + 1; i <= DEL_QUERY; i++) {
- if (model->priv->statements[i])
- forget_statement (model, model->priv->statements[i]);
- }
-
- if (options & GDA_DATA_MODEL_QUERY_OPTION_USE_ALL_FIELDS_IF_NO_PK)
- require_pk = FALSE;
- if (gda_compute_dml_statements (model->priv->cnc, model->priv->statements[SEL_QUERY], require_pk,
- &ins, &upd, &del, error)) {
-
- g_object_set (G_OBJECT (model), "insert_query", ins,
- "update-query", upd, "delete-query", del, NULL);
- if (ins) g_object_unref (ins);
- if (upd) g_object_unref (upd);
- if (del) g_object_unref (del);
- return TRUE;
- }
-
- return FALSE;
-}
Modified: trunk/libgda/gda-data-model-query.h
==============================================================================
--- trunk/libgda/gda-data-model-query.h (original)
+++ trunk/libgda/gda-data-model-query.h Sun Sep 7 19:06:38 2008
@@ -25,6 +25,7 @@
#include <libgda/gda-data-model.h>
#include <libgda/gda-connection.h>
+#include <sql-parser/gda-sql-statement.h>
G_BEGIN_DECLS
@@ -43,16 +44,10 @@
#define GDA_DATA_MODEL_QUERY_ERROR gda_data_model_query_error_quark ()
typedef enum {
- GDA_DATA_MODEL_QUERY_XML_LOAD_ERROR,
- GDA_DATA_MODEL_QUERY_COMPUTE_MODIF_STATEMENTS_ERROR,
- GDA_DATA_MODEL_QUERY_MODIF_STATEMENT_ERROR,
+ GDA_DATA_MODEL_QUERY_SELECT_STATEMENT_ERROR,
GDA_DATA_MODEL_QUERY_CONNECTION_ERROR
} GdaDataModelQueryError;
-typedef enum {
- GDA_DATA_MODEL_QUERY_OPTION_USE_ALL_FIELDS_IF_NO_PK = 1 << 0
-} GdaDataModelQueryOptions;
-
struct _GdaDataModelQuery {
GObject object;
GdaDataModelQueryPrivate *priv;
@@ -62,16 +57,17 @@
GObjectClass parent_class;
};
-GType gda_data_model_query_get_type (void) G_GNUC_CONST;
-GdaDataModel *gda_data_model_query_new (GdaConnection *cnc, GdaStatement *select_stmt);
-
-GdaSet *gda_data_model_query_get_parameter_list (GdaDataModelQuery *model);
-gboolean gda_data_model_query_refresh (GdaDataModelQuery *model, GError **error);
-gboolean gda_data_model_query_set_modification_query (GdaDataModelQuery *model,
- GdaStatement *mod_stmt, GError **error);
-gboolean gda_data_model_query_compute_modification_queries (GdaDataModelQuery *model, const gchar *target,
- GdaDataModelQueryOptions options, GError **error);
-
+GType gda_data_model_query_get_type (void) G_GNUC_CONST;
+GdaDataModelQuery *gda_data_model_query_new (GdaConnection *cnc, GdaStatement *select_stmt, GdaSet *params);
+gboolean gda_data_model_query_refresh (GdaDataModelQuery *model, GError **error);
+
+gboolean gda_data_model_query_set_row_selection_condition (GdaDataModelQuery *model, GdaSqlExpr *expr, GError **error);
+gboolean gda_data_model_query_set_row_selection_condition_sql (GdaDataModelQuery *model, const gchar *sql_where, GError **error);
+gboolean gda_data_model_query_compute_row_selection_condition (GdaDataModelQuery *model, GError **error);
+
+gboolean gda_data_model_query_set_modification_statement (GdaDataModelQuery *model, GdaStatement *mod_stmt, GError **error);
+gboolean gda_data_model_query_set_modification_statement_sql (GdaDataModelQuery *model, const gchar *sql, GError **error);
+gboolean gda_data_model_query_compute_modification_statements (GdaDataModelQuery *model, GError **error);
G_END_DECLS
Modified: trunk/libgda/gda-data-model.c
==============================================================================
--- trunk/libgda/gda-data-model.c (original)
+++ trunk/libgda/gda-data-model.c Sun Sep 7 19:06:38 2008
@@ -812,8 +812,11 @@
return FALSE;
/* validity tests */
- if (row >= gda_data_model_get_n_rows (model))
- goto onerror;
+ if ((row < 0) || (row >= gda_data_model_get_n_rows (model))) {
+ gda_data_model_iter_invalidate_contents (iter);
+ g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
+ return FALSE;
+ }
g_return_val_if_fail (GDA_IS_DATA_MODEL_ITER (iter), FALSE);
@@ -827,18 +830,18 @@
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);
- if (!cvalue || !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL))
- goto onerror;
+ if (!cvalue ||
+ !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL)) {
+ g_object_set (G_OBJECT (iter), "current_row", row,
+ "update_model", update_model, NULL);
+ gda_data_model_iter_invalidate_contents (iter);
+ return FALSE;
+ }
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 TRUE;
-
- onerror:
- gda_data_model_iter_invalidate_contents (iter);
- g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
- return FALSE;
}
static void
@@ -900,8 +903,11 @@
g_object_get (G_OBJECT (iter), "current_row", &row, NULL);
row++;
- if (row >= gda_data_model_get_n_rows (model))
- goto onerror;
+ if (row >= gda_data_model_get_n_rows (model)) {
+ gda_data_model_iter_invalidate_contents (iter);
+ g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
+ return FALSE;
+ }
/* actual sync. */
g_object_get (G_OBJECT (iter), "update_model", &update_model, NULL);
@@ -909,19 +915,19 @@
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);
- if (!cvalue || !gda_holder_set_value ((GdaHolder *) list->data, cvalue, NULL))
- goto onerror;
+ if (!cvalue ||
+ !gda_holder_set_value ((GdaHolder *) list->data, cvalue, NULL)) {
+ g_object_set (G_OBJECT (iter), "current_row", row,
+ "update_model", update_model, NULL);
+ gda_data_model_iter_invalidate_contents (iter);
+ return FALSE;
+ }
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 TRUE;
-
- onerror:
- gda_data_model_iter_invalidate_contents (iter);
- g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
- return FALSE;
}
/**
@@ -970,8 +976,11 @@
g_object_get (G_OBJECT (iter), "current_row", &row, NULL);
row--;
- if (row < 0)
- goto onerror;
+ if (row < 0) {
+ gda_data_model_iter_invalidate_contents (iter);
+ g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
+ return FALSE;
+ }
/* actual sync. */
g_object_get (G_OBJECT (iter), "update_model", &update_model, NULL);
@@ -979,19 +988,19 @@
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);
- if (!cvalue || !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL))
- goto onerror;
+ if (!cvalue ||
+ !gda_holder_set_value ((GdaHolder*) list->data, cvalue, NULL)) {
+ g_object_set (G_OBJECT (iter), "current_row", row,
+ "update_model", update_model, NULL);
+ gda_data_model_iter_invalidate_contents (iter);
+ return FALSE;
+ }
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 TRUE;
-
- onerror:
- gda_data_model_iter_invalidate_contents (iter);
- g_object_set (G_OBJECT (iter), "current_row", -1, NULL);
- return FALSE;
}
@@ -1906,7 +1915,14 @@
to_nb_rows = gda_data_model_get_n_rows (to);
}
- gda_data_model_iter_move_next (from_iter); /* move to first row */
+ gboolean mstatus;
+ mstatus = gda_data_model_iter_move_next (from_iter); /* move to first row */
+ if (!mstatus) {
+ gint crow;
+ g_object_get (from_iter, "current-row", &crow, NULL);
+ if (crow >= 0)
+ retval = FALSE;
+ }
while (retval && gda_data_model_iter_is_valid (from_iter)) {
GList *values = NULL;
GList *avlist = append_values;
@@ -1965,7 +1981,13 @@
}
g_list_free (values);
- gda_data_model_iter_move_next (from_iter);
+ mstatus = gda_data_model_iter_move_next (from_iter);
+ if (!mstatus) {
+ gint crow;
+ g_object_get (from_iter, "current-row", &crow, NULL);
+ if (crow >= 0)
+ retval = FALSE;
+ }
}
/* free memory */
Added: trunk/libgda/gda-data-select-extra.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-data-select-extra.h Sun Sep 7 19:06:38 2008
@@ -0,0 +1,63 @@
+/* GDA common library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_DATA_SELECT_EXTRA_H__
+#define __GDA_DATA_SELECT_EXTRA_H__
+
+#include <glib-object.h>
+#include <libgda/gda-row.h>
+#include <libgda/providers-support/gda-pstmt.h>
+#include <sql-parser/gda-sql-statement.h>
+#include <libgda/gda-data-select.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ FIRST_QUERY = 0,
+ INS_QUERY = 0,
+ UPD_QUERY = 1,
+ DEL_QUERY = 2,
+ NB_QUERIES = 3
+} ModType;
+
+typedef struct {
+ gboolean safely_locked;
+ GdaSqlExpr *unique_row_condition;
+ gint *insert_to_select_mapping; /* see compute_insert_select_params_mapping() */
+
+ GdaSet *exec_set; /* owned by this object (copied) */
+ GdaSet *modif_set; /* owned by this object */
+ GdaStatement *modif_stmts[NB_QUERIES];
+ GHashTable *upd_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an UPDATE GdaStatement */
+ GHashTable *ins_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an INSERT GdaStatement */
+ GdaStatement *one_row_select_stmt; /* used to retreive one row after an UPDATE
+ * or INSERT operation */
+} GdaDataSelectInternals;
+
+GdaDataSelectInternals *_gda_data_select_internals_steal (GdaDataSelect *model);
+void _gda_data_select_internals_paste (GdaDataSelect *model, GdaDataSelectInternals *inter);
+void _gda_data_select_internals_free (GdaDataSelectInternals *inter);
+
+G_END_DECLS
+
+#endif
Modified: trunk/libgda/gda-data-select.c
==============================================================================
--- trunk/libgda/gda-data-select.c (original)
+++ trunk/libgda/gda-data-select.c Sun Sep 7 19:06:38 2008
@@ -27,6 +27,7 @@
#include <string.h>
#include "gda-data-select.h"
#include "providers-support/gda-data-select-priv.h"
+#include "gda-data-select-extra.h"
#include "gda-row.h"
#include "providers-support/gda-pstmt.h"
#include <libgda/gda-statement.h>
@@ -37,15 +38,6 @@
#define CLASS(x) (GDA_DATA_SELECT_CLASS (G_OBJECT_GET_CLASS (x)))
-typedef enum
-{
- FIRST_QUERY = 0,
- INS_QUERY = 0,
- UPD_QUERY = 1,
- DEL_QUERY = 2,
- NB_QUERIES = 3
-} ModType;
-
typedef struct {
GdaStatement *select;
GdaSet *params;
@@ -82,16 +74,7 @@
GdaDataModelAccessFlags usage_flags;
/* attributes specific to data model modifications */
- GdaSqlExpr *unique_row_condition;
- gint *insert_to_select_mapping; /* see compute_insert_select_params_mapping() */
-
- GdaSet *exec_set; /* owned by this object (copied) */
- GdaSet *modif_set; /* owned by this object */
- GdaStatement *modif_stmts[NB_QUERIES];
- GHashTable *upd_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an UPDATE GdaStatement */
- GHashTable *ins_stmts; /* key = a gboolean vector with TRUEs when the column is used, value = an INSERT GdaStatement */
- GdaStatement *one_row_select_stmt; /* used to retreive one row after an UPDATE
- * or INSERT operation */
+ GdaDataSelectInternals *modif_internals;
/* Global overriding data when the data model has been modified */
GArray *del_rows; /* array[index] = number of the index'th deleted row,
@@ -139,7 +122,7 @@
/* utility functions */
typedef struct {
gint size; /* number of elements in the @data array */
- guchar *data; /* data[0] tp data[ size-1] are valid */
+ guchar *data; /* data[0] to data[ size-1] are valid */
} BVector;
static GdaStatement *check_acceptable_statement (GdaDataSelect *model, GError **error);
static GdaStatement *compute_single_update_stmt (GdaDataSelect *model, BVector *bv, GError **error);
@@ -296,6 +279,7 @@
static void
gda_data_select_init (GdaDataSelect *model, GdaDataSelectClass *klass)
{
+ ModType i;
g_return_if_fail (GDA_IS_DATA_SELECT (model));
model->priv = g_new0 (GdaDataSelectPrivate, 1);
model->priv->cnc = NULL;
@@ -308,13 +292,17 @@
model->priv->iter_row = G_MININT;
model->priv->iter = NULL;
- model->priv->unique_row_condition = NULL;
- model->priv->insert_to_select_mapping = NULL;
- model->priv->modif_set = NULL;
- model->priv->exec_set = NULL;
- model->priv->upd_stmts = NULL;
- model->priv->ins_stmts = NULL;
- model->priv->one_row_select_stmt = NULL;
+ model->priv->modif_internals = g_new0 (GdaDataSelectInternals, 1);
+ model->priv->modif_internals->safely_locked = FALSE;
+ model->priv->modif_internals->unique_row_condition = NULL;
+ model->priv->modif_internals->insert_to_select_mapping = NULL;
+ model->priv->modif_internals->modif_set = NULL;
+ model->priv->modif_internals->exec_set = NULL;
+ for (i = FIRST_QUERY; i < NB_QUERIES; i++)
+ model->priv->modif_internals->modif_stmts[i] = NULL;
+ model->priv->modif_internals->upd_stmts = NULL;
+ model->priv->modif_internals->ins_stmts = NULL;
+ model->priv->modif_internals->one_row_select_stmt = NULL;
model->priv->upd_rows = NULL;
model->priv->del_rows = NULL;
@@ -331,14 +319,9 @@
if (model->priv) {
gint i;
- if (model->priv->unique_row_condition) {
- gda_sql_expr_free (model->priv->unique_row_condition);
- model->priv->unique_row_condition = NULL;
- }
-
- if (model->priv->insert_to_select_mapping) {
- g_free (model->priv->insert_to_select_mapping);
- model->priv->insert_to_select_mapping = NULL;
+ if (model->priv->modif_internals) {
+ _gda_data_select_internals_free (model->priv->modif_internals);
+ model->priv->modif_internals = NULL;
}
if (model->priv->upd_rows) {
@@ -356,15 +339,11 @@
model->priv->cnc = NULL;
}
- if (model->priv->one_row_select_stmt) {
- g_object_unref (model->priv->one_row_select_stmt);
- model->priv->one_row_select_stmt = NULL;
- }
-
if (model->prep_stmt) {
g_object_unref (model->prep_stmt);
model->prep_stmt = NULL;
}
+
if (model->priv->rows) {
for (i = 0; i < model->priv->rows->len; i++) {
GdaRow *prow;
@@ -383,35 +362,58 @@
g_slist_free (model->priv->columns);
model->priv->columns = NULL;
}
+ }
- if (model->priv->modif_set) {
- g_object_unref (model->priv->modif_set);
- model->priv->modif_set = NULL;
- }
+ /* chain to parent class */
+ parent_class->dispose (object);
+}
- if (model->priv->exec_set) {
- g_object_unref (model->priv->exec_set);
- model->priv->exec_set = NULL;
- }
+void
+_gda_data_select_internals_free (GdaDataSelectInternals *inter)
+{
+ ModType i;
- for (i = FIRST_QUERY; i < NB_QUERIES; i++) {
- if (model->priv->modif_stmts [i]) {
- g_object_unref (model->priv->modif_stmts [i]);
- model->priv->modif_stmts [i] = NULL;
- }
- }
- if (model->priv->upd_stmts) {
- g_hash_table_destroy (model->priv->upd_stmts);
- model->priv->upd_stmts = NULL;
- }
- if (model->priv->ins_stmts) {
- g_hash_table_destroy (model->priv->ins_stmts);
- model->priv->ins_stmts = NULL;
+ if (inter->unique_row_condition) {
+ gda_sql_expr_free (inter->unique_row_condition);
+ inter->unique_row_condition = NULL;
+ }
+
+ if (inter->insert_to_select_mapping) {
+ g_free (inter->insert_to_select_mapping);
+ inter->insert_to_select_mapping = NULL;
+ }
+
+ if (inter->modif_set) {
+ g_object_unref (inter->modif_set);
+ inter->modif_set = NULL;
+ }
+
+ if (inter->exec_set) {
+ g_object_unref (inter->exec_set);
+ inter->exec_set = NULL;
+ }
+
+ for (i = FIRST_QUERY; i < NB_QUERIES; i++) {
+ if (inter->modif_stmts [i]) {
+ g_object_unref (inter->modif_stmts [i]);
+ inter->modif_stmts [i] = NULL;
}
}
+ if (inter->upd_stmts) {
+ g_hash_table_destroy (inter->upd_stmts);
+ inter->upd_stmts = NULL;
+ }
+ if (inter->ins_stmts) {
+ g_hash_table_destroy (inter->ins_stmts);
+ inter->ins_stmts = NULL;
+ }
- /* chain to parent class */
- parent_class->dispose (object);
+ if (inter->one_row_select_stmt) {
+ g_object_unref (inter->one_row_select_stmt);
+ inter->one_row_select_stmt = NULL;
+ }
+
+ g_free (inter);
}
static void
@@ -431,6 +433,24 @@
parent_class->finalize (object);
}
+GdaDataSelectInternals *
+_gda_data_select_internals_steal (GdaDataSelect *model)
+{
+ GdaDataSelectInternals *inter;
+ inter = model->priv->modif_internals;
+ model->priv->modif_internals = NULL;
+
+ return inter;
+}
+
+void
+_gda_data_select_internals_paste (GdaDataSelect *model, GdaDataSelectInternals *inter)
+{
+ if (model->priv->modif_internals)
+ _gda_data_select_internals_free (model->priv->modif_internals);
+ model->priv->modif_internals = inter;
+}
+
static void
create_columns (GdaDataSelect *model)
{
@@ -509,29 +529,29 @@
GdaSet *set;
set = g_value_get_object (value);
if (set)
- model->priv->exec_set = gda_set_copy (set);
+ model->priv->modif_internals->exec_set = gda_set_copy (set);
break;
}
case PROP_INS_QUERY:
- if (model->priv->modif_stmts [INS_QUERY])
- g_object_unref (model->priv->modif_stmts [INS_QUERY]);
- model->priv->modif_stmts [INS_QUERY] = g_value_get_object (value);
- if (model->priv->modif_stmts [INS_QUERY])
- g_object_ref (model->priv->modif_stmts [INS_QUERY]);
+ if (model->priv->modif_internals->modif_stmts [INS_QUERY])
+ g_object_unref (model->priv->modif_internals->modif_stmts [INS_QUERY]);
+ model->priv->modif_internals->modif_stmts [INS_QUERY] = g_value_get_object (value);
+ if (model->priv->modif_internals->modif_stmts [INS_QUERY])
+ g_object_ref (model->priv->modif_internals->modif_stmts [INS_QUERY]);
break;
case PROP_DEL_QUERY:
- if (model->priv->modif_stmts [DEL_QUERY])
- g_object_unref (model->priv->modif_stmts [DEL_QUERY]);
- model->priv->modif_stmts [DEL_QUERY] = g_value_get_object (value);
- if (model->priv->modif_stmts [DEL_QUERY])
- g_object_ref (model->priv->modif_stmts [DEL_QUERY]);
+ if (model->priv->modif_internals->modif_stmts [DEL_QUERY])
+ g_object_unref (model->priv->modif_internals->modif_stmts [DEL_QUERY]);
+ model->priv->modif_internals->modif_stmts [DEL_QUERY] = g_value_get_object (value);
+ if (model->priv->modif_internals->modif_stmts [DEL_QUERY])
+ g_object_ref (model->priv->modif_internals->modif_stmts [DEL_QUERY]);
break;
case PROP_UPD_QUERY:
- if (model->priv->modif_stmts [UPD_QUERY])
- g_object_unref (model->priv->modif_stmts [UPD_QUERY]);
- model->priv->modif_stmts [UPD_QUERY] = g_value_get_object (value);
- if (model->priv->modif_stmts [UPD_QUERY])
- g_object_ref (model->priv->modif_stmts [UPD_QUERY]);
+ if (model->priv->modif_internals->modif_stmts [UPD_QUERY])
+ g_object_unref (model->priv->modif_internals->modif_stmts [UPD_QUERY]);
+ model->priv->modif_internals->modif_stmts [UPD_QUERY] = g_value_get_object (value);
+ if (model->priv->modif_internals->modif_stmts [UPD_QUERY])
+ g_object_ref (model->priv->modif_internals->modif_stmts [UPD_QUERY]);
break;
default:
break;
@@ -567,16 +587,16 @@
}
break;
case PROP_PARAMS:
- g_value_set_object (value, model->priv->exec_set);
+ g_value_set_object (value, model->priv->modif_internals->exec_set);
break;
case PROP_INS_QUERY:
- g_value_set_object (value, model->priv->modif_stmts [INS_QUERY]);
+ g_value_set_object (value, model->priv->modif_internals->modif_stmts [INS_QUERY]);
break;
case PROP_DEL_QUERY:
- g_value_set_object (value, model->priv->modif_stmts [DEL_QUERY]);
+ g_value_set_object (value, model->priv->modif_internals->modif_stmts [DEL_QUERY]);
break;
case PROP_UPD_QUERY:
- g_value_set_object (value, model->priv->modif_stmts [UPD_QUERY]);
+ g_value_set_object (value, model->priv->modif_internals->modif_stmts [UPD_QUERY]);
break;
default:
break;
@@ -649,38 +669,38 @@
}
/*
- * Add the +/-<col num> holders to model->priv->modif_set
+ * Add the +/-<col num> holders to model->priv->modif_internals->modif_set
*/
static gboolean
compute_modif_set (GdaDataSelect *model, GError **error)
{
gint i;
- if (model->priv->modif_set)
- g_object_unref (model->priv->modif_set);
- if (model->priv->exec_set)
- model->priv->modif_set = gda_set_copy (model->priv->exec_set);
+ if (model->priv->modif_internals->modif_set)
+ g_object_unref (model->priv->modif_internals->modif_set);
+ if (model->priv->modif_internals->exec_set)
+ model->priv->modif_internals->modif_set = gda_set_copy (model->priv->modif_internals->exec_set);
else
- model->priv->modif_set = gda_set_new (NULL);
+ model->priv->modif_internals->modif_set = gda_set_new (NULL);
for (i = 0; i < NB_QUERIES; i++) {
GdaSet *set;
- if (! model->priv->modif_stmts [i])
+ if (! model->priv->modif_internals->modif_stmts [i])
continue;
- if (! gda_statement_get_parameters (model->priv->modif_stmts [i], &set, error)) {
- g_object_unref (model->priv->modif_set);
- model->priv->modif_set = NULL;
+ if (! gda_statement_get_parameters (model->priv->modif_internals->modif_stmts [i], &set, error)) {
+ g_object_unref (model->priv->modif_internals->modif_set);
+ model->priv->modif_internals->modif_set = NULL;
return FALSE;
}
- gda_set_merge_with_set (model->priv->modif_set, set);
+ gda_set_merge_with_set (model->priv->modif_internals->modif_set, set);
g_object_unref (set);
}
#ifdef GDA_DEBUG_NO
GSList *list;
g_print ("-------\n");
- for (list = model->priv->modif_set->holders; list; list = list->next) {
+ for (list = model->priv->modif_internals->modif_set->holders; list; list = list->next) {
GdaHolder *h = GDA_HOLDER (list->data);
g_print ("=> holder '%s'\n", gda_holder_get_id (h));
}
@@ -877,14 +897,14 @@
mtype = DEL_QUERY;
- /* if there is no WHERE part, then use model->priv->unique_row_condition if set */
+ /* if there is no WHERE part, then use model->priv->modif_internals->unique_row_condition if set */
g_object_get (G_OBJECT (mod_stmt), "structure", &sqlst, NULL);
g_assert (sqlst);
del = (GdaSqlStatementDelete*) sqlst->contents;
if (!del->cond) {
- if (model->priv->unique_row_condition) {
- /* copy model->priv->unique_row_condition */
- del->cond = gda_sql_expr_copy (model->priv->unique_row_condition);
+ if (model->priv->modif_internals->unique_row_condition) {
+ /* copy model->priv->modif_internals->unique_row_condition */
+ del->cond = gda_sql_expr_copy (model->priv->modif_internals->unique_row_condition);
GDA_SQL_ANY_PART (del->cond)->parent = GDA_SQL_ANY_PART (del);
g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL);
}
@@ -896,10 +916,10 @@
}
}
else {
- if (model->priv->unique_row_condition) {
- /* replace WHERE with model->priv->unique_row_condition */
+ if (model->priv->modif_internals->unique_row_condition) {
+ /* replace WHERE with model->priv->modif_internals->unique_row_condition */
gda_sql_expr_free (del->cond);
- del->cond = gda_sql_expr_copy (model->priv->unique_row_condition);
+ del->cond = gda_sql_expr_copy (model->priv->modif_internals->unique_row_condition);
GDA_SQL_ANY_PART (del->cond)->parent = GDA_SQL_ANY_PART (del);
g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL);
}
@@ -917,14 +937,14 @@
mtype = UPD_QUERY;
- /* if there is no WHERE part, then use model->priv->unique_row_condition if set */
+ /* if there is no WHERE part, then use model->priv->modif_internals->unique_row_condition if set */
g_object_get (G_OBJECT (mod_stmt), "structure", &sqlst, NULL);
g_assert (sqlst);
upd = (GdaSqlStatementUpdate*) sqlst->contents;
if (!upd->cond) {
- if (model->priv->unique_row_condition) {
- /* copy model->priv->unique_row_condition */
- upd->cond = gda_sql_expr_copy (model->priv->unique_row_condition);
+ if (model->priv->modif_internals->unique_row_condition) {
+ /* copy model->priv->modif_internals->unique_row_condition */
+ upd->cond = gda_sql_expr_copy (model->priv->modif_internals->unique_row_condition);
GDA_SQL_ANY_PART (upd->cond)->parent = GDA_SQL_ANY_PART (upd);
g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL);
}
@@ -936,10 +956,10 @@
}
}
else {
- if (model->priv->unique_row_condition) {
- /* replace WHERE with model->priv->unique_row_condition */
+ if (model->priv->modif_internals->unique_row_condition) {
+ /* replace WHERE with model->priv->modif_internals->unique_row_condition */
gda_sql_expr_free (upd->cond);
- upd->cond = gda_sql_expr_copy (model->priv->unique_row_condition);
+ upd->cond = gda_sql_expr_copy (model->priv->modif_internals->unique_row_condition);
GDA_SQL_ANY_PART (upd->cond)->parent = GDA_SQL_ANY_PART (upd);
g_object_set (G_OBJECT (mod_stmt), "structure", sqlst, NULL);
}
@@ -959,16 +979,16 @@
if (! gda_statement_check_structure (mod_stmt, error))
return FALSE;
- if (model->priv->modif_stmts[mtype]) {
- g_object_unref (model->priv->modif_stmts[mtype]);
- model->priv->modif_stmts[mtype] = NULL;
+ if (model->priv->modif_internals->modif_stmts[mtype]) {
+ g_object_unref (model->priv->modif_internals->modif_stmts[mtype]);
+ model->priv->modif_internals->modif_stmts[mtype] = NULL;
}
- /* prepare model->priv->modif_set */
+ /* prepare model->priv->modif_internals->modif_set */
if (!compute_modif_set (model, error))
return FALSE;
- /* check that all the parameters required to execute @mod_stmt are in model->priv->modif_set */
+ /* check that all the parameters required to execute @mod_stmt are in model->priv->modif_internals->modif_set */
GdaSet *params;
GSList *list;
if (! gda_statement_get_parameters (mod_stmt, ¶ms, error))
@@ -976,7 +996,7 @@
for (list = params->holders; list; list = list->next) {
GdaHolder *holder = GDA_HOLDER (list->data);
GdaHolder *eholder;
- eholder = gda_set_get_holder (model->priv->modif_set, gda_holder_get_id (holder));
+ eholder = gda_set_get_holder (model->priv->modif_internals->modif_set, gda_holder_get_id (holder));
if (!eholder) {
gint num;
gboolean is_old;
@@ -995,7 +1015,7 @@
g_object_unref (params);
return FALSE;
}
- gda_set_add_holder (model->priv->modif_set, holder);
+ gda_set_add_holder (model->priv->modif_internals->modif_set, holder);
}
else if (gda_holder_get_g_type (holder) != gda_holder_get_g_type (eholder)) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR,
@@ -1009,7 +1029,7 @@
}
g_object_unref (params);
- model->priv->modif_stmts[mtype] = mod_stmt;
+ model->priv->modif_internals->modif_stmts[mtype] = mod_stmt;
g_object_ref (mod_stmt);
}
else {
@@ -1021,8 +1041,8 @@
#ifdef GDA_DEBUG_NO
GSList *hlist;
g_print ("SET MODIF QUERY\n");
- if (model->priv->modif_set) {
- for (hlist = model->priv->modif_set->holders; hlist; hlist = hlist->next) {
+ if (model->priv->modif_internals->modif_set) {
+ for (hlist = model->priv->modif_internals->modif_set->holders; hlist; hlist = hlist->next) {
GdaHolder *h = GDA_HOLDER (hlist->data);
g_print (" %s type=> %s (%d)\n", gda_holder_get_id (h), g_type_name (gda_holder_get_g_type (h)),
gda_holder_get_g_type (h));
@@ -1064,9 +1084,9 @@
return FALSE;
}
for (mtype = FIRST_QUERY; mtype < NB_QUERIES; mtype++)
- if (model->priv->modif_stmts[mtype]) {
- g_object_unref (model->priv->modif_stmts[mtype]);
- model->priv->modif_stmts[mtype] = NULL;
+ if (model->priv->modif_internals->modif_stmts[mtype]) {
+ g_object_unref (model->priv->modif_internals->modif_stmts[mtype]);
+ model->priv->modif_internals->modif_stmts[mtype] = NULL;
}
retval = gda_compute_dml_statements (model->priv->cnc, stmt, TRUE,
@@ -1136,7 +1156,7 @@
if (!check_acceptable_statement (model, error))
return FALSE;
- if (model->priv->unique_row_condition) {
+ if (model->priv->modif_internals->unique_row_condition) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR,
_("Unique row condition has already been specified"));
return FALSE;
@@ -1148,7 +1168,7 @@
if (!valid)
return FALSE;
- model->priv->unique_row_condition = gda_sql_expr_copy (expr);
+ model->priv->modif_internals->unique_row_condition = gda_sql_expr_copy (expr);
return TRUE;
}
@@ -1191,7 +1211,7 @@
if (!check_acceptable_statement (model, error))
return FALSE;
- if (model->priv->unique_row_condition) {
+ if (model->priv->modif_internals->unique_row_condition) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MODIFICATION_STATEMENT_ERROR,
_("Unique row condition has already been specified"));
return FALSE;
@@ -1376,12 +1396,14 @@
flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
}
- if (imodel->priv->modif_stmts [UPD_QUERY])
- flags |= GDA_DATA_MODEL_ACCESS_UPDATE;
- if (imodel->priv->modif_stmts [INS_QUERY])
- flags |= GDA_DATA_MODEL_ACCESS_INSERT;
- if (imodel->priv->modif_stmts [DEL_QUERY])
- flags |= GDA_DATA_MODEL_ACCESS_DELETE;
+ if (! imodel->priv->modif_internals->safely_locked) {
+ if (imodel->priv->modif_internals->modif_stmts [UPD_QUERY])
+ flags |= GDA_DATA_MODEL_ACCESS_UPDATE;
+ if (imodel->priv->modif_internals->modif_stmts [INS_QUERY])
+ flags |= GDA_DATA_MODEL_ACCESS_INSERT;
+ if (imodel->priv->modif_internals->modif_stmts [DEL_QUERY])
+ flags |= GDA_DATA_MODEL_ACCESS_DELETE;
+ }
return flags;
}
@@ -1471,7 +1493,8 @@
GdaDataModel *tmpmodel;
if (!dstmt->select || !dstmt->params) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
- _("Unable to retreive data after modifications"));
+ _("Unable to retreive data after modifications, no further modification will be allowed"));
+ imodel->priv->modif_internals->safely_locked = TRUE;
return NULL;
}
tmpmodel = gda_connection_statement_execute_select (imodel->priv->cnc,
@@ -1479,14 +1502,16 @@
dstmt->params, NULL);
if (!tmpmodel) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
- _("Unable to retreive data after modifications"));
+ _("Unable to retreive data after modifications, no further modification will be allowed"));
+ imodel->priv->modif_internals->safely_locked = TRUE;
return NULL;
}
if (gda_data_model_get_n_rows (tmpmodel) != 1) {
g_object_unref (tmpmodel);
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
- _("Unable to retreive data after modifications"));
+ _("Unable to retreive data after modifications, no further modification will be allowed"));
+ imodel->priv->modif_internals->safely_locked = TRUE;
return NULL;
}
@@ -1507,7 +1532,8 @@
g_object_unref (tmpmodel);
g_object_unref (prow);
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
- _("Unable to retreive data after modifications"));
+ _("Unable to retreive data after modifications, no further modification will be allowed"));
+ imodel->priv->modif_internals->safely_locked = TRUE;
return NULL;
}
}
@@ -1541,16 +1567,21 @@
static GdaValueAttribute
gda_data_select_get_attributes_at (GdaDataModel *model, gint col, gint row)
{
- GdaValueAttribute flags = 0;
+ GdaValueAttribute flags = GDA_VALUE_ATTR_IS_UNCHANGED;
GdaDataSelect *imodel;
g_return_val_if_fail (GDA_IS_DATA_SELECT (model), 0);
imodel = (GdaDataSelect *) model;
g_return_val_if_fail (imodel->priv, 0);
- if (! imodel->priv->modif_stmts [UPD_QUERY])
+ if (imodel->priv->modif_internals->safely_locked || !imodel->priv->modif_internals->modif_stmts [UPD_QUERY])
flags = GDA_VALUE_ATTR_NO_MODIF;
-
+ GdaColumn *gdacol = g_slist_nth_data (imodel->priv->columns, col);
+ if (gdacol) {
+ if (gda_column_get_allow_null (gdacol))
+ flags |= GDA_VALUE_ATTR_CAN_BE_NULL;
+ }
+
return flags;
}
@@ -1750,7 +1781,7 @@
}
/*
- * creates a derivative of the model->priv->modif_stmts [UPD_QUERY] statement
+ * creates a derivative of the model->priv->modif_internals->modif_stmts [UPD_QUERY] statement
* where only the columns where @bv->data[colnum] is not 0 are updated.
*
* Returns: a new #GdaStatement, or %NULL
@@ -1763,8 +1794,8 @@
GdaStatement *updstmt = NULL;
/* get a copy of complete UPDATE stmt */
- g_assert (model->priv->modif_stmts [UPD_QUERY]);
- g_object_get (G_OBJECT (model->priv->modif_stmts [UPD_QUERY]), "structure", &sqlst, NULL);
+ g_assert (model->priv->modif_internals->modif_stmts [UPD_QUERY]);
+ g_object_get (G_OBJECT (model->priv->modif_internals->modif_stmts [UPD_QUERY]), "structure", &sqlst, NULL);
g_assert (sqlst);
g_free (sqlst->sql);
sqlst->sql = NULL;
@@ -1843,7 +1874,7 @@
}
/*
- * creates a derivative of the model->priv->modif_stmts [INS_QUERY] statement
+ * creates a derivative of the model->priv->modif_internals->modif_stmts [INS_QUERY] statement
* where only the columns where @bv->data[colnum] is not 0 are not mentionned.
*
* Returns: a new #GdaStatement, or %NULL
@@ -1856,8 +1887,8 @@
GdaStatement *insstmt = NULL;
/* get a copy of complete INSERT stmt */
- g_assert (model->priv->modif_stmts [INS_QUERY]);
- g_object_get (G_OBJECT (model->priv->modif_stmts [INS_QUERY]), "structure", &sqlst, NULL);
+ g_assert (model->priv->modif_internals->modif_stmts [INS_QUERY]);
+ g_object_get (G_OBJECT (model->priv->modif_internals->modif_stmts [INS_QUERY]), "structure", &sqlst, NULL);
g_assert (sqlst);
g_free (sqlst->sql);
sqlst->sql = NULL;
@@ -1941,7 +1972,7 @@
* after an UPDATE or INSERT statement has been run)
*
* The new created statement is merely the copy of the SELECT statement where the WHERE part
- * has been altered as "<original condition> AND <update condition>"
+ * has been altered as "<update condition>"
*
* Returns: a new #GdaStatement, or %NULL
*/
@@ -1966,13 +1997,13 @@
return NULL;
}
- if (model->priv->unique_row_condition)
- row_cond = gda_sql_expr_copy (model->priv->unique_row_condition);
- else if (model->priv->modif_stmts [DEL_QUERY]) {
+ if (model->priv->modif_internals->unique_row_condition)
+ row_cond = gda_sql_expr_copy (model->priv->modif_internals->unique_row_condition);
+ else if (model->priv->modif_internals->modif_stmts [DEL_QUERY]) {
GdaStatement *del_stmt;
GdaSqlStatement *del_sqlst;
GdaSqlStatementDelete *del;
- del_stmt = model->priv->modif_stmts [DEL_QUERY];
+ del_stmt = model->priv->modif_internals->modif_stmts [DEL_QUERY];
g_object_get (G_OBJECT (del_stmt), "structure", &del_sqlst, NULL);
del = (GdaSqlStatementDelete*) del_sqlst->contents;
@@ -1984,11 +2015,11 @@
row_cond = NULL;
}
}
- else if (model->priv->modif_stmts [UPD_QUERY]) {
+ else if (model->priv->modif_internals->modif_stmts [UPD_QUERY]) {
GdaStatement *upd_stmt;
GdaSqlStatement *upd_sqlst;
GdaSqlStatementUpdate *upd;
- upd_stmt = model->priv->modif_stmts [UPD_QUERY];
+ upd_stmt = model->priv->modif_internals->modif_stmts [UPD_QUERY];
g_object_get (G_OBJECT (upd_stmt), "structure", &upd_sqlst, NULL);
upd = (GdaSqlStatementUpdate*) upd_sqlst->contents;
@@ -2020,25 +2051,10 @@
sel = (GdaSqlStatementSelect*) sel_sqlst->contents;
g_free (sel_sqlst->sql);
sel_sqlst->sql = NULL;
- if (sel->where_cond) {
- GdaSqlExpr *and_expr;
- GdaSqlOperation *and_cond;
-
- and_expr = gda_sql_expr_new (GDA_SQL_ANY_PART (sel));
- and_cond = gda_sql_operation_new (GDA_SQL_ANY_PART (and_expr));
- and_expr->cond = and_cond;
- and_cond->operator_type = GDA_SQL_OPERATOR_TYPE_AND;
- and_cond->operands = g_slist_append (NULL, sel->where_cond);
- GDA_SQL_ANY_PART (sel->where_cond)->parent = GDA_SQL_ANY_PART (and_cond);
- sel->where_cond = and_expr;
-
- and_cond->operands = g_slist_append (and_cond->operands, row_cond);
- GDA_SQL_ANY_PART (row_cond)->parent = GDA_SQL_ANY_PART (and_cond);
- }
- else {
- sel->where_cond = row_cond;
- GDA_SQL_ANY_PART (row_cond)->parent = GDA_SQL_ANY_PART (sel);
- }
+ if (sel->where_cond)
+ gda_sql_expr_free (sel->where_cond);
+ sel->where_cond = row_cond;
+ GDA_SQL_ANY_PART (row_cond)->parent = GDA_SQL_ANY_PART (sel);
ret_stmt = (GdaStatement *) g_object_new (GDA_TYPE_STATEMENT, "structure", sel_sqlst, NULL);
@@ -2103,12 +2119,17 @@
/* arguments check */
g_assert (bv);
+ if (imodel->priv->modif_internals->safely_locked) {
+ g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR,
+ _("Modifications are not allowed anymore"));
+ return FALSE;
+ }
if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
_("Data model does not support random access"));
return FALSE;
}
- if (! imodel->priv->modif_stmts [UPD_QUERY]) {
+ if (! imodel->priv->modif_internals->modif_stmts [UPD_QUERY]) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
_("No UPDATE statement provided"));
return FALSE;
@@ -2119,15 +2140,15 @@
return FALSE;
/* compute UPDATE statement */
- if (! imodel->priv->upd_stmts)
- imodel->priv->upd_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, (GEqualFunc) bvector_equal,
+ if (! imodel->priv->modif_internals->upd_stmts)
+ imodel->priv->modif_internals->upd_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, (GEqualFunc) bvector_equal,
(GDestroyNotify) bvector_free, g_object_unref);
- stmt = g_hash_table_lookup (imodel->priv->upd_stmts, bv);
+ stmt = g_hash_table_lookup (imodel->priv->modif_internals->upd_stmts, bv);
if (! stmt) {
stmt = compute_single_update_stmt (imodel, bv, error);
if (stmt) {
free_bv = FALSE;
- g_hash_table_insert (imodel->priv->upd_stmts, bv, stmt);
+ g_hash_table_insert (imodel->priv->modif_internals->upd_stmts, bv, stmt);
}
else {
bvector_free (bv);
@@ -2139,7 +2160,7 @@
ncols = gda_data_select_get_n_columns ((GdaDataModel*) imodel);
for (i = 0; i < ncols; i++) {
str = g_strdup_printf ("-%d", i);
- holder = gda_set_get_holder (imodel->priv->modif_set, str);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
g_free (str);
if (holder) {
const GValue *cvalue;
@@ -2161,7 +2182,7 @@
GError *lerror = NULL;
sql = gda_statement_to_sql_extended (stmt,
imodel->priv->cnc,
- imodel->priv->modif_set,
+ imodel->priv->modif_internals->modif_set,
GDA_STATEMENT_SQL_PRETTY, NULL,
&lerror);
g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql);
@@ -2171,31 +2192,56 @@
#endif
if (gda_connection_statement_execute_non_select (imodel->priv->cnc, stmt,
- imodel->priv->modif_set, NULL, error) == -1)
+ imodel->priv->modif_internals->modif_set, NULL, error) == -1)
return FALSE;
/* mark that this row has been modified */
DelayedSelectStmt *dstmt;
dstmt = g_new0 (DelayedSelectStmt, 1);
- if (! imodel->priv->one_row_select_stmt)
- imodel->priv->one_row_select_stmt = compute_single_select_stmt (imodel, error);
- if (imodel->priv->one_row_select_stmt) {
- dstmt->select = g_object_ref (imodel->priv->one_row_select_stmt);
+ if (! imodel->priv->modif_internals->one_row_select_stmt)
+ imodel->priv->modif_internals->one_row_select_stmt = compute_single_select_stmt (imodel, error);
+ if (imodel->priv->modif_internals->one_row_select_stmt) {
+ dstmt->select = g_object_ref (imodel->priv->modif_internals->one_row_select_stmt);
gda_statement_get_parameters (dstmt->select, &(dstmt->params), NULL);
if (dstmt->params) {
GSList *list;
- for (list = dstmt->params->holders; list; list = list->next) {
+ gboolean allok = TRUE;
+
+ /* overwrite old values with new values if some have been provided */
+ for (list = imodel->priv->modif_internals->modif_set->holders; list; list = list->next) {
+ GdaHolder *h = (GdaHolder*) list->data;
+ gint res;
+ gboolean old;
+ if (gda_holder_is_valid ((GdaHolder*) list->data) &&
+ param_name_to_int (gda_holder_get_id (h), &res, &old) &&
+ !old) {
+ str = g_strdup_printf ("-%d", res);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
+ g_free (str);
+ if (holder &&
+ ! gda_holder_set_value (holder, gda_holder_get_value (h), error)) {
+ allok = FALSE;
+ break;
+ }
+ }
+ }
+
+ for (list = dstmt->params->holders; list && allok; list = list->next) {
GdaHolder *holder = GDA_HOLDER (list->data);
GdaHolder *eholder;
- eholder = gda_set_get_holder (imodel->priv->modif_set,
+ eholder = gda_set_get_holder (imodel->priv->modif_internals->modif_set,
gda_holder_get_id (holder));
if (!eholder ||
- ! gda_holder_set_value (holder, gda_holder_get_value (eholder), error)) {
- g_object_unref (dstmt->params);
- dstmt->params = NULL;
+ ! gda_holder_set_value (holder, gda_holder_get_value (eholder), NULL)) {
+ allok = FALSE;
break;
}
}
+
+ if (!allok) {
+ g_object_unref (dstmt->params);
+ dstmt->params = NULL;
+ }
}
}
dstmt->row = NULL;
@@ -2227,12 +2273,17 @@
imodel = (GdaDataSelect *) model;
g_return_val_if_fail (imodel->priv, FALSE);
+ if (imodel->priv->modif_internals->safely_locked) {
+ g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR,
+ _("Modifications are not allowed anymore"));
+ return FALSE;
+ }
if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
_("Data model does not support random access"));
return FALSE;
}
- if (! imodel->priv->modif_stmts [UPD_QUERY]) {
+ if (! imodel->priv->modif_internals->modif_stmts [UPD_QUERY]) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
_("No UPDATE statement provided"));
return FALSE;
@@ -2246,9 +2297,17 @@
return FALSE;
}
+ /* invalidate all the imodel->priv->modif_internals->modif_set's value holders */
+ GSList *list;
+ for (list = imodel->priv->modif_internals->modif_set->holders; list; list = list->next) {
+ GdaHolder *h = (GdaHolder*) list->data;
+ if (param_name_to_int (gda_holder_get_id (h), NULL, NULL))
+ gda_holder_force_invalid ((GdaHolder*) list->data);
+ }
+
/* give values to params for new value */
str = g_strdup_printf ("+%d", col);
- holder = gda_set_get_holder (imodel->priv->modif_set, str);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
g_free (str);
if (! holder) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
@@ -2294,12 +2353,17 @@
/* arguments check */
g_return_val_if_fail (imodel->priv, FALSE);
+ if (imodel->priv->modif_internals->safely_locked) {
+ g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR,
+ _("Modifications are not allowed anymore"));
+ return FALSE;
+ }
if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
_("Data model does not support random access"));
return FALSE;
}
- if (! imodel->priv->modif_stmts [UPD_QUERY]) {
+ if (! imodel->priv->modif_internals->modif_stmts [UPD_QUERY]) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
_("No UPDATE statement provided"));
return FALSE;
@@ -2332,13 +2396,21 @@
return TRUE;
}
+ /* invalidate all the imodel->priv->modif_internals->modif_set's value holders */
+ GSList *slist;
+ for (slist = imodel->priv->modif_internals->modif_set->holders; slist; slist = slist->next) {
+ GdaHolder *h = (GdaHolder*) slist->data;
+ if (param_name_to_int (gda_holder_get_id (h), NULL, NULL))
+ gda_holder_force_invalid ((GdaHolder*) slist->data);
+ }
+
/* give values to params for new values */
for (i = 0, list = values; list; i++, list = list->next) {
if (!bv->data[i])
continue;
str = g_strdup_printf ("+%d", i);
- holder = gda_set_get_holder (imodel->priv->modif_set, str);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
g_free (str);
if (! holder) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
@@ -2368,12 +2440,17 @@
g_return_val_if_fail (imodel->priv, -1);
+ if (imodel->priv->modif_internals->safely_locked) {
+ g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR,
+ _("Modifications are not allowed anymore"));
+ return FALSE;
+ }
if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
_("Data model does not support random access"));
return -1;
}
- if (! imodel->priv->modif_stmts [INS_QUERY]) {
+ if (! imodel->priv->modif_internals->modif_stmts [INS_QUERY]) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
_("No INSERT statement provided"));
return -1;
@@ -2414,15 +2491,15 @@
/* compute INSERT statement */
GdaStatement *stmt;
- if (! imodel->priv->ins_stmts)
- imodel->priv->ins_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, (GEqualFunc) bvector_equal,
+ if (! imodel->priv->modif_internals->ins_stmts)
+ imodel->priv->modif_internals->ins_stmts = g_hash_table_new_full ((GHashFunc) bvector_hash, (GEqualFunc) bvector_equal,
(GDestroyNotify) bvector_free, g_object_unref);
- stmt = g_hash_table_lookup (imodel->priv->ins_stmts, bv);
+ stmt = g_hash_table_lookup (imodel->priv->modif_internals->ins_stmts, bv);
if (! stmt) {
stmt = compute_single_insert_stmt (imodel, bv, error);
if (stmt) {
free_bv = FALSE;
- g_hash_table_insert (imodel->priv->ins_stmts, bv, stmt);
+ g_hash_table_insert (imodel->priv->modif_internals->ins_stmts, bv, stmt);
}
else {
bvector_free (bv);
@@ -2436,7 +2513,7 @@
continue;
str = g_strdup_printf ("+%d", i);
- holder = gda_set_get_holder (imodel->priv->modif_set, str);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
g_free (str);
if (! holder) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
@@ -2459,7 +2536,7 @@
GError *lerror = NULL;
sql = gda_statement_to_sql_extended (stmt,
imodel->priv->cnc,
- imodel->priv->modif_set,
+ imodel->priv->modif_internals->modif_set,
GDA_STATEMENT_SQL_PRETTY, NULL,
&lerror);
g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql);
@@ -2475,24 +2552,24 @@
GdaSet *last_insert;
if (gda_connection_statement_execute_non_select (imodel->priv->cnc, stmt,
- imodel->priv->modif_set, &last_insert, error) == -1)
+ imodel->priv->modif_internals->modif_set, &last_insert, error) == -1)
return -1;
/* mark that this row has been modified */
DelayedSelectStmt *dstmt;
dstmt = g_new0 (DelayedSelectStmt, 1);
- if (! imodel->priv->one_row_select_stmt)
- imodel->priv->one_row_select_stmt = compute_single_select_stmt (imodel, error);
- if (last_insert && imodel->priv->one_row_select_stmt) {
- dstmt->select = g_object_ref (imodel->priv->one_row_select_stmt);
+ if (! imodel->priv->modif_internals->one_row_select_stmt)
+ imodel->priv->modif_internals->one_row_select_stmt = compute_single_select_stmt (imodel, error);
+ if (last_insert && imodel->priv->modif_internals->one_row_select_stmt) {
+ dstmt->select = g_object_ref (imodel->priv->modif_internals->one_row_select_stmt);
gda_statement_get_parameters (dstmt->select, &(dstmt->params), NULL);
if (dstmt->params) {
GSList *list;
- if (! imodel->priv->insert_to_select_mapping)
- imodel->priv->insert_to_select_mapping =
+ if (! imodel->priv->modif_internals->insert_to_select_mapping)
+ imodel->priv->modif_internals->insert_to_select_mapping =
compute_insert_select_params_mapping (dstmt->params, last_insert,
- imodel->priv->unique_row_condition);
- if (imodel->priv->insert_to_select_mapping) {
+ imodel->priv->modif_internals->unique_row_condition);
+ if (imodel->priv->modif_internals->insert_to_select_mapping) {
for (list = dstmt->params->holders; list; list = list->next) {
GdaHolder *holder = GDA_HOLDER (list->data);
GdaHolder *eholder;
@@ -2501,7 +2578,7 @@
g_assert (param_name_to_int (gda_holder_get_id (holder), &pos, NULL));
eholder = g_slist_nth_data (last_insert->holders,
- imodel->priv->insert_to_select_mapping[pos]);
+ imodel->priv->modif_internals->insert_to_select_mapping[pos]);
if (!eholder ||
! gda_holder_set_value (holder, gda_holder_get_value (eholder), error)) {
g_object_unref (dstmt->params);
@@ -2546,12 +2623,17 @@
g_return_val_if_fail (imodel->priv, FALSE);
+ if (imodel->priv->modif_internals->safely_locked) {
+ g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_SAFETY_LOCKED_ERROR,
+ _("Modifications are not allowed anymore"));
+ return FALSE;
+ }
if (! (imodel->priv->usage_flags & GDA_DATA_MODEL_ACCESS_RANDOM)) {
g_set_error (error, GDA_DATA_MODEL_ERROR, GDA_DATA_MODEL_ACCESS_ERROR,
_("Data model does not support random access"));
return FALSE;
}
- if (! imodel->priv->modif_stmts [DEL_QUERY]) {
+ if (! imodel->priv->modif_internals->modif_stmts [DEL_QUERY]) {
g_set_error (error, GDA_DATA_SELECT_ERROR, GDA_DATA_SELECT_MISSING_MODIFICATION_STATEMENT_ERROR,
_("No DELETE statement provided"));
return FALSE;
@@ -2564,7 +2646,7 @@
ncols = gda_data_select_get_n_columns (model);
for (i = 0; i < ncols; i++) {
str = g_strdup_printf ("-%d", i);
- holder = gda_set_get_holder (imodel->priv->modif_set, str);
+ holder = gda_set_get_holder (imodel->priv->modif_internals->modif_set, str);
g_free (str);
if (holder) {
const GValue *cvalue;
@@ -2579,9 +2661,9 @@
#ifdef GDA_DEBUG_NO
gchar *sql;
GError *lerror = NULL;
- sql = gda_statement_to_sql_extended (imodel->priv->modif_stmts [DEL_QUERY],
+ sql = gda_statement_to_sql_extended (imodel->priv->modif_internals->modif_stmts [DEL_QUERY],
imodel->priv->cnc,
- imodel->priv->modif_set,
+ imodel->priv->modif_internals->modif_set,
GDA_STATEMENT_SQL_PRETTY, NULL,
&lerror);
g_print ("%s(): SQL=> %s\n", __FUNCTION__, sql);
@@ -2590,8 +2672,8 @@
g_free (sql);
#endif
if (gda_connection_statement_execute_non_select (imodel->priv->cnc,
- imodel->priv->modif_stmts [DEL_QUERY],
- imodel->priv->modif_set, NULL, error) == -1)
+ imodel->priv->modif_internals->modif_stmts [DEL_QUERY],
+ imodel->priv->modif_internals->modif_set, NULL, error) == -1)
return FALSE;
/* mark that this row has been removed */
@@ -2615,7 +2697,7 @@
*
* The way of preceeding is:
* - for each parameter required by model->one_row_select_stmt statement (the @sel_params argument),
- * use the model->priv->unique_row_condition to get the name of the corresponding column (the GdaHolder's ID
+ * use the model->priv->modif_internals->unique_row_condition to get the name of the corresponding column (the GdaHolder's ID
* is "-<num1>" )
* - from the column name get the GdaHolder in the GdaSet retruned after the INSERT statement (the
* @ins_values argument) using the "name" property of each GdaHolder in the GdaSet (the GdaHolder's ID
Modified: trunk/libgda/gda-data-select.h
==============================================================================
--- trunk/libgda/gda-data-select.h (original)
+++ trunk/libgda/gda-data-select.h Sun Sep 7 19:06:38 2008
@@ -50,7 +50,8 @@
GDA_DATA_SELECT_CONNECTION_ERROR,
GDA_DATA_SELECT_VALUE_ERROR,
GDA_DATA_SELECT_ACCESS_ERROR,
- GDA_DATA_SELECT_SQL_ERROR
+ GDA_DATA_SELECT_SQL_ERROR,
+ GDA_DATA_SELECT_SAFETY_LOCKED_ERROR
};
struct _GdaDataSelect {
Modified: trunk/libgda/sqlite/virtual/gda-vconnection-hub.c
==============================================================================
--- trunk/libgda/sqlite/virtual/gda-vconnection-hub.c (original)
+++ trunk/libgda/sqlite/virtual/gda-vconnection-hub.c Sun Sep 7 19:06:38 2008
@@ -27,7 +27,7 @@
#include "gda-virtual-provider.h"
#include <sql-parser/gda-sql-parser.h>
#include <libgda/gda-util.h>
-#include <libgda/gda-data-model-query.h>
+#include <libgda/gda-data-select.h>
typedef struct {
GdaVconnectionHub *hub;
@@ -404,11 +404,10 @@
tmp = g_strdup_printf ("SELECT * FROM %s", g_value_get_string (lspec->table_name));
stmt = gda_sql_parser_parse_string (internal_parser, tmp, NULL, NULL);
g_free (tmp);
- model = gda_data_model_query_new (lspec->hc->cnc, stmt);
+ model = gda_connection_statement_execute_select (lspec->hc->cnc, stmt, NULL, NULL);
g_object_unref (stmt);
- gda_data_model_query_compute_modification_queries (GDA_DATA_MODEL_QUERY (model),
- g_value_get_string (lspec->table_name),
- GDA_DATA_MODEL_QUERY_OPTION_USE_ALL_FIELDS_IF_NO_PK, NULL);
+ if (model)
+ gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), NULL);
return model;
}
Modified: trunk/tests/data-models/Makefile.am
==============================================================================
--- trunk/tests/data-models/Makefile.am (original)
+++ trunk/tests/data-models/Makefile.am Sun Sep 7 19:06:38 2008
@@ -7,8 +7,8 @@
-DTOP_SRC_DIR=\""$(top_srcdir)"\" \
-DTOP_BUILD_DIR=\""$(top_builddir)"\"
-check_PROGRAMS = check_model_import check_virtual check_data_proxy check_model_copy check_pmodel
-TESTS = check_model_import check_virtual check_data_proxy check_model_copy check_pmodel
+check_PROGRAMS = check_model_import check_virtual check_data_proxy check_model_copy check_pmodel check_model_query
+TESTS = check_model_import check_virtual check_data_proxy check_model_copy check_pmodel check_model_query
common_sources =
@@ -37,13 +37,20 @@
check_pmodel_SOURCES = $(common_sources) check_pmodel.c
check_pmodel_CFLAGS = \
- -I$(top_srcdir)/libgda/sqlite \
- -I$(top_srcdir)/libgda/sqlite/pmodel
+ -I$(top_srcdir)/libgda/sqlite
check_pmodel_LDADD = \
$(top_builddir)/libgda/libgda-4.0.la \
$(top_builddir)/tests/libgda-test-4.0.la \
$(LIBGDA_LIBS)
+check_model_query_SOURCES = $(common_sources) check_model_query.c
+check_model_query_CFLAGS = \
+ -I$(top_srcdir)/libgda/sqlite
+check_model_query_LDADD = \
+ $(top_builddir)/libgda/libgda-4.0.la \
+ $(top_builddir)/tests/libgda-test-4.0.la \
+ $(LIBGDA_LIBS)
+
EXTRA_DIST = \
check_virtual.csv \
city.csv \
@@ -54,4 +61,4 @@
pmodel_data_locations.xml
CLEANFILES = \
- pmodel.db
+ pmodel.db modelquery.db
Added: trunk/tests/data-models/check_model_query.c
==============================================================================
--- (empty file)
+++ trunk/tests/data-models/check_model_query.c Sun Sep 7 19:06:38 2008
@@ -0,0 +1,696 @@
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include <sql-parser/gda-sql-statement.h>
+#include <tests/gda-ddl-creator.h>
+#include <glib/gstdio.h>
+#include "../test-cnc-utils.h"
+
+#define fail(x) g_warning (x)
+#define fail_if(x,y) if (x) g_warning (y)
+#define fail_unless(x,y) if (!(x)) g_warning (y)
+
+#define CHECK_EXTRA_INFO
+
+/* signals checking */
+typedef struct {
+ GdaDataModel *model;
+ gchar type; /* U, I, D */
+ gint row;
+} SigEvent;
+static GSList *signals = NULL;
+static void monitor_model_signals (GdaDataModel *model);
+static void signal_callback (GdaDataModel *model, gint row, gchar *type);
+static void clear_signals (void);
+static gboolean check_expected_signal (GdaDataModel *model, gchar type, gint row);
+static gboolean check_no_expected_signal (GdaDataModel *model);
+
+/* utility functions */
+static GdaConnection *setup_connection (void);
+static GdaStatement *stmt_from_string (const gchar *sql);
+static void load_data_from_file (GdaConnection *cnc, const gchar *table, const gchar *file);
+static gboolean check_set_value_at (GdaDataModel *model, gint col, gint row,
+ const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params);
+static gboolean check_set_value_at_ext (GdaDataModel *model, gint col, gint row,
+ const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params, GError **error);
+static gboolean check_set_values (GdaDataModel *model, gint row, GList *set_values,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params);
+static gint check_append_values (GdaDataModel *model, GList *set_values,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params);
+
+typedef gboolean (*TestFunc) (GdaConnection *);
+static gint test1 (GdaConnection *cnc);
+static gint test2 (GdaConnection *cnc);
+
+TestFunc tests[] = {
+ test1,
+ test2
+};
+
+int
+main (int argc, char **argv)
+{
+ gint i, ntests = 0, number_failed = 0;
+ GdaConnection *cnc;
+
+ /* set up test environment */
+ g_setenv ("GDA_TOP_BUILD_DIR", TOP_BUILD_DIR, 0);
+ g_setenv ("GDA_TOP_SRC_DIR", TOP_SRC_DIR, TRUE);
+ gda_init ();
+
+ g_unlink ("modelquery.db");
+ cnc = setup_connection ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (TestFunc); i++) {
+ g_print ("---------- test %d ----------\n", i+1);
+ gint n = tests[i] (cnc);
+ number_failed += n;
+ if (n > 0)
+ g_print ("Test %d failed\n", i+1);
+ ntests ++;
+ }
+
+ g_object_unref (cnc);
+ if (number_failed == 0)
+ g_print ("Ok.\n");
+ else
+ g_print ("%d failed\n", number_failed);
+
+ return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+static GdaConnection *
+setup_connection (void)
+{
+ GdaDDLCreator *ddl;
+ GError *error = NULL;
+ GdaConnection *cnc;
+ gchar *str;
+
+ /* open a connection */
+ cnc = gda_connection_open_from_string ("SQLite", "DB_DIR=.;DB_NAME=modelquery", NULL, GDA_CONNECTION_OPTIONS_NONE, &error);
+ if (!cnc) {
+ g_print ("Error opening connection: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Setup structure */
+ ddl = gda_ddl_creator_new ();
+ gda_ddl_creator_set_connection (ddl, cnc);
+ str = g_build_filename (CHECK_FILES, "tests", "data-models", "pmodel_dbstruct.xml", NULL);
+ if (!gda_ddl_creator_set_dest_from_file (ddl, str, &error)) {
+ g_print ("Error creating GdaDDLCreator: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+ g_free (str);
+
+#ifdef SHOW_SQL
+ str = gda_ddl_creator_get_sql (ddl, &error);
+ if (!str) {
+ g_print ("Error getting SQL: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+ g_print ("%s\n", str);
+ g_free (str);
+#endif
+
+ if (!gda_ddl_creator_execute (ddl, &error)) {
+ g_print ("Error creating database objects: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ if (! gda_connection_update_meta_store (cnc, NULL, &error)) {
+ g_print ("Error fetching meta data: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ /* load some data */
+ load_data_from_file (cnc, "locations", "pmodel_data_locations.xml");
+ load_data_from_file (cnc, "customers", "pmodel_data_customers.xml");
+
+ /* update meta store */
+ if (! gda_connection_update_meta_store (cnc, NULL, &error)) {
+ g_print ("Error updateing meta store: %s\n", error && error->message ? error->message : "No detail");
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ g_object_unref (ddl);
+ return cnc;
+}
+
+static void
+load_data_from_file (GdaConnection *cnc, const gchar *table, const gchar *file)
+{
+ gchar *str;
+ GError *error = NULL;
+
+ str = g_build_filename (CHECK_FILES, "tests", "data-models", file, NULL);
+ if (! test_cnc_load_data_from_file (cnc, table, str, &error)) {
+ g_print ("Error loading data into table '%s' from file '%s': %s\n", table, str,
+ error && error->message ? error->message : "No detail");
+ exit (EXIT_FAILURE);
+ }
+ g_free (str);
+}
+
+static GdaStatement *
+stmt_from_string (const gchar *sql)
+{
+ GdaStatement *stmt;
+ GError *error = NULL;
+
+ static GdaSqlParser *parser = NULL;
+ if (!parser)
+ parser = gda_sql_parser_new ();
+
+ stmt = gda_sql_parser_parse_string (parser, sql, NULL, &error);
+ if (!stmt) {
+ g_print ("Cound not parse SQL: %s\nSQL was: %s\n",
+ error && error->message ? error->message : "No detail",
+ sql);
+ exit (EXIT_FAILURE);
+ }
+ return stmt;
+}
+
+/*
+ * check modifications statements' setting
+ *
+ * Returns the number of failures
+ */
+static gint
+test1 (GdaConnection *cnc)
+{
+ GError *error = NULL;
+ GdaDataModel *model;
+ GdaStatement *stmt;
+ gint nfailed = 0;
+
+ /* create GdaDataModelQuery */
+ stmt = stmt_from_string ("SELECT * FROM customers WHERE id= ##theid::gint");
+ model = (GdaDataModel*) gda_data_model_query_new (cnc, stmt, NULL);
+ g_assert (model);
+ if (gda_data_model_get_n_rows (model) >= 0) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Returned n_rows should be -1\n");
+#endif
+ goto out;
+ }
+
+ if (gda_data_model_get_value_at (model, 0, 0, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_get_value_at() should return NULL\n");
+#endif
+ goto out;
+ }
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Got expected error: %s\n", error && error->message ? error->message : "No detail");
+#endif
+ g_error_free (error);
+ error = NULL;
+
+ out:
+ g_object_unref (model);
+ g_object_unref (stmt);
+
+ return nfailed;
+}
+
+/*
+ * check gda_data_model_set_value_at()
+ *
+ * Returns the number of failures
+ */
+static gint
+test2 (GdaConnection *cnc)
+{
+ GError *error = NULL;
+ GdaDataModel *model;
+ GdaStatement *stmt, *mod_stmt;
+ gint nfailed = 0;
+ GValue *value;
+
+ clear_signals ();
+
+ /* create GdaDataModelQuery */
+ stmt = stmt_from_string ("SELECT * FROM customers");
+ model = (GdaDataModel*) gda_data_model_query_new (cnc, stmt, NULL);
+
+ /* test INSERT with undefined params */
+ mod_stmt = stmt_from_string ("UPDATE customers SET name = ##+1::string, last_update = ##+2::timestamp WHERE id = ##-0::gint");
+ if (!gda_data_model_query_set_modification_statement (GDA_DATA_MODEL_QUERY (model), mod_stmt, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_query_set_modification_statement() should have succedded, error: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+
+ /****/
+ monitor_model_signals (model);
+ g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "Jack");
+ if (! check_set_value_at (model, 1, 0, value, cnc, stmt, NULL)) {
+ nfailed ++;
+ goto out;
+ }
+ if (! check_expected_signal (model, 'U', 0)) {
+ nfailed++;
+ goto out;
+ }
+ gda_value_free (value);
+ clear_signals ();
+
+ /****/
+ gda_value_set_from_string ((value = gda_value_new (GDA_TYPE_TIMESTAMP)),
+ "2009-11-30 11:22:33", GDA_TYPE_TIMESTAMP);
+ if (! check_set_value_at (model, 2, 1, value, cnc, stmt, NULL)) {
+ nfailed ++;
+ goto out;
+ }
+ gda_value_free (value);
+
+ /****/
+ g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "Henry");
+ if (! check_set_value_at (model, 1, 0, value, cnc, stmt, NULL)) {
+ nfailed ++;
+ goto out;
+ }
+ gda_value_free (value);
+
+ /****/
+ if (gda_data_model_set_value_at (model, 0, 0, value, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_set_value_at should have failed\n");
+#endif
+ goto out;
+ }
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Got expected error: %s\n", error && error->message ? error->message : "No detail");
+#endif
+ g_error_free (error);
+ error = NULL;
+
+ GdaDataModel *copy;
+ copy = (GdaDataModel *) gda_data_model_array_copy_model (model, &error);
+ if (!copy) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not copy data model: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+ gda_data_model_dump (model, stdout);
+ gda_data_model_dump (copy, stdout);
+ if (! gda_data_model_query_refresh (GDA_DATA_MODEL_QUERY (model), &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_query_refresh() failed: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+ gda_data_model_dump (model, stdout);
+
+ out:
+ g_object_unref (model);
+ g_object_unref (stmt);
+
+ return nfailed;
+}
+
+
+
+/*
+ * Checking value function:
+ * - reads the value of @model at the provided column and row and compares with the expected @set_value
+ * - if @stmt is not NULL, then re-run the statement and compares with @model
+ */
+static gboolean
+check_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params)
+{
+ GError *error = NULL;
+ gboolean retval;
+ retval = check_set_value_at_ext (model, col, row, set_value, cnc, stmt, stmt_params, &error);
+ if (error)
+ g_error_free (error);
+ return retval;
+}
+
+static gboolean
+check_set_value_at_ext (GdaDataModel *model, gint col, gint row,
+ const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params, GError **error)
+{
+ const GValue *get_value;
+
+ if (! gda_data_model_set_value_at (model, col, row, set_value, error)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_set_value_at(%d,%d) failed: %s\n",
+ col, row,
+ error && *error && (*error)->message ? (*error)->message : "No detail");
+#endif
+ return FALSE;
+ }
+ get_value = gda_data_model_get_value_at (model, col, row, error);
+ if (!get_value) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Can't get data model's value: %s\n",
+ error && *error && (*error)->message ? (*error)->message : "No detail");
+#endif
+ return FALSE;
+ }
+ if (gda_value_compare (get_value, set_value)) {
+#ifdef CHECK_EXTRA_INFO
+ gchar *s1, *s2;
+ s1 = gda_value_stringify (get_value);
+ s2 = gda_value_stringify (set_value);
+ g_print ("gda_data_model_get_value_at(%d,%d) returned '%s' when it should have returned '%s'\n", col, row, s1, s2);
+ g_free (s1);
+ g_free (s2);
+#endif
+ return FALSE;
+ }
+
+ if (stmt) {
+ /* run the statement and compare it with @model */
+ GdaDataModel *rerun;
+ GdaDataComparator *cmp;
+ gboolean cmpres = TRUE;
+ rerun = gda_connection_statement_execute_select (cnc, stmt, stmt_params, error);
+ if (!rerun) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not re-run the SELECT statement: %s\n",
+ error && *error && (*error)->message ? (*error)->message : "No detail");
+#endif
+ return FALSE;
+ }
+
+ cmp = (GdaDataComparator*) gda_data_comparator_new (model, rerun);
+ if (! gda_data_comparator_compute_diff (cmp, error)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not compute the data model differences: %s\n",
+ error && *error && (*error)->message ? (*error)->message : "No detail");
+#endif
+ cmpres = FALSE;
+ }
+ if (gda_data_comparator_get_n_diffs (cmp) != 0) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("There are some differences when re-running the SELECT statement...\n");
+#endif
+ cmpres = FALSE;
+ gda_data_model_dump (model, stdout);
+ gda_data_model_dump (rerun, stdout);
+ if (error) {
+ g_set_error (error, 0, -1,
+ "There are some differences when re-running the SELECT statement...");
+ }
+ }
+ g_object_unref (cmp);
+ g_object_unref (rerun);
+ return cmpres;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Checking value function:
+ * - reads the value of @model at the provided column and row and compares with the expected @set_value
+ * - if @stmt is not NULL, then re-run the statement and compares with @model
+ */
+static gboolean
+check_set_values (GdaDataModel *model, gint row, GList *set_values, GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params)
+{
+ GError *error = NULL;
+ GList *list;
+ gint i;
+
+ if (! gda_data_model_set_values (model, row, set_values, &error)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_set_values (%d) failed: %s\n",
+ row,
+ error && error->message ? error->message : "No detail");
+#endif
+ return FALSE;
+ }
+
+ for (i = 0, list = set_values; list; i++, list = list->next) {
+ const GValue *get_value;
+
+ if (!list->data)
+ continue;
+
+ get_value = gda_data_model_get_value_at (model, i, row, &error);
+ if (!get_value) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Can't get data model's value: %s",
+ error && error->message ? error->message : "No detail");
+#endif
+ return FALSE;
+ }
+ if (gda_value_compare (get_value, (GValue*) list->data)) {
+#ifdef CHECK_EXTRA_INFO
+ gchar *s1, *s2;
+ s1 = gda_value_stringify (get_value);
+ s2 = gda_value_stringify ((GValue*) list->data);
+ g_print ("gda_data_model_get_value_at(%d,%d) returned '%s' when it should have returned '%s'\n", i, row, s1, s2);
+ g_free (s1);
+ g_free (s2);
+#endif
+ return FALSE;
+ }
+ }
+
+ if (stmt) {
+ /* run the statement and compare it with @model */
+ GdaDataModel *rerun;
+ GdaDataComparator *cmp;
+ GError *error = NULL;
+ gboolean cmpres = TRUE;
+ rerun = gda_connection_statement_execute_select (cnc, stmt, stmt_params, &error);
+ if (!rerun) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not re-run the SELECT statement: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ return FALSE;
+ }
+
+ cmp = (GdaDataComparator*) gda_data_comparator_new (model, rerun);
+ if (! gda_data_comparator_compute_diff (cmp, &error)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not compute the data model differences: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ cmpres = FALSE;
+ }
+ if (gda_data_comparator_get_n_diffs (cmp) != 0) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("There are some differences when re-running the SELECT statement...\n");
+#endif
+ cmpres = FALSE;
+ }
+
+ g_object_unref (cmp);
+ g_object_unref (rerun);
+ return cmpres;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Checking value function:
+ * - reads the value of @model at the provided column and row and compares with the expected @set_value
+ * - if @stmt is not NULL, then re-run the statement and compares with @model
+ *
+ * Returns: -1 if an error occurred, or the new row number
+ */
+static gint
+check_append_values (GdaDataModel *model, GList *set_values, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *stmt_params)
+{
+ GError *error = NULL;
+ GList *list;
+ gint i, newrow;
+
+ newrow = gda_data_model_append_values (model, set_values, &error);
+ if (newrow < 0) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_model_append_values () failed: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ return -1;
+ }
+
+ for (i = 0, list = set_values; list; i++, list = list->next) {
+ const GValue *get_value;
+
+ if (!list->data)
+ continue;
+
+ get_value = gda_data_model_get_value_at (model, i, newrow, &error);
+ if (!get_value) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Can't get data model's value: %s",
+ error && error->message ? error->message : "No detail");
+#endif
+ return FALSE;
+ }
+ if (gda_value_compare (get_value, (GValue*) list->data)) {
+#ifdef CHECK_EXTRA_INFO
+ gchar *s1, *s2;
+ s1 = gda_value_stringify (get_value);
+ s2 = gda_value_stringify ((GValue*) list->data);
+ g_print ("gda_data_model_get_value_at(%d,%d) returned '%s' when it should have returned '%s'\n", i,
+ newrow, s1, s2);
+ g_free (s1);
+ g_free (s2);
+#endif
+ return -1;
+ }
+ }
+
+ if (stmt) {
+ /* run the statement and compare it with @model */
+ GdaDataModel *rerun;
+ GdaDataComparator *cmp;
+ GError *error = NULL;
+ rerun = gda_connection_statement_execute_select (cnc, stmt, stmt_params, &error);
+ if (!rerun) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not re-run the SELECT statement: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ return -1;
+ }
+
+ cmp = (GdaDataComparator*) gda_data_comparator_new (model, rerun);
+ if (! gda_data_comparator_compute_diff (cmp, &error)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not compute the data model differences: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ newrow = -1;
+ }
+ if (gda_data_comparator_get_n_diffs (cmp) != 0) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("There are some differences when re-running the SELECT statement...\n");
+#endif
+ newrow = -1;
+ }
+
+ g_object_unref (cmp);
+ g_object_unref (rerun);
+ return newrow;
+ }
+
+ return newrow;
+}
+
+/*
+ * signals checking
+ */
+static void
+monitor_model_signals (GdaDataModel *model)
+{
+ g_signal_connect (model, "row-updated", G_CALLBACK (signal_callback), "U");
+ g_signal_connect (model, "row-removed", G_CALLBACK (signal_callback), "D");
+ g_signal_connect (model, "row-inserted", G_CALLBACK (signal_callback), "I");
+}
+
+static void
+signal_callback (GdaDataModel *model, gint row, gchar *type)
+{
+ SigEvent *se;
+ se = g_new0 (SigEvent, 1);
+ se->model = model;
+ se->type = *type;
+ se->row = row;
+ signals = g_slist_append (signals, se);
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Received '%s' signal for row %d from model %p\n",
+ (*type == 'I') ? "row-inserted" : ((*type == 'D') ? "row-removed" : "row-updated"),
+ row, model);
+#endif
+}
+
+static void
+clear_signals (void)
+{
+ if (signals) {
+ GSList *list;
+ for (list = signals; list; list = list->next) {
+ SigEvent *se = (SigEvent*) list->data;
+ g_free (se);
+ }
+ g_slist_free (signals);
+ signals = NULL;
+ }
+}
+
+static gboolean
+check_expected_signal (GdaDataModel *model, gchar type, gint row)
+{
+ SigEvent *se = NULL;
+ if (signals)
+ se = (SigEvent*) signals->data;
+ if (se && (se->model == model) && (se->row == row) && (se->type == type)) {
+ g_free (se);
+ signals = g_slist_remove (signals, se);
+ return TRUE;
+ }
+#ifdef CHECK_EXTRA_INFO
+ else {
+ g_print ("Expected signal '%s' for row %d from model %p and got ",
+ (type == 'I') ? "row-inserted" : ((type == 'D') ? "row-removed" : "row-updated"),
+ row, model);
+ if (se)
+ g_print ("signal '%s' for row %d from model %p\n",
+ (se->type == 'I') ? "row-inserted" : ((se->type == 'D') ? "row-removed" : "row-updated"),
+ se->row, se->model);
+ else
+ g_print ("no signal\n");
+ }
+#endif
+
+ return FALSE;
+}
+
+static gboolean
+check_no_expected_signal (GdaDataModel *model)
+{
+ SigEvent *se = NULL;
+ if (signals)
+ se = (SigEvent*) signals->data;
+ if (se && (se->model == model)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("No signal expected and got ");
+ if (se)
+ g_print ("signal '%s' for row %d from model %p\n",
+ (se->type == 'I') ? "row-inserted" : ((se->type == 'D') ? "row-removed" : "row-updated"),
+ se->row, se->model);
+ else
+ g_print ("no signal\n");
+#endif
+ return FALSE;
+ }
+
+ return TRUE;
+}
Modified: trunk/tests/data-models/check_pmodel.c
==============================================================================
--- trunk/tests/data-models/check_pmodel.c (original)
+++ trunk/tests/data-models/check_pmodel.c Sun Sep 7 19:06:38 2008
@@ -34,6 +34,9 @@
static gboolean check_set_value_at (GdaDataModel *model, gint col, gint row,
const GValue *set_value,
GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params);
+static gboolean check_set_value_at_ext (GdaDataModel *model, gint col, gint row,
+ const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params, GError **error);
static gboolean check_set_values (GdaDataModel *model, gint row, GList *set_values,
GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params);
static gint check_append_values (GdaDataModel *model, GList *set_values,
@@ -47,6 +50,9 @@
static gint test5 (GdaConnection *cnc);
static gint test6 (GdaConnection *cnc);
static gint test7 (GdaConnection *cnc);
+static gint test8 (GdaConnection *cnc);
+static gint test9 (GdaConnection *cnc);
+static gint test10 (GdaConnection *cnc);
TestFunc tests[] = {
test1,
@@ -55,7 +61,10 @@
test4,
test5,
test6,
- test7
+ test7,
+ test8,
+ test9,
+ test10
};
int
@@ -353,7 +362,7 @@
}
/*
- * check gda_data_model_set_at()
+ * check gda_data_model_set_value_at()
*
* Returns the number of failures
*/
@@ -853,6 +862,240 @@
return nfailed;
}
+/*
+ * check gda_data_model_set_value_at(), modifies the PK
+ *
+ * Returns the number of failures
+ */
+static gint
+test8 (GdaConnection *cnc)
+{
+ GError *error = NULL;
+ GdaDataModel *model;
+ GdaStatement *stmt;
+ gint nfailed = 0;
+ GValue *value;
+
+ clear_signals ();
+
+ /* create GdaDataSelect */
+ stmt = stmt_from_string ("SELECT * FROM customers");
+ model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+ if (!model) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not execute SELECT!\n");
+#endif
+ goto out;
+ }
+ if (!GDA_IS_DATA_SELECT (model)) {
+ g_print ("Data model should be a GdaDataSelect!\n");
+ exit (EXIT_FAILURE);
+ }
+
+ /* test INSERT with undefined params */
+ if (!gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_select_set_modification_statement() should have succedded, error: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+
+ /****/
+ monitor_model_signals (model);
+ g_value_set_int ((value = gda_value_new (G_TYPE_INT)), 102);
+ if (! check_set_value_at (model, 0, 4, value, cnc, stmt, NULL)) {
+ nfailed ++;
+ goto out;
+ }
+ if (! check_expected_signal (model, 'U', 4)) {
+ nfailed++;
+ goto out;
+ }
+ gda_value_free (value);
+ clear_signals ();
+
+ out:
+ g_object_unref (model);
+ g_object_unref (stmt);
+
+ return nfailed;
+}
+
+/*
+ * check modifications statements' setting, with external parameter
+ * the modification makes the row 'disappear' from the data model
+ *
+ * Returns the number of failures
+ */
+static gint
+test9 (GdaConnection *cnc)
+{
+ GError *error = NULL;
+ GdaDataModel *model;
+ GdaStatement *stmt;
+ gint nfailed = 0;
+ GdaSet *params;
+ GValue *value;
+
+ clear_signals ();
+
+ /* create GdaDataSelect */
+ stmt = stmt_from_string ("SELECT * FROM customers WHERE country = ##country::string");
+ if (!gda_statement_get_parameters (stmt, ¶ms, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not get SELECT's parameters!\n");
+#endif
+ goto out;
+ }
+ if (! gda_set_set_holder_value (params, &error, "country", "SP")) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not get SELECT's parameters!\n");
+#endif
+ goto out;
+ }
+ model = gda_connection_statement_execute_select (cnc, stmt, params, &error);
+ if (!model) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not execute SELECT!\n");
+#endif
+ goto out;
+ }
+ if (!GDA_IS_DATA_SELECT (model)) {
+ g_print ("Data model should be a GdaDataSelect!\n");
+ exit (EXIT_FAILURE);
+ }
+
+
+ /* gda_data_select_compute_modification_statements() */
+ if (!gda_data_select_compute_modification_statements (GDA_DATA_SELECT (model), &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("gda_data_select_compute_modification_statements() should have succedded, error: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+
+ monitor_model_signals (model);
+ g_value_set_string ((value = gda_value_new (G_TYPE_STRING)), "UK");
+ if (! check_set_value_at_ext (model, 4, 1, value, cnc, stmt, params, &error)) {
+ if (error && (error->domain == 0) && (error->code == -1)) {
+#ifdef CHECK_EXTRA_INFO
+ g_print ("This error was expected (modified row would not have been in the SELECT)\n");
+#endif
+ }
+ else {
+ nfailed ++;
+ goto out;
+ }
+ }
+ if (! check_expected_signal (model, 'U', 1)) {
+ nfailed++;
+ goto out;
+ }
+ gda_value_free (value);
+ clear_signals ();
+
+ out:
+ g_object_unref (model);
+ g_object_unref (stmt);
+ g_object_unref (params);
+
+ return nfailed;
+}
+
+
+/*
+ * Simple data model copy
+ *
+ * Returns the number of failures
+ */
+static gint
+test10 (GdaConnection *cnc)
+{
+ GError *error = NULL;
+ GdaDataModel *model, *copy;
+ GdaStatement *stmt;
+ gint nfailed = 0;
+ GdaSet *params;
+
+ clear_signals ();
+
+ /* create GdaDataSelect */
+ stmt = stmt_from_string ("SELECT * FROM customers WHERE country = ##country::string");
+ if (!gda_statement_get_parameters (stmt, ¶ms, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not get SELECT's parameters!\n");
+#endif
+ goto out;
+ }
+ if (! gda_set_set_holder_value (params, &error, "country", "SP")) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not get SELECT's parameters!\n");
+#endif
+ goto out;
+ }
+ model = gda_connection_statement_execute_select (cnc, stmt, params, &error);
+ if (!model) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not execute SELECT!\n");
+#endif
+ goto out;
+ }
+ if (!GDA_IS_DATA_SELECT (model)) {
+ g_print ("Data model should be a GdaDataSelect!\n");
+ exit (EXIT_FAILURE);
+ }
+
+ copy = (GdaDataModel*) gda_data_model_array_copy_model (model, &error);
+ if (!copy) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not copy GdaDataSelect, error: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+
+ GdaDataComparator *cmp;
+ cmp = (GdaDataComparator*) gda_data_comparator_new (model, copy);
+ if (! gda_data_comparator_compute_diff (cmp, &error)) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("Could not compute the data model differences: %s\n",
+ error && error->message ? error->message : "No detail");
+#endif
+ goto out;
+ }
+ if (gda_data_comparator_get_n_diffs (cmp) != 0) {
+ nfailed++;
+#ifdef CHECK_EXTRA_INFO
+ g_print ("There are some differences whith the copied data model ...\n");
+#endif
+ gda_data_model_dump (model, stdout);
+ gda_data_model_dump (copy, stdout);
+ goto out;
+ }
+ g_object_unref (cmp);
+ g_object_unref (copy);
+
+ out:
+ g_object_unref (model);
+ g_object_unref (stmt);
+ g_object_unref (params);
+
+ return nfailed;
+}
+
/*
* Checking value function:
@@ -863,22 +1106,34 @@
check_set_value_at (GdaDataModel *model, gint col, gint row, const GValue *set_value,
GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params)
{
- const GValue *get_value;
GError *error = NULL;
+ gboolean retval;
+ retval = check_set_value_at_ext (model, col, row, set_value, cnc, stmt, stmt_params, &error);
+ if (error)
+ g_error_free (error);
+ return retval;
+}
- if (! gda_data_model_set_value_at (model, col, row, set_value, &error)) {
+static gboolean
+check_set_value_at_ext (GdaDataModel *model, gint col, gint row,
+ const GValue *set_value,
+ GdaConnection *cnc, GdaStatement *stmt, GdaSet *stmt_params, GError **error)
+{
+ const GValue *get_value;
+
+ if (! gda_data_model_set_value_at (model, col, row, set_value, error)) {
#ifdef CHECK_EXTRA_INFO
g_print ("gda_data_model_set_value_at(%d,%d) failed: %s\n",
col, row,
- error && error->message ? error->message : "No detail");
+ error && *error && (*error)->message ? (*error)->message : "No detail");
#endif
return FALSE;
}
- get_value = gda_data_model_get_value_at (model, col, row, &error);
+ get_value = gda_data_model_get_value_at (model, col, row, error);
if (!get_value) {
#ifdef CHECK_EXTRA_INFO
- g_print ("Can't get data model's value: %s",
- error && error->message ? error->message : "No detail");
+ g_print ("Can't get data model's value: %s\n",
+ error && *error && (*error)->message ? (*error)->message : "No detail");
#endif
return FALSE;
}
@@ -898,22 +1153,21 @@
/* run the statement and compare it with @model */
GdaDataModel *rerun;
GdaDataComparator *cmp;
- GError *error = NULL;
gboolean cmpres = TRUE;
- rerun = gda_connection_statement_execute_select (cnc, stmt, stmt_params, &error);
+ rerun = gda_connection_statement_execute_select (cnc, stmt, stmt_params, error);
if (!rerun) {
#ifdef CHECK_EXTRA_INFO
g_print ("Could not re-run the SELECT statement: %s\n",
- error && error->message ? error->message : "No detail");
+ error && *error && (*error)->message ? (*error)->message : "No detail");
#endif
return FALSE;
}
cmp = (GdaDataComparator*) gda_data_comparator_new (model, rerun);
- if (! gda_data_comparator_compute_diff (cmp, &error)) {
+ if (! gda_data_comparator_compute_diff (cmp, error)) {
#ifdef CHECK_EXTRA_INFO
g_print ("Could not compute the data model differences: %s\n",
- error && error->message ? error->message : "No detail");
+ error && *error && (*error)->message ? (*error)->message : "No detail");
#endif
cmpres = FALSE;
}
@@ -922,6 +1176,12 @@
g_print ("There are some differences when re-running the SELECT statement...\n");
#endif
cmpres = FALSE;
+ gda_data_model_dump (model, stdout);
+ gda_data_model_dump (rerun, stdout);
+ if (error) {
+ g_set_error (error, 0, -1,
+ "There are some differences when re-running the SELECT statement...");
+ }
}
g_object_unref (cmp);
g_object_unref (rerun);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]