[libgda] GdaBrowser: actually execute statements



commit 4b0809fc9d1ec865f973cc77c44ba4484358eabc
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sun Sep 6 22:15:18 2009 +0200

    GdaBrowser: actually execute statements
    
    the results are not yet browsable and are dumped
    to SDTOUT for now.

 tools/browser/browser-connection.c             |   76 ++++++++
 tools/browser/browser-connection.h             |   12 ++-
 tools/browser/doc/gda-browser-sections.txt     |    3 +
 tools/browser/doc/tmpl/browser-connection.sgml |   36 ++++
 tools/browser/query-exec/query-console.c       |  222 +++++++++++++++++++++---
 tools/browser/query-exec/query-editor.c        |   17 ++-
 6 files changed, 335 insertions(+), 31 deletions(-)
---
diff --git a/tools/browser/browser-connection.c b/tools/browser/browser-connection.c
index 6fe8c5f..2aeb4a5 100644
--- a/tools/browser/browser-connection.c
+++ b/tools/browser/browser-connection.c
@@ -675,3 +675,79 @@ browser_connection_create_parser (BrowserConnection *bcnc)
 		parser = gda_sql_parser_new ();
 	return parser;
 }
+
+/**
+ * browser_connection_render_pretty_sql
+ * @bcnc: a #BrowserConnection
+ * @stmt: a #GdaStatement
+ *
+ * Renders @stmt as SQL well indented
+ *
+ * Returns: a new string
+ */
+gchar *
+browser_connection_render_pretty_sql (BrowserConnection *bcnc, GdaStatement *stmt)
+{
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+
+	return gda_statement_to_sql_extended (stmt, bcnc->priv->cnc, NULL,
+					      GDA_STATEMENT_SQL_PRETTY |
+					      GDA_STATEMENT_SQL_PARAMS_SHORT,
+					      NULL, NULL);
+}
+
+/**
+ * browser_connection_execute_statement
+ * @bcnc: a #BrowserConnection
+ * @stmt: a #GdaStatement
+ * @params: a #GdaSet as parameters, or %NULL
+ * @model_usage: how the returned data model (if any) will be used
+ * @need_last_insert_row: %TRUE if the values of the last interted row must be computed
+ * @error: a place to store errors, or %NULL
+ *
+ * Executes @stmt by @bcnc
+ *
+ * Returns: a job ID, to be used with browser_connection_execution_get_result(), or %0 if an
+ * error occurred
+ */
+guint
+browser_connection_execute_statement (BrowserConnection *bcnc,
+				      GdaStatement *stmt,
+				      GdaSet *params,
+				      GdaStatementModelUsage model_usage,
+				      gboolean need_last_insert_row,
+				      GError **error)
+{
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), 0);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), 0);
+	g_return_val_if_fail (!params || GDA_IS_SET (params), 0);
+
+	return gda_connection_async_statement_execute (bcnc->priv->cnc, stmt,
+						       params, model_usage,
+						       NULL, need_last_insert_row,
+						       error);
+}
+
+/**
+ * browser_connection_execution_get_result
+ * @bcnc: a #BrowserConnection
+ * @exec_id: the ID of the excution
+ * @last_insert_row: a place to store the last inserted row, if any, or %NULL
+ * @error: a place to store errors, or %NULL
+ *
+ * Pick up the result of the @exec_id's execution.
+ *
+ * Retunrs: see gda_connection_async_fetch_result()
+ */
+GObject *
+browser_connection_execution_get_result (BrowserConnection *bcnc, guint exec_id,
+					 GdaSet **last_insert_row, GError **error)
+{
+	g_return_val_if_fail (BROWSER_IS_CONNECTION (bcnc), NULL);
+	g_return_val_if_fail (exec_id > 0, NULL);
+	
+	return gda_connection_async_fetch_result (bcnc->priv->cnc, exec_id,
+						  last_insert_row,
+						  error);
+}
diff --git a/tools/browser/browser-connection.h b/tools/browser/browser-connection.h
index b6f95e4..c9b03db 100644
--- a/tools/browser/browser-connection.h
+++ b/tools/browser/browser-connection.h
@@ -71,7 +71,17 @@ BrowserFavorites   *browser_connection_get_favorites          (BrowserConnection
  * statements's execution
  */
 GdaSqlParser       *browser_connection_create_parser          (BrowserConnection *bcnc);
-/* TODO */
+gchar              *browser_connection_render_pretty_sql      (BrowserConnection *bcnc,
+							       GdaStatement *stmt);
+guint               browser_connection_execute_statement      (BrowserConnection *bcnc,
+							       GdaStatement *stmt,
+							       GdaSet *params,
+							       GdaStatementModelUsage model_usage,
+							       gboolean need_last_insert_row,
+							       GError **error);
+GObject            *browser_connection_execution_get_result   (BrowserConnection *bcnc,
+							       guint exec_id,
+							       GdaSet **last_insert_row, GError **error);
 
 G_END_DECLS
 
diff --git a/tools/browser/doc/gda-browser-sections.txt b/tools/browser/doc/gda-browser-sections.txt
index 41b6f39..6df6895 100644
--- a/tools/browser/doc/gda-browser-sections.txt
+++ b/tools/browser/doc/gda-browser-sections.txt
@@ -151,6 +151,9 @@ browser_connection_get_meta_store
 browser_connection_get_dictionary_file
 browser_connection_get_favorites
 browser_connection_create_parser
+browser_connection_render_pretty_sql
+browser_connection_execute_statement
+browser_connection_execution_get_result
 <SUBSECTION Standard>
 BROWSER_CONNECTION
 BROWSER_IS_CONNECTION
diff --git a/tools/browser/doc/tmpl/browser-connection.sgml b/tools/browser/doc/tmpl/browser-connection.sgml
index 534ff21..1a85fb2 100644
--- a/tools/browser/doc/tmpl/browser-connection.sgml
+++ b/tools/browser/doc/tmpl/browser-connection.sgml
@@ -144,3 +144,39 @@ An opened connection
 @Returns: 
 
 
+<!-- ##### FUNCTION browser_connection_render_pretty_sql ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ stmt: 
+ Returns: 
+
+
+<!-- ##### FUNCTION browser_connection_execute_statement ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ stmt: 
+ params: 
+ model_usage: 
+ need_last_insert_row: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION browser_connection_execution_get_result ##### -->
+<para>
+
+</para>
+
+ bcnc: 
+ exec_id: 
+ last_insert_row: 
+ error: 
+ Returns: 
+
+
diff --git a/tools/browser/query-exec/query-console.c b/tools/browser/query-exec/query-console.c
index ef7a149..53c0546 100644
--- a/tools/browser/query-exec/query-console.c
+++ b/tools/browser/query-exec/query-console.c
@@ -45,6 +45,62 @@
 			 "Valid types are: <tt>string</tt>, <tt>boolean</tt>, <tt>int</tt>,\n" \
 			 "<tt>date</tt>, <tt>time</tt>, <tt>timestamp</tt>, <tt>guint</tt></small>")
 
+/*
+ * Statement execution structures
+ */
+typedef struct {
+	GTimeVal start_time;
+	GdaBatch *batch; /* ref held here */
+	QueryEditorHistoryBatch *hist_batch; /* ref held here */
+	GSList *statements; /* list of ExecutionStatament */
+} ExecutionBatch;
+static void execution_batch_free (ExecutionBatch *ebatch);
+
+typedef struct {
+	GdaStatement *stmt /* no ref held here */;
+	GError *exec_error;
+	GObject *result;
+	guint exec_id; /* 0 when execution not requested */
+} ExecutionStatement;
+static void execution_statement_free (ExecutionStatement *estmt);
+
+/*
+ * Frees an @ExecutionBatch
+ *
+ * If necessary, may set up and idle handler to perform some
+ * additionnal jobs
+ */
+static void
+execution_batch_free (ExecutionBatch *ebatch)
+{
+	GSList *list;
+	for (list = ebatch->statements; list; list = list->next)
+		execution_statement_free ((ExecutionStatement*) list->data);
+	g_slist_free (ebatch->statements);
+
+	g_object_unref (ebatch->batch);
+	if (ebatch->hist_batch)
+		query_editor_history_batch_unref (ebatch->hist_batch);
+
+	g_free (ebatch);
+}
+
+static void
+execution_statement_free (ExecutionStatement *estmt)
+{
+	if (estmt->exec_id > 0) {
+		/* job started => set up idle task */
+		TO_IMPLEMENT;
+	}
+	else {
+		if (estmt->exec_error)
+			g_error_free (estmt->exec_error);
+		if (estmt->result)
+			g_object_unref (estmt->result);
+		g_free (estmt);
+	}
+}
+
 struct _QueryConsolePrivate {
 	BrowserConnection *bcnc;
 	GdaSqlParser *parser;
@@ -66,6 +122,9 @@ struct _QueryConsolePrivate {
 	QueryEditor *history;
 	GtkWidget *history_del_button;
 	GtkWidget *history_copy_button;
+
+	ExecutionBatch *current_exec;
+	guint current_exec_id; /* timout ID to fetch execution results */
 };
 
 static void query_console_class_init (QueryConsoleClass *klass);
@@ -139,6 +198,10 @@ query_console_dispose (GObject *object)
 
 	/* free memory */
 	if (tconsole->priv) {
+		if (tconsole->priv->current_exec_id)
+			g_source_remove (tconsole->priv->current_exec_id);
+		if (tconsole->priv->current_exec)
+			execution_batch_free (tconsole->priv->current_exec);
 		if (tconsole->priv->bcnc)
 			g_object_unref (tconsole->priv->bcnc);
 		if (tconsole->priv->parser)
@@ -616,11 +679,8 @@ sql_indent_clicked_cb (GtkButton *button, QueryConsole *tconsole)
 		stmt_list = gda_batch_get_statements (batch);
 		string = g_string_new ("");
 		for (list = stmt_list; list; list = list->next) {
-			GError *error = NULL;
-			sql = gda_statement_to_sql_extended (GDA_STATEMENT (list->data), NULL, NULL,
-							     GDA_STATEMENT_SQL_PRETTY |
-							     GDA_STATEMENT_SQL_PARAMS_SHORT,
-							     NULL, &error);
+			sql = browser_connection_render_pretty_sql (tconsole->priv->bcnc,
+								    GDA_STATEMENT (list->data));
 			if (!sql)
 				sql = gda_statement_to_sql (GDA_STATEMENT (list->data), NULL, NULL);
 			if (list != stmt_list)
@@ -672,6 +732,8 @@ params_form_changed_cb (GdauiBasicForm *form, GdaHolder *param, gboolean is_user
 				  gdaui_basic_form_is_valid (form));
 }
 
+static gboolean query_exec_fetch_cb (QueryConsole *tconsole);
+
 static void
 sql_execute_clicked_cb (GtkButton *button, QueryConsole *tconsole)
 {
@@ -765,34 +827,144 @@ sql_execute_clicked_cb (GtkButton *button, QueryConsole *tconsole)
 	}
 	g_free (sql);
 
-	QueryEditorHistoryBatch *hbatch;
-	GTimeVal tv;
-	g_get_current_time (&tv);
-	hbatch = query_editor_history_batch_new (tv);
-	query_editor_start_history_batch (tconsole->priv->history, hbatch);
-	query_editor_history_batch_unref (hbatch);
+	/* if a query is being executed, then show an error */
+	if (tconsole->priv->current_exec) {
+		g_object_unref (batch);
+		browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
+				    _("A query is already being executed, "
+				      "to execute another query, open a new connection."));
+		return;
+	}
 
+	/* actual Execution */
 	const GSList *stmt_list, *list;
+	ExecutionBatch *ebatch;
+	ebatch = g_new0 (ExecutionBatch, 1);
+	ebatch->batch = batch;
+	g_get_current_time (&(ebatch->start_time));
+	ebatch->hist_batch = query_editor_history_batch_new (ebatch->start_time);
+	query_editor_start_history_batch (tconsole->priv->history, ebatch->hist_batch);
+
 	stmt_list = gda_batch_get_statements (batch);
 	for (list = stmt_list; list; list = list->next) {
-		QueryEditorHistoryItem *history;
-		GdaSqlStatement *sqlst;
-		g_object_get (G_OBJECT (list->data), "structure", &sqlst, NULL);
-		if (!sqlst->sql) {
-			sql = gda_statement_to_sql (GDA_STATEMENT (list->data), NULL, NULL);
-			history = query_editor_history_item_new (sql, NULL, NULL);
-			g_free (sql);
+		ExecutionStatement *estmt;
+		estmt = g_new0 (ExecutionStatement, 1);
+		estmt->stmt = GDA_STATEMENT (list->data);
+		ebatch->statements = g_slist_prepend (ebatch->statements, estmt);
+
+		if (list == stmt_list) {
+			estmt->exec_id = browser_connection_execute_statement (tconsole->priv->bcnc,
+									       estmt->stmt,
+									       tconsole->priv->params,
+									       GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+									       FALSE, &(estmt->exec_error));
+			g_print ("Executing: %u\n", estmt->exec_id);
+			if (estmt->exec_id == 0) {
+				browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
+						    _("Error executing query: %s"),
+						    estmt->exec_error && estmt->exec_error->message ? estmt->exec_error->message : _("No detail"));
+				execution_batch_free (ebatch);
+				return;
+			}
 		}
-		else
-			history = query_editor_history_item_new (sqlst->sql, NULL, NULL);
-		gda_sql_statement_free (sqlst);
-
-		query_editor_add_history_item (tconsole->priv->history, history);
-		query_editor_history_item_unref (history);
 	}
-	g_object_unref (batch);
+	ebatch->statements = g_slist_reverse (ebatch->statements);
+
+	tconsole->priv->current_exec = ebatch;
+	tconsole->priv->current_exec_id = g_timeout_add (200,
+							 (GSourceFunc) query_exec_fetch_cb,
+							 tconsole);
 }
 
+static gboolean
+query_exec_fetch_cb (QueryConsole *tconsole)
+{
+	gboolean alldone = TRUE;
+	
+	if (tconsole->priv->current_exec) {
+		if (tconsole->priv->current_exec->statements) {
+			ExecutionStatement *estmt;
+			estmt = (ExecutionStatement*) tconsole->priv->current_exec->statements->data;
+			g_assert (estmt->exec_id);
+			g_assert (!estmt->result);
+			g_assert (!estmt->exec_error);
+			g_print ("Getting results for exec ID %u\n", estmt->exec_id);
+			estmt->result = browser_connection_execution_get_result (tconsole->priv->bcnc,
+										 estmt->exec_id, NULL,
+										 &(estmt->exec_error));
+			if (estmt->result || estmt->exec_error) {
+				QueryEditorHistoryItem *history;
+				GdaSqlStatement *sqlst;
+				g_object_get (G_OBJECT (estmt->stmt), "structure", &sqlst, NULL);
+				if (!sqlst->sql) {
+					gchar *sql;
+					sql = gda_statement_to_sql (GDA_STATEMENT (estmt->stmt), NULL, NULL);
+					history = query_editor_history_item_new (sql, tconsole->priv->params,
+										 estmt->result);
+					g_free (sql);
+				}
+				else
+					history = query_editor_history_item_new (sqlst->sql, tconsole->priv->params,
+										 estmt->result);
+				gda_sql_statement_free (sqlst);
+				if (estmt->exec_error) {
+					browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
+							    _("Error executing query:\n%s"),
+							    estmt->exec_error && estmt->exec_error->message ?
+							    estmt->exec_error->message : _("No detail"));
+					TO_IMPLEMENT;
+					/* FIXME: offer the opportunity to stop execution of batch if there
+					 *        are some remaining statements to execute
+					 * FIXME: store error in history => modify QueryEditorHistoryItem
+					 */
+				}
+				
+				query_editor_add_history_item (tconsole->priv->history, history);
+				query_editor_history_item_unref (history);
+
+				/* get rid of estmt */
+				estmt->exec_id = 0;
+				execution_statement_free (estmt);
+				tconsole->priv->current_exec->statements =
+					g_slist_delete_link (tconsole->priv->current_exec->statements,
+							     tconsole->priv->current_exec->statements);
+
+				/* more to do ? */
+				if (tconsole->priv->current_exec->statements) {
+					estmt = (ExecutionStatement*) tconsole->priv->current_exec->statements->data;
+					estmt->exec_id = browser_connection_execute_statement (tconsole->priv->bcnc,
+											       estmt->stmt,
+											       tconsole->priv->params,
+											       GDA_STATEMENT_MODEL_RANDOM_ACCESS,
+											       FALSE,
+											       &(estmt->exec_error));
+					g_print ("Executing: %u\n", estmt->exec_id);
+					if (estmt->exec_id == 0) {
+						browser_show_error (GTK_WINDOW (gtk_widget_get_toplevel ((GtkWidget*) tconsole)),
+								    _("Error executing query:\n%s"),
+								    estmt->exec_error && estmt->exec_error->message ?
+								    estmt->exec_error->message : _("No detail"));
+					}
+					else
+						alldone = FALSE;
+				}
+			}
+			else
+				alldone = FALSE;
+		}
+	}
+	
+	if (alldone) {
+		if (tconsole->priv->current_exec) {
+			execution_batch_free (tconsole->priv->current_exec);
+			tconsole->priv->current_exec = NULL;
+		}
+
+		tconsole->priv->current_exec_id = 0;
+	}
+
+	return !alldone;
+}
 
 /*
  * UI actions
diff --git a/tools/browser/query-exec/query-editor.c b/tools/browser/query-exec/query-editor.c
index 315fa5b..32be854 100644
--- a/tools/browser/query-exec/query-editor.c
+++ b/tools/browser/query-exec/query-editor.c
@@ -292,10 +292,12 @@ text_view_expose_event (GtkTextView *tv, GdkEventExpose *event, QueryEditor *edi
 		GSList *list;
 		HistItemData *hdata;
 		list = g_slist_last (editor->priv->hist_focus->batch->hist_items);
-		hdata = g_hash_table_lookup (editor->priv->hash, list->data);
-		gtk_text_buffer_get_iter_at_mark (tv->buffer, &cur, hdata->end_mark);	
-		gtk_text_view_get_line_yrange (tv, &cur, &ye, &heighte);
-		height = ye - y;
+		if (list) {
+			hdata = g_hash_table_lookup (editor->priv->hash, list->data);
+			gtk_text_buffer_get_iter_at_mark (tv->buffer, &cur, hdata->end_mark);	
+			gtk_text_view_get_line_yrange (tv, &cur, &ye, &heighte);
+			height = ye - y;
+		}
 	}
 		
 	gtk_text_view_get_visible_rect (tv, &visible_rect);
@@ -1315,8 +1317,13 @@ query_editor_history_item_new (const gchar *sql, GdaSet *params, GObject *result
 	qih->sql = g_strdup (sql);
 	if (params)
 		qih->params = gda_set_copy (params);
-	if (result)
+	if (result) {
 		qih->result = g_object_ref (result);
+		if (GDA_IS_DATA_MODEL (result))
+			gda_data_model_dump (GDA_DATA_MODEL (result), NULL);
+		else
+			g_print ("RESULT!!!\n");
+	}
 
 	return qih;
 }



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