[libgda/gtk3] MySQL provider: handle selection statements in case the prepare step does not work



commit 938cbb0da6f32b7dfd73b8c5779ccc9392203f74
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sat Oct 30 21:13:23 2010 +0200

    MySQL provider: handle selection statements in case the prepare step does not work
    
    following work in commit #fe504de1a4991b454571bf9c8959b069c6ea141b

 doc/C/libgda-sections.txt                       |    1 +
 doc/C/tmpl/gda-data-select-priv.sgml            |    9 ++
 libgda/gda-data-select.c                        |   28 ++++-
 libgda/libgda.symbols                           |    1 +
 libgda/providers-support/gda-data-select-priv.h |    2 +-
 providers/mysql/gda-mysql-provider.c            |   15 ++-
 providers/mysql/gda-mysql-recordset.c           |  146 +++++++++++++++++++++--
 providers/mysql/gda-mysql-recordset.h           |   30 ++---
 8 files changed, 201 insertions(+), 31 deletions(-)
---
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index 8dd5256..d15cee1 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -1396,6 +1396,7 @@ GdaDataSelectClass
 gda_data_select_take_row
 gda_data_select_get_stored_row
 gda_data_select_get_connection
+gda_data_select_set_columns
 <SUBSECTION>
 gda_column_set_name
 gda_column_set_description
diff --git a/doc/C/tmpl/gda-data-select-priv.sgml b/doc/C/tmpl/gda-data-select-priv.sgml
index d8f23a4..68752b7 100644
--- a/doc/C/tmpl/gda-data-select-priv.sgml
+++ b/doc/C/tmpl/gda-data-select-priv.sgml
@@ -80,6 +80,15 @@ Base class for all the data models returned by DBMS providers when a SELECT stat
 @Returns: 
 
 
+<!-- ##### FUNCTION gda_data_select_set_columns ##### -->
+<para>
+
+</para>
+
+ model: 
+ columns: 
+
+
 <!-- ##### FUNCTION gda_column_set_name ##### -->
 <para>
 
diff --git a/libgda/gda-data-select.c b/libgda/gda-data-select.c
index 2e7f7b9..75cd817 100644
--- a/libgda/gda-data-select.c
+++ b/libgda/gda-data-select.c
@@ -824,6 +824,32 @@ gda_data_select_get_connection (GdaDataSelect *model)
 	return model->priv->cnc;
 }
 
+/**
+ * gda_data_select_set_columns
+ * @model: a #GdaDataSelect data model
+ * @columns: (transfer full): a lis of #GdaColumn objects
+ *
+ * Makes @columns the list of columns for @model. Both the list and each #GdaColumn object in the
+ * list are 'stolen' by @model (ie. when this function returns the caller should not use anymore
+ * the list or each column object in it). This method should not be used directly, it is used by
+ * database provider's implementations.
+ *
+ * Since: 4.2.1
+ */
+void
+gda_data_select_set_columns (GdaDataSelect *model, GSList *columns)
+{
+	g_return_if_fail (GDA_IS_DATA_SELECT (model));
+	g_return_if_fail (model->priv);
+
+	if (model->priv->sh->columns) {
+		g_slist_foreach (model->priv->sh->columns, (GFunc) g_object_unref, NULL);
+		g_slist_free (model->priv->sh->columns);
+		model->priv->sh->columns = NULL;
+	}
+	model->priv->sh->columns = columns;
+}
+
 /*
  * Add the +/-<col num> holders to model->priv->sh->modif_internals->modif_set
  */
@@ -1576,7 +1602,7 @@ gda_data_select_get_n_columns (GdaDataModel *model)
 	if (imodel->prep_stmt)
 		return imodel->prep_stmt->ncols;
 	else
-		return 0;
+		return g_slist_length (imodel->priv->sh->columns);
 }
 
 static GdaColumn *
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index a3f4d05..b8dc296 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -310,6 +310,7 @@
 	gda_data_select_get_stored_row
 	gda_data_select_get_type
 	gda_data_select_rerun
+	gda_data_select_set_columns
 	gda_data_select_set_modification_statement
 	gda_data_select_set_modification_statement_sql
 	gda_data_select_set_row_selection_condition
diff --git a/libgda/providers-support/gda-data-select-priv.h b/libgda/providers-support/gda-data-select-priv.h
index b8c631f..a05501b 100644
--- a/libgda/providers-support/gda-data-select-priv.h
+++ b/libgda/providers-support/gda-data-select-priv.h
@@ -38,7 +38,7 @@ GType          gda_data_select_get_type                     (void) G_GNUC_CONST;
 void           gda_data_select_take_row                     (GdaDataSelect *model, GdaRow *row, gint rownum);
 GdaRow        *gda_data_select_get_stored_row               (GdaDataSelect *model, gint rownum);
 GdaConnection *gda_data_select_get_connection               (GdaDataSelect *model);
-
+void           gda_data_select_set_columns                  (GdaDataSelect *model, GSList *columns);
 
 /* internal API */
 void           _gda_data_select_share_private_data (GdaDataSelect *master, GdaDataSelect *slave);
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index 3a45fce..0722d1a 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -2123,8 +2123,18 @@ gda_mysql_provider_statement_execute (GdaServerProvider               *provider,
 					/* Create GdaConnectionEvent notice with the type of command and impacted rows */
 					affected_rows = mysql_affected_rows (cdata->mysql);
 					if (affected_rows == (my_ulonglong)~0) {
-						TO_IMPLEMENT;
-						return (GObject *) gda_data_model_array_new (0);
+						GdaDataModelAccessFlags flags;
+						
+						if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
+							flags = GDA_DATA_MODEL_ACCESS_RANDOM;
+						else
+							flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+						gda_connection_internal_statement_executed (cnc, stmt,
+											    NULL, NULL); /* required: help @cnc keep some stats */
+
+						return (GObject *) gda_mysql_recordset_new_direct (cnc,
+												   flags,
+												   col_types);
 					}
 					else {
 						gchar *str;
@@ -2525,6 +2535,7 @@ gda_mysql_provider_statement_execute (GdaServerProvider               *provider,
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SHOW", 4) ||
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "DESCRIBE", 8) ||
+		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXECUTE", 7) ||
 		    !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
 			if (mysql_stmt_store_result (ps->mysql_stmt)) {
 				_gda_mysql_make_error (cnc, NULL, ps->mysql_stmt, error);
diff --git a/providers/mysql/gda-mysql-recordset.c b/providers/mysql/gda-mysql-recordset.c
index 6200245..ad88014 100644
--- a/providers/mysql/gda-mysql-recordset.c
+++ b/providers/mysql/gda-mysql-recordset.c
@@ -1,5 +1,5 @@
 /* GDA Mysql provider
- * Copyright (C) 2008 - 2009 The GNOME Foundation.
+ * Copyright (C) 2008 - 2010 The GNOME Foundation.
  *
  * AUTHORS:
  *      Carlos Savoretti <csavoretti gmail com>
@@ -26,6 +26,7 @@
 #include <glib/gi18n-lib.h>
 #include <libgda/gda-util.h>
 #include <libgda/gda-connection-private.h>
+#include <libgda/providers-support/gda-data-select-priv.h>
 #include "gda-mysql.h"
 #include "gda-mysql-recordset.h"
 #include "gda-mysql-provider.h"
@@ -78,13 +79,16 @@ gda_mysql_recordset_fetch_at (GdaDataSelect  *model,
 
 struct _GdaMysqlRecordsetPrivate {
 	GdaConnection  *cnc;
-	/* TO_ADD: specific information */
 	
 	MYSQL_STMT     *mysql_stmt;
 
 	gint            chunk_size;    /* Number of rows to fetch at a time when iterating forward/backward. */
 	gint            chunks_read;   /* Number of times that we've iterated forward/backward. */
 	GdaRow         *tmp_row;       /* Used in cursor mode to store a reference to the latest #GdaRow. */
+
+	/* if no prepared statement available */
+	gint          ncols;
+        GType        *types;
 };
 static GObjectClass *parent_class = NULL;
 
@@ -100,9 +104,11 @@ gda_mysql_recordset_init (GdaMysqlRecordset       *recset,
 	recset->priv->cnc = NULL;
 
 	/* initialize specific information */
-	// TO_IMPLEMENT;
 	recset->priv->chunk_size = 1;
 	recset->priv->chunks_read = 0;
+
+	recset->priv->ncols = 0;
+	recset->priv->types = NULL;
 }
 
 
@@ -254,9 +260,9 @@ gda_mysql_recordset_dispose (GObject  *object)
 			g_object_unref (G_OBJECT(recset->priv->tmp_row));
 			recset->priv->tmp_row = NULL;
 		}
+		if (recset->priv->types)
+			g_free (recset->priv->types);
 
-		/* free specific information */
-		// TO_IMPLEMENT;
 		g_free (recset->priv);
 		recset->priv = NULL;
 	}
@@ -378,6 +384,133 @@ _gda_mysql_type_to_gda (MysqlConnectionData *cdata,
 	return gtype;
 }
 
+GdaDataModel *
+gda_mysql_recordset_new_direct (GdaConnection *cnc, GdaDataModelAccessFlags flags, 
+				GType *col_types)
+{
+	GdaMysqlRecordset *model;
+        MysqlConnectionData *cdata;
+        gint i;
+	GdaDataModelAccessFlags rflags;
+	GSList *columns = NULL;
+
+        g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+
+	cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return NULL;
+
+	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
+	if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
+		rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
+	else
+		rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+
+	/* create data model */
+        model = g_object_new (GDA_TYPE_MYSQL_RECORDSET,
+			      "connection", cnc,
+			      "model-usage", rflags,
+			      NULL);
+        model->priv->cnc = cnc;
+	g_object_ref (G_OBJECT(cnc));
+
+	/* columns & types */	
+	model->priv->ncols = mysql_field_count (cdata->mysql);
+	model->priv->types = g_new0 (GType, model->priv->ncols);
+	
+	/* create columns */
+	for (i = 0; i < model->priv->ncols; i++)
+		columns = g_slist_prepend (columns, gda_column_new ());
+	columns = g_slist_reverse (columns);
+
+	if (col_types) {
+		for (i = 0; ; i++) {
+			if (col_types [i] > 0) {
+				if (col_types [i] == G_TYPE_NONE)
+					break;
+				if (i >= model->priv->ncols) {
+					g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i,
+						   model->priv->ncols - 1);
+					break;
+				}
+				else
+					model->priv->types [i] = col_types [i];
+			}
+		}
+	}
+
+	/* fill bind result */
+	MYSQL_RES *mysql_res = mysql_store_result (cdata->mysql);
+	MYSQL_FIELD *mysql_fields = mysql_fetch_fields (mysql_res);
+	GSList *list;
+
+	((GdaDataSelect *) model)->advertized_nrows = mysql_affected_rows (cdata->mysql);
+	for (i=0, list = columns; 
+	     i < model->priv->ncols; 
+	     i++, list = list->next) {
+		GdaColumn *column = GDA_COLUMN (list->data);
+		
+		/* use C API to set columns' information using gda_column_set_*() */
+		MYSQL_FIELD *field = &mysql_fields[i];
+		
+		GType gtype = model->priv->types [i];
+		if (gtype == 0) {
+			gtype = _gda_mysql_type_to_gda (cdata, field->type, field->charsetnr);
+			model->priv->types [i] = gtype;
+		}
+		gda_column_set_g_type (column, gtype);
+		gda_column_set_name (column, field->name);
+		gda_column_set_description (column, field->name);
+	}
+	gda_data_select_set_columns (GDA_DATA_SELECT (model), columns);
+
+	/* load ALL data */
+	MYSQL_ROW mysql_row;
+	gint rownum;
+	GdaServerProvider *prov;
+	prov = gda_connection_get_provider (cnc);
+	for (mysql_row = mysql_fetch_row (mysql_res), rownum = 0;
+	     mysql_row;
+	     mysql_row = mysql_fetch_row (mysql_res), rownum++) {
+		GdaRow *row = gda_row_new (model->priv->ncols);
+		gint col;
+		for (col = 0; col < model->priv->ncols; col++) {
+			gint i = col;
+		
+			GValue *value = gda_row_get_value (row, i);
+			GType type = model->priv->types[i];
+			char *data = mysql_row[i];
+
+			if (!data || (type == GDA_TYPE_NULL))
+				continue;
+
+			gda_value_reset_with_type (value, type);
+			if (type == G_TYPE_STRING)
+				g_value_set_string (value, data);
+			else {
+				GdaDataHandler *dh;
+				gboolean valueset = FALSE;
+				dh = gda_server_provider_get_data_handler_g_type (prov, cnc, type);
+				if (dh) {
+					GValue *tmpvalue;
+					tmpvalue = gda_data_handler_get_value_from_str (dh, data, type);
+					if (tmpvalue) {
+						*value = *tmpvalue;
+						g_free (tmpvalue);
+						valueset = TRUE;
+					}
+				}
+				if (!valueset)
+					gda_row_invalidate_value (row, value);
+			}
+		}
+		gda_data_select_take_row ((GdaDataSelect*) model, row, rownum);
+	}
+	mysql_free_result (mysql_res);
+
+        return GDA_DATA_MODEL (model);
+}
+
 
 /*
  * the @ps struct is modified and transferred to the new data model created in
@@ -545,9 +678,6 @@ gda_mysql_recordset_new (GdaConnection            *cnc,
         model->priv->cnc = cnc;
 	g_object_ref (G_OBJECT(cnc));
 
-	/* post init specific code */
-	// TO_IMPLEMENT;
-	
 	model->priv->mysql_stmt = ps->mysql_stmt;
 
 	((GdaDataSelect *) model)->advertized_nrows = mysql_stmt_affected_rows (ps->mysql_stmt);
diff --git a/providers/mysql/gda-mysql-recordset.h b/providers/mysql/gda-mysql-recordset.h
index 472a0bb..8fc260f 100644
--- a/providers/mysql/gda-mysql-recordset.h
+++ b/providers/mysql/gda-mysql-recordset.h
@@ -1,8 +1,9 @@
 /* GDA Mysql provider
- * Copyright (C) 2008 The GNOME Foundation.
+ * Copyright (C) 2008 - 2010 The GNOME Foundation.
  *
  * AUTHORS:
  *      Carlos Savoretti <csavoretti gmail com>
+ *      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
@@ -48,25 +49,16 @@ struct _GdaMysqlRecordsetClass {
 	GdaDataSelectClass         parent_class;
 };
 
-GType
-gda_mysql_recordset_get_type  (void) G_GNUC_CONST;
-GdaDataModel *
-gda_mysql_recordset_new       (GdaConnection            *cnc,
-			       GdaMysqlPStmt            *ps,
-			       GdaSet                   *exec_params,
-			       GdaDataModelAccessFlags   flags, 
-			       GType                    *col_types);
+GType gda_mysql_recordset_get_type  (void) G_GNUC_CONST;
+GdaDataModel *gda_mysql_recordset_new       (GdaConnection *cnc, GdaMysqlPStmt *ps,
+					     GdaSet *exec_params, GdaDataModelAccessFlags flags, 
+					     GType *col_types);
+GdaDataModel *gda_mysql_recordset_new_direct (GdaConnection *cnc, GdaDataModelAccessFlags flags, 
+					      GType *col_types);
 
-
-gint
-gda_mysql_recordset_get_chunk_size (GdaMysqlRecordset  *recset);
-
-void
-gda_mysql_recordset_set_chunk_size (GdaMysqlRecordset  *recset,
-				    gint                chunk_size);
-
-gint
-gda_mysql_recordset_get_chunks_read (GdaMysqlRecordset  *recset);
+gint gda_mysql_recordset_get_chunk_size (GdaMysqlRecordset  *recset);
+void gda_mysql_recordset_set_chunk_size (GdaMysqlRecordset  *recset, gint chunk_size);
+gint gda_mysql_recordset_get_chunks_read (GdaMysqlRecordset  *recset);
 
 G_END_DECLS
 



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