[libgda] MySQL provider: handle selection statements in case the prepare step does not work
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] MySQL provider: handle selection statements in case the prepare step does not work
- Date: Thu, 4 Nov 2010 20:07:39 +0000 (UTC)
commit 58d846973a3b74e6aba66859862026f5741e7989
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 6ac52dc..0201eaa 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -1397,6 +1397,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 6e749fb..f8512df 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 2f825c3..76c36bc 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -2125,8 +2125,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;
@@ -2527,6 +2537,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]