[libgda] GdaSql: improved inline help (translations welcome!)



commit f5d3a9a9ed7c7258704996025becb5b19322a0dc
Author: Vivien Malerba <malerba gnome-db org>
Date:   Sun Jan 15 20:37:33 2012 +0100

    GdaSql: improved inline help (translations welcome!)

 configure.ac                  |    1 +
 tools/command-exec.c          |  358 ++++++++++++++++++++++++++++++++++++++---
 tools/gda-sql.c               |   85 +++++-----
 tools/help/C/gda-sql-help.xml |  315 ++++++++++++++++++++++++++++++++++++
 tools/help/Makefile.am        |   10 ++
 5 files changed, 707 insertions(+), 62 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 648482f..9353bdd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -917,6 +917,7 @@ control-center/Makefile
 control-center/data/Makefile
 tools/Makefile
 tools/gda-sql-5.0.1:tools/gda-sql.1.in
+tools/help/Makefile
 tools/browser/Makefile
 tools/browser/data/Makefile
 tools/browser/common/Makefile
diff --git a/tools/command-exec.c b/tools/command-exec.c
index b92ba7a..a98e754 100644
--- a/tools/command-exec.c
+++ b/tools/command-exec.c
@@ -21,6 +21,7 @@
 
 #undef GDA_DISABLE_DEPRECATED
 #include "command-exec.h"
+#include <libgda/binreloc/gda-binreloc.h>
 #include <glib/gi18n-lib.h>
 #include <string.h>
 #include "tools-input.h"
@@ -251,46 +252,359 @@ default_gda_internal_commandargs_func (const gchar *string)
 	return array;
 }
 
+/*
+ * Same as append_to_string but cuts strings which are too long
+ */
+static void
+append_raw_to_string (GString *string, gchar *str, gint width, gint offset)
+{
+	g_assert (string);
+	if (!str)
+		return;
+	if ((width <= 0) && (offset <= 0)) {
+		g_string_append (string, str);
+		return;
+	}
+	if (offset < 0)
+		offset = 0;
+
+	/* start on a fresh line */
+	if ((string->str) && (string->len > 0) &&
+	    (string->str[string->len - 1] != '\n'))
+		g_string_append_c (string, '\n');
+
+	gchar *ptr;
+	gboolean startofline = TRUE;
+	for (ptr = str; *ptr; ) {
+		gchar *next, *pnext;
+		if (*ptr == '\n') {
+			g_string_append_c (string, '\n');
+			ptr++;
+			startofline = TRUE;
+			continue;
+		}
+		guint clen = 0;
+		for (next = ptr, pnext = ptr;
+		     *next && (*next != '\n');
+		     pnext = next + 1, next = g_utf8_next_char (next), clen++) {
+			if (startofline) {
+				if (offset > 0) {
+					gint i;
+					for (i = 0; i < offset; i++)
+						g_string_append_c (string, ' ');
+				}
+				startofline = FALSE;
+			}
+
+			if ((width > 0) && (clen >= width - offset)) {
+				g_string_append_c (string, '\n');
+				startofline = TRUE;
+				for (; *next && (*next != '\n'); next++);
+				if (*next == '\n')
+					next++;
+				break;
+			}
+			else {
+				for (; pnext <= next; pnext++)
+					g_string_append_c (string, *pnext);
+			}
+		}
+		ptr = next;
+	}
+}
+
+/*
+ * parses @str, and appends to @string lines which are @width large, if @offset is >0, then
+ * leave that amount of spaces. If @width <= 0, then only adds @offset spaces at the beginning of each
+ * new line.
+ */
+static void
+append_to_string (GString *string, gchar *str, gint width, gint offset)
+{
+	g_assert (string);
+	if (!str)
+		return;
+	if ((width <= 0) && (offset <= 0)) {
+		g_string_append (string, str);
+		return;
+	}
+	if (offset < 0)
+		offset = 0;
+
+	/* replace @WORD@ by <WORD> */
+	gchar *ptr;
+	gboolean in = FALSE;
+	for (ptr = str; *ptr; ptr++) {
+		if (*ptr == '@') {
+			if (in) {
+				*ptr = '>';
+				in = FALSE;
+			}
+			else {
+				*ptr = '<';
+				in = TRUE;
+			}
+		}
+	}
+
+	/* actual work */
+	gboolean firstword = TRUE;
+	gint clen = 0;
+	if ((string->str) && (string->len > 0) &&
+	    (string->str[string->len - 1] != '\n')) {
+		for (ptr = string->str + (string->len -1); (ptr >= string->str) && (*ptr != '\n'); ptr --)
+			clen++;
+	}
+	for (ptr = str; *ptr; ) {
+		/* skip spaces */
+		if ((*ptr == ' ') || (*ptr == '\t') || (*ptr == '\n') || (*ptr == '\r')) {
+			ptr++;
+			continue;
+		}
+
+		/* find end of next word */
+		gchar *next;
+		gint wlen;
+		for (wlen = 0, next = ptr;
+		     *next && (*next != ' ') && (*next != '\t') && (*next != '\n') && (*next != '\r');
+		     wlen ++, next = g_utf8_next_char (next));
+
+		if (wlen >= width - offset) {
+			const gchar *n2;
+			for (n2 = ptr; n2 < next; n2++) {
+				g_string_append_c (string, *n2);
+			}
+			ptr = next;
+			firstword = FALSE;
+			g_string_append_c (string, '\n');
+			clen = 0;
+			continue;
+		}
+		else if ((width > 0) && ((wlen + clen) >= width)) {
+			/* cut here */
+			g_string_append_c (string, '\n');
+			clen = 0;
+			continue;
+		}
+		else {
+			/* copy word */
+			if (clen == 0) {
+				if (offset > 0) {
+					gint i;
+					for (i = 0; i < offset; i++) {
+						g_string_append_c (string, ' ');
+						clen++;
+					}
+				}
+			}
+			else if (!firstword) {
+				g_string_append_c (string, ' ');
+				clen++;
+			}
+			const gchar *n2;
+			for (n2 = ptr; n2 < next; n2++) {
+				g_string_append_c (string, *n2);
+				clen++;
+			}
+			ptr = next;
+			firstword = FALSE;
+		}
+	}
+}
+
+static gchar *
+help_xml_doc_to_string (xmlDocPtr helpdoc, const gchar *command_name, gint width)
+{
+	xmlNodePtr node;
+	node = xmlDocGetRootElement (helpdoc);
+	if (!node)
+		return NULL;
+	for (node = node->children; node; node = node->next) {
+		if (strcmp ((gchar*) node->name, "command"))
+			continue;
+		xmlChar *prop;
+		prop = xmlGetProp (node, BAD_CAST "name");
+		if (prop && !strcmp ((gchar*) prop, command_name))
+			break;
+	}
+	if (!node)
+		return NULL;
+
+	/* create output string */
+	GString *string;
+	string = g_string_new ("");
+	for (node = node->children; node; node = node->next) {
+		xmlChar *data = NULL;
+		if (!strcmp ((gchar*) node->name, "shortdescription")) {
+			data = xmlNodeGetContent (node);
+			if (data) {
+				append_to_string (string, (gchar*) data, width, 0);
+				g_string_append (string, "\n\n");
+			}
+		}
+		else if (!strcmp ((gchar*) node->name, "usage") || !strcmp ((gchar*) node->name, "example")) {
+			if (!strcmp ((gchar*) node->name, "usage"))
+				append_to_string (string, _("Usage"), width, 0);
+			else
+				append_to_string (string, _("Example"), width, 0);
+			g_string_append (string, ":\n");
+			xmlNodePtr snode;
+			for (snode = node->children; snode; snode = snode->next) {
+				if (!strcmp ((gchar*) snode->name, "synopsis")) {
+					data = xmlNodeGetContent (snode);
+					if (data) {
+						append_to_string (string, "> ", width, 3);
+						append_to_string (string, (gchar*) data, width, 3);
+						g_string_append_c (string, '\n');
+					}
+				}
+				else if (!strcmp ((gchar*) snode->name, "comment")) {
+					data = xmlNodeGetContent (snode);
+					if (data) {
+						append_to_string (string, (gchar*) data, width, 6);
+						g_string_append_c (string, '\n');
+					}
+				}
+				else if (!strcmp ((gchar*) snode->name, "raw")) {
+					data = xmlNodeGetContent (snode);
+					if (data) {
+						append_raw_to_string (string, (gchar*) data, width, 6);
+						g_string_append (string, "\n\n");
+					}
+				}
+				if (data)
+					xmlFree (data);
+				data = NULL;
+			}
+		}
+		if (data)
+			xmlFree (data);
+	}
+
+	return g_string_free (string, FALSE);
+}
+
 GdaInternalCommandResult *
 gda_internal_command_help (SqlConsole *console, G_GNUC_UNUSED GdaConnection *cnc,
-			   G_GNUC_UNUSED const gchar **args, G_GNUC_UNUSED GError **error,
+			   const gchar **args, G_GNUC_UNUSED GError **error,
 			   GdaInternalCommandsList *clist)
 {
 	GdaInternalCommandResult *res;
 	GSList *list;
 	gchar *current_group = NULL;
 	GString *string = g_string_new ("");
+	xmlDocPtr helpdoc = NULL;
 #define NAMESIZE 18
 
+	/* get term size */
+	gint width;
+	input_get_size (&width, NULL);
+
 	res = g_new0 (GdaInternalCommandResult, 1);
 	res->type = GDA_INTERNAL_COMMAND_RESULT_TXT;
 
-	for (list = clist->group_ordered; list; list = list->next) {
-		GdaInternalCommand *command = (GdaInternalCommand*) list->data;
+	if (args[0] && *args[0]) {
+		const gchar *command_name = NULL;
+		GdaInternalCommand *command = NULL;
+		command_name = args[0];
+		for (list = clist->group_ordered; list; list = list->next) {
+			command = (GdaInternalCommand*) list->data;
+			gint clength;
+			clength = strlen (command_name);
+			if (!g_ascii_strncasecmp (command->name, command_name, clength) &&
+			    (command->name[clength] == ' '))
+				break;
+			command = NULL;
+		}
+		if (!command)
+			g_string_append_printf (string, _("Command '%s' not found\n"), command_name);
+		else {
+			if (!helpdoc) {
+				const gchar * const *langs = g_get_language_names ();
+				gchar *dirname, *helpfile;
+				gint i;
+				dirname = gda_gbr_get_file_path (GDA_DATA_DIR, "gnome", "help",
+								 "gda-sql", NULL);
+				for (i = 0; langs[i]; i++) {
+					helpfile = g_build_filename (dirname, langs[i], "gda-sql-help.xml", NULL);
+					if (g_file_test (helpfile, G_FILE_TEST_EXISTS))
+						helpdoc = xmlParseFile (helpfile);
+					g_free (helpfile);
+					if (helpdoc)
+						break;
+				}
 
-		if (console && command->limit_to_main)
-			continue;
+				if (!helpdoc) {
+					/* default to the "C" one */
+					helpfile = g_build_filename (dirname, "C", "gda-sql-help.xml", NULL);
+					if (g_file_test (helpfile, G_FILE_TEST_EXISTS))
+						helpdoc = xmlParseFile (helpfile);
+					g_free (helpfile);
+				}
+				g_free (dirname);
+			}
+			gboolean done = FALSE;
+			if (helpdoc) {
+				gchar *tmp;
+				tmp = help_xml_doc_to_string (helpdoc, command_name, width);
+				if (tmp) {
+					g_string_append (string, tmp);
+					g_free (tmp);
+					done = TRUE;
+				}
+			}
+			if (!done) {
+				append_to_string (string, command->description, width, 0);
+				g_string_append_printf (string, "\n\n%s:\n   .", _("Usage"));
+				append_to_string (string, command->name, width, 0);
+			}
+		}
+	}
+	else {
+		for (list = clist->group_ordered; list; list = list->next) {
+			GdaInternalCommand *command = (GdaInternalCommand*) list->data;
+			gint clen;
+			if (console && command->limit_to_main)
+				continue;
 
-		if (!current_group || strcmp (current_group, command->group)) {
-			current_group = command->group;
-			if (list != clist->group_ordered)
+			if (!current_group || strcmp (current_group, command->group)) {
+				current_group = command->group;
+				if (list != clist->group_ordered)
+					g_string_append_c (string, '\n');
+				if (width > 0) {
+					gint i, nb, remain;
+					nb = (width - g_utf8_strlen (current_group, -1) - 2) / 2;
+					remain = width - (2 * nb + 2 + g_utf8_strlen (current_group, -1));
+					for (i = 0; i < nb; i++)
+						g_string_append_c (string, '=');
+					g_string_append_c (string, ' ');
+					append_to_string (string, current_group, width, 0);
+					g_string_append_c (string, ' ');
+					for (i = 0; i < nb + remain; i++)
+						g_string_append_c (string, '=');
+					g_string_append_c (string, '\n');
+				}
+				else {
+					g_string_append (string, "=== ");
+					append_to_string (string, current_group, width, 0);
+					g_string_append (string, " ===\n");
+				}
+			}
+
+			g_string_append (string, "   .");
+			append_to_string (string, command->name, width, 3);
+			clen = g_utf8_strlen (command->name, -1);
+			if (clen >= NAMESIZE)
 				g_string_append_c (string, '\n');
-			g_string_append_printf (string, "%s\n", current_group);
-			
-		}
-		g_string_append_printf (string, "  \\%s", command->name);
-		if (strlen (command->name) < NAMESIZE) {
-			gint i;
-			for (i = strlen (command->name); i < NAMESIZE; i++)
-				g_string_append_c (string, ' ');
-		}
-		else {
+			else {
+				gint i, size;
+				size = NAMESIZE - clen - 1;
+				for (i = 0; i < size; i++)
+					g_string_append_c (string, ' ');
+			}
+			append_to_string (string, command->description, width, NAMESIZE + 3);
 			g_string_append_c (string, '\n');
-			gint i;
-			for (i = 0; i < NAMESIZE + 3; i++)
-				g_string_append_c (string, ' ');
 		}
-		g_string_append_printf (string, "%s\n", command->description);
 	}
 	res->u.txt = string;
 	return res;
diff --git a/tools/gda-sql.c b/tools/gda-sql.c
index 7cc9b4e..a9bdd9b 100644
--- a/tools/gda-sql.c
+++ b/tools/gda-sql.c
@@ -290,7 +290,7 @@ main (int argc, char *argv[])
 		g_print (_("Welcome to the GDA SQL console, version " PACKAGE_VERSION));
 		g_print ("\n\n");
 		g_print (_("Type: .copyright to show usage and distribution terms\n"
-			   "      .? for help with internal commands\n"
+			   "      .? or .h for help with internal commands\n"
 			   "      .q (or CTRL-D) to quit\n"
 			   "      (the '.' can be replaced by a '\\')\n"
 			   "      or any query terminated by a semicolon\n\n"));
@@ -986,6 +986,11 @@ find_command (GdaInternalCommandsList *commands_list, const gchar *command_str,
 			command = NULL;
 	}
 
+	if (!command &&
+	    ((command_str[1] == 'h') || (command_str[1] == 'H')) &&
+	    ((command_str[2] == ' ') || !command_str[2]))
+		command = find_command (commands_list, ".?", command_complete);
+
 	/* FIXME */
 	if (command_complete)
 		*command_complete = TRUE;
@@ -2158,7 +2163,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = g_strdup_printf (_("%s [FILE]"), "s");
+	c->name = g_strdup_printf (_("%s [<FILE>]"), "s");
 	c->description = _("Show commands history, or save it to file");
 	c->args = NULL;
 	c->command_func = gda_internal_command_history;
@@ -2170,7 +2175,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [META DATA TYPE]"), "meta");
+	c->name = g_strdup_printf (_("%s [<META DATA TYPE>]"), "meta");
 	c->description = _("Force reading the database meta data (or part of the meta data, ex:\"tables\")");
 	c->args = NULL;
 	c->command_func = gda_internal_command_dict_sync;
@@ -2206,7 +2211,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [TABLE]"), "dt");
+	c->name = g_strdup_printf (_("%s [<TABLE>]"), "dt");
 	c->description = _("List all tables (or named table)");
 	c->args = NULL;
 	c->command_func = gda_internal_command_list_tables;
@@ -2218,7 +2223,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [VIEW]"), "dv");
+	c->name = g_strdup_printf (_("%s [<VIEW>]"), "dv");
 	c->description = _("List all views (or named view)");
 	c->args = NULL;
 	c->command_func = gda_internal_command_list_views;
@@ -2230,7 +2235,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [SCHEMA]"), "dn");
+	c->name = g_strdup_printf (_("%s [<SCHEMA>]"), "dn");
 	c->description = _("List all schemas (or named schema)");
 	c->args = NULL;
 	c->command_func = gda_internal_command_list_schemas;
@@ -2242,7 +2247,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [OBJ_NAME|SCHEMA.*]"), "d");
+	c->name = g_strdup_printf (_("%s [<OBJ_NAME>|<SCHEMA>.*]"), "d");
 	c->description = _("Describe object or full list of objects");
 	c->args = NULL;
 	c->command_func = gda_internal_command_detail;
@@ -2254,7 +2259,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [TABLE1 [TABLE2...]]"), "graph");
+	c->name = g_strdup_printf (_("%s [<TABLE1> [<TABLE2>...]]"), "graph");
 	c->description = _("Create a graph of all or the listed tables");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_graph;
@@ -2267,7 +2272,7 @@ build_internal_commands_list (void)
 #ifdef HAVE_LIBSOUP
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Information");
-	c->name = g_strdup_printf (_("%s [port [authentication token]]"), "http");
+	c->name = g_strdup_printf (_("%s [<port> [<authentication token>]]"), "http");
 	c->description = _("Start/stop embedded HTTP server (on given port or on 12345 by default)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_httpd;
@@ -2281,7 +2286,7 @@ build_internal_commands_list (void)
 	/* specific commands */
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = g_strdup_printf (_("%s [CNC_NAME [DSN|CONNECTION STRING]]"), "c");
+	c->name = g_strdup_printf (_("%s [<CNC_NAME> [<DSN>|<CONNECTION STRING>]]"), "c");
 	c->description = _("Opens a new connection or lists opened connections");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_manage_cnc;
@@ -2293,7 +2298,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = g_strdup_printf (_("%s [CNC_NAME]"), "close");
+	c->name = g_strdup_printf (_("%s [<CNC_NAME>]"), "close");
 	c->description = _("Close a connection");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_close_cnc;
@@ -2305,8 +2310,8 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = g_strdup_printf (_("%s CNC_NAME CNC_NAME1 CNC_NAME2 [CNC_NAME ...]"), "bind");
-	c->description = _("Bind several connections together into the CNC_NAME virtual connection");
+	c->name = g_strdup_printf (_("%s <CNC_NAME> <CNC_NAME1> <CNC_NAME2> [<CNC_NAME> ...]"), "bind");
+	c->description = _("Bind two or more connections into a single new one (allowing SQL commands to be executed across multiple connections)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc)extra_command_bind_cnc;
 	c->user_data = NULL;
@@ -2317,7 +2322,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("DSN (data sources) management");
-	c->name = g_strdup_printf (_("%s [DSN]"), "l");
+	c->name = g_strdup_printf (_("%s [<DSN>]"), "l");
 	c->description = _("List all DSN (or named DSN's attributes)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_list_dsn;
@@ -2329,7 +2334,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("DSN (data sources) management");
-	c->name = g_strdup_printf (_("%s DSN_NAME DSN_DEFINITION [DESCRIPTION]"), "lc");
+	c->name = g_strdup_printf (_("%s <DSN_NAME> <DSN_DEFINITION> [<DESCRIPTION>]"), "lc");
 	c->description = _("Create (or modify) a DSN");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_create_dsn;
@@ -2341,7 +2346,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("DSN (data sources) management");
-	c->name = g_strdup_printf (_("%s DSN_NAME [DSN_NAME...]"), "lr");
+	c->name = g_strdup_printf (_("%s <DSN_NAME> [<DSN_NAME>...]"), "lr");
 	c->description = _("Remove a DSN");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_remove_dsn;
@@ -2353,7 +2358,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("DSN (data sources) management");
-	c->name = g_strdup_printf (_("%s [PROVIDER]"), "lp");
+	c->name = g_strdup_printf (_("%s [<PROVIDER>]"), "lp");
 	c->description = _("List all installed database providers (or named one's attributes)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_list_providers;
@@ -2365,7 +2370,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Input/Output");
-	c->name = g_strdup_printf (_("%s FILE"), "i");
+	c->name = g_strdup_printf (_("%s <FILE>"), "i");
 	c->description = _("Execute commands from file");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_set_input;
@@ -2377,7 +2382,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Input/Output");
-	c->name = g_strdup_printf (_("%s [FILE]"), "o");
+	c->name = g_strdup_printf (_("%s [<FILE>]"), "o");
 	c->description = _("Send output to a file or |pipe");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_set_output;
@@ -2389,8 +2394,8 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Input/Output");
-	c->name = g_strdup_printf (_("%s [TEXT]"), "echo");
-	c->description = _("Send output to stdout");
+	c->name = g_strdup_printf (_("%s [<TEXT>]"), "echo");
+	c->description = _("Print TEXT or an empty line to standard output");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_echo;
 	c->user_data = NULL;
@@ -2401,8 +2406,8 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Input/Output");
-	c->name = g_strdup_printf (_("%s [TEXT]"), "qecho");
-	c->description = _("Send output to output stream");
+	c->name = g_strdup_printf (_("%s [<TEXT>]"), "qecho");
+	c->description = _("Send TEXT or an empty line to current output stream");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_qecho;
 	c->user_data = NULL;
@@ -2425,7 +2430,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = g_strdup_printf (_("%s [DIR]"), "cd");
+	c->name = g_strdup_printf (_("%s [<DIR>]"), "cd");
 	c->description = _("Change the current working directory");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_cd;
@@ -2449,7 +2454,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [FILE]"), "e");
+	c->name = g_strdup_printf (_("%s [<FILE>]"), "e");
 	c->description = _("Edit the query buffer (or file) with external editor");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_edit_buffer;
@@ -2461,7 +2466,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [FILE]"), "qr");
+	c->name = g_strdup_printf (_("%s [<FILE>]"), "qr");
 	c->description = _("Reset the query buffer (fill buffer with contents of file)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_reset_buffer;
@@ -2485,7 +2490,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [QUERY_BUFFER_NAME]"), "g");
+	c->name = g_strdup_printf (_("%s [<QUERY_BUFFER_NAME>]"), "g");
 	c->description = _("Execute contents of query buffer, or named query buffer");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_exec_buffer;
@@ -2497,7 +2502,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s FILE"), "qw");
+	c->name = g_strdup_printf (_("%s <FILE>"), "qw");
 	c->description = _("Write query buffer to file");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_write_buffer;
@@ -2509,7 +2514,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "qs");
+	c->name = g_strdup_printf (_("%s <QUERY_BUFFER_NAME>"), "qs");
 	c->description = _("Save query buffer to dictionary");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_to_dict;
@@ -2521,7 +2526,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "ql");
+	c->name = g_strdup_printf (_("%s <QUERY_BUFFER_NAME>"), "ql");
 	c->description = _("Load query buffer from dictionary");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_from_dict;
@@ -2533,7 +2538,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s QUERY_BUFFER_NAME"), "qd");
+	c->name = g_strdup_printf (_("%s <QUERY_BUFFER_NAME>"), "qd");
 	c->description = _("Delete query buffer from dictionary");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_query_buffer_delete_dict;
@@ -2570,7 +2575,7 @@ build_internal_commands_list (void)
 	/*
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s FILE TABLE BLOB_COLUMN ROW_CONDITION"), "lo_update");
+	c->name = g_strdup_printf (_("%s <FILE> <TABLE> <BLOB_COLUMN> <ROW_CONDITION>"), "lo_update");
 	c->description = _("Import a blob into the database");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_lo_update;
@@ -2582,7 +2587,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Query buffer");
-	c->name = g_strdup_printf (_("%s [NAME|TABLE COLUMN ROW_CONDITION] FILE"), "export");
+	c->name = g_strdup_printf (_("%s [<NAME>|<TABLE> <COLUMN> <ROW_CONDITION>] <FILE>"), "export");
 	c->description = _("Export internal parameter or table's value to the FILE file");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_export;
@@ -2594,8 +2599,8 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Execution context");
-	c->name = g_strdup_printf (_("%s [NAME [VALUE|_null_]]"), "set");
-	c->description = _("Set or show internal parameter, or list all if no parameters");
+	c->name = g_strdup_printf (_("%s [<NAME> [<VALUE>|_null_]]"), "set");
+	c->description = _("Set or show internal parameter, or list all if no parameter specified ");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_set;
 	c->user_data = NULL;
@@ -2606,7 +2611,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Execution context");
-	c->name = g_strdup_printf (_("%s [NAME]"), "unset");
+	c->name = g_strdup_printf (_("%s [<NAME>]"), "unset");
 	c->description = _("Unset (delete) internal named parameter (or all parameters)");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_unset;
@@ -2618,7 +2623,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Execution context");
-	c->name = g_strdup_printf (_("%s NAME [FILE|TABLE COLUMN ROW_CONDITION]"), "setex");
+	c->name = g_strdup_printf (_("%s <NAME> [<FILE>|<TABLE> <COLUMN> <ROW_CONDITION>]"), "setex");
 	c->description = _("Set internal parameter as the contents of the FILE file or from an existing table's value");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) extra_command_set2;
@@ -2630,7 +2635,7 @@ build_internal_commands_list (void)
 
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("Execution context");
-	c->name = g_strdup_printf (_("%s \"SELECT\" ROW_FIELDS [COLUMN_FIELDS [DATA_FIELDS ...]]"), "pivot");
+	c->name = g_strdup_printf (_("%s <SELECT> <ROW_FIELDS> [<COLUMN_FIELDS> [<DATA_FIELDS> ...]]"), "pivot");
 	c->description = _("Performs a statistical analysis on the data from SELECT, "
 			   "using ROW_FIELDS and COLUMN_FIELDS criteria and optionally DATA_FIELDS for the data");
 	c->args = NULL;
@@ -2644,8 +2649,8 @@ build_internal_commands_list (void)
 	/* comes last */
 	c = g_new0 (GdaInternalCommand, 1);
 	c->group = _("General");
-	c->name = "?";
-	c->description = _("List all available commands");
+	c->name = g_strdup_printf (_("%s [command]"), "?");
+	c->description = _("List all available commands or give help for the specified command");
 	c->args = NULL;
 	c->command_func = (GdaInternalCommandFunc) gda_internal_command_help;
 	c->user_data = commands;
diff --git a/tools/help/C/gda-sql-help.xml b/tools/help/C/gda-sql-help.xml
new file mode 100644
index 0000000..71ab98d
--- /dev/null
+++ b/tools/help/C/gda-sql-help.xml
@@ -0,0 +1,315 @@
+<?xml version="1.0"?>
+<gda-sql-help>
+  <!-- "." command -->
+  <command name="">
+    <shortdescription>
+    </shortdescription>
+    <usage>
+      <synopsis>.</synopsis>
+      <comment></comment>
+    </usage>
+    <example>
+      <synopsis>.</synopsis>
+      <comment></comment>
+    </example>
+  </command>
+
+  <!-- ".bind" command -->
+  <command name="bind">
+    <shortdescription>Bind two or more connections into a single new one (allowing SQL commands to be executed across multiple connections).
+    </shortdescription>
+    <usage>
+      <synopsis>.bind @CNC_NAME@ @CNC_NAME1@ @CNC_NAME2@ [ CNC_NAME@ ...]</synopsis>
+      <comment>creates a new connection named @CNC_NAME@ which binds the tables of the @CNC_NAME1@, @CNC_NAME2@ and any other connection specified.</comment>
+    </usage>
+    <example>
+      <synopsis>.bind attached c0 c1</synopsis>
+      <comment>creates the "attached" connection where all the tables from connection "c1" are mapped to the "c1" schema and all the tables from connection "c2" are mapped to the "c2" schema.</comment>
+    </example>
+  </command>
+
+  <!-- ".c" command -->
+  <command name="c">
+    <shortdescription>Opens a new connection or lists opened connections</shortdescription>
+    <usage>
+      <synopsis>.c [ CNC_NAME@ [ DSN@|@CONNECTION STRING ]]</synopsis>
+      <comment>Opens a new connection, named @CNC_NAME@ using either a DSN name (use the ".l" command to list all declared DSN), or a connection string (use the ".lp" command to list database providers and see which argument their connection string accepts).</comment>
+      <comment>If only a connection name is passed as argument, then the named connection becomes the current active connection. As a side note, using "~" as a connection name will switch to a (new or already opened) connection which contains the meta data for the active connection.</comment>
+      <comment>If no connection name is specified, then this command lists all the opened connections</comment>
+    </usage>
+    <example>
+      <synopsis>.c st SalesTest</synopsis>
+      <synopsis>.c ht htsql_demo.db</synopsis>
+      <synopsis>.c</synopsis>
+      <raw>                      List of opened connections
+Name | Provider | DSN or connection string                         | Username
+-----+----------+--------------------------------------------------+---------
+ht   | SQLite   | DB_DIR=.;EXTRA_FUNCTIONS=TRUE;DB_NAME=htsql_demo |         
+st   | SQLite   | SalesTest                                        |         
+(2 rows)</raw>
+      <comment>This example opens two SQLite connections, named "ht" and "st"</comment>
+    </example>
+
+    <example>
+      <synopsis>.c ~</synopsis>
+      <synopsis>.d</synopsis>
+      <raw>Schema | Name                             | Type       | Owner
+-------+----------------------------------+------------+------
+main   | __declared_fk                    | BASE TABLE |      
+main   | _all_types                       | VIEW       |      
+main   | _attributes                      | BASE TABLE |
+[...]
+(32 rows)</raw>
+      <comment>This command switches to the connection containing the currently active connection's meta data, the ".d" command displays all the tables and views of the current active connection.</comment>
+    </example>
+
+    <example>
+      <synopsis>.c</synopsis>
+      <comment>This command lists all opened connections (including the meta data connections)</comment>
+      <raw>                                              List of opened connections
+Name | Provider | DSN or connection string                                                                   
+-----+----------+--------------------------------------------------------------------------------------------
+ht   | SQLite   | DB_DIR=.;EXTRA_FUNCTIONS=TRUE;DB_NAME=htsql_demo                                           
+st   | SQLite   | SalesTest                                                                                  
+~st  | SQLite   | DB_DIR=/home/vivien/.local/share/libgda;DB_NAME=gda-sql-SalesTest                          
+~ht  | SQLite   | DB_DIR=/home/vivien/.local/share/libgda;DB_NAME=gda-sql-ab1b5c41e024d87d739797e820dadb05d26
+(4 rows)</raw>
+    </example>
+  </command>
+
+  <!-- ".l" command -->
+  <command name="l">
+    <shortdescription>List all defined data source (DSN), or named DSN's attributes.
+    </shortdescription>
+    <usage>
+      <synopsis>.l [ DSN@]</synopsis>
+      <comment>If no @DSN@ argument is specified, then lists all the DSN, otherwise gives information about the specified DSN</comment>
+    </usage>
+    <example>
+      <synopsis>.l</synopsis>
+      <raw>                       DSN list
+DSN       | Description                          | Provider  
+----------+--------------------------------------+-----------
+mysales   |                                      | MySQL     
+pgsales   |                                      | PostgreSQL
+SalesTest | Test database for a sales department | SQLite    
+(3 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>.l mysales</synopsis>
+      <raw>   DSN 'mysales' description
+Attribute      | Value            
+---------------+------------------
+DSN name       | mysales          
+Provider       | MySQL            
+Description    |                  
+Parameters     | HOST: gda        
+                 DB_NAME: test1   
+Authentication | USERNAME: gdauser
+System DSN?    | No               
+(6 rows)</raw>
+      <comment>The output above shows that the "mysales" DSN uses a MySQL server, hosted on the "gda" machine, for the database "test1", and that the username will be "gdauser"</comment>
+    </example>
+  </command>
+
+  <!-- ".lp" command -->
+  <command name="lp">
+    <shortdescription>List all installed database providers (or named one's attributes)
+    </shortdescription>
+    <usage>
+      <synopsis>.lp [ PROVIDER@]</synopsis>
+      <comment>Shows information about database providers installed, or about a specific database provider if specified. Use this information to create connection strings</comment>
+    </usage>
+    <example>
+      <synopsis>.lp</synopsis>
+      <raw>                                    Installed providers list
+Provider      | Description                                                                        
+--------------+------------------------------------------------------------------------------------
+BDBSql        | Provider for BDB SQL databases                                                     
+Berkeley-DB   | Provider for Berkeley databases                                                    
+Firebird      | Provider for Firebird databases                                                    
+FirebirdEmbed | Provider for embedded Firebird databases                                           
+Ldap          | Provider for database where tables are based on data contained in an LDAP directory
+MSAccess      | Provider for Microsoft Access files                                                
+MySQL         | Provider for MySQL databases                                                       
+Oracle        | Provider for Oracle databases                                                      
+PostgreSQL    | Provider for PostgreSQL databases                                                  
+SQLCipher     | Provider for SQLCipher                                                             
+SQLite        | Provider for SQLite databases                                                      
+Web           | Provider for web server proxies                                                    
+(12 rows)</raw>
+      <synopsis>.lp MySQL</synopsis>
+      <raw>                                         Provider 'MySQL' description
+Attribute      | Value                                                                                         
+---------------+-----------------------------------------------------------------------------------------------
+Provider       | MySQL                                                                                         
+Description    | Provider for MySQL databases                                                                  
+DSN parameters | DB_NAME: Database name. The name of a database to connect to (string),                        
+                 HOST: Database server. Host on which the database server is running (string),                 
+                 PORT: Port. Database server port (int),                                                       
+                 UNIX_SOCKET: UNIX Socket. Full path of the UNIX socket to use when connecting locally (string)
+                 USE_SSL: Require SSL. Whether or not to use SSL to establish the connection (boolean),        
+                 COMPRESS: Compress. Use compression protocol (boolean)                                        
+Authentication | USERNAME (string),                                                                            
+                 PASSWORD (string)                                                                             
+File           | /usrlib/libgda-5.0/providers/libgda-mysql.so                                         
+(5 rows)</raw>
+      <comment>This output shows all the arguments accepted by the MySQL provider (DB_NAME, HOST, PORT, ...)</comment>
+    </example>
+  </command>
+
+  <!-- ".pivot" command -->
+  <command name="pivot">
+    <shortdescription>Performs a statistical analysis on the data from SELECT, using ROW_FIELDS and COLUMN_FIELDS criteria and optionally DATA_FIELDS for the data.</shortdescription>
+    <usage>
+      <synopsis>  SELECT@ @ROW_FIELDS@ [ COLUMN_FIELDS@ [ DATA_FIELDS@ ...]]</synopsis>
+      <comment>The @SELECT@ defines the data set to perform summarization on.</comment>
+      <comment></comment>
+      <comment>The  @ROW_FIELDS@ defines the fields from the data set from which each individual value will
+              yield to a row in the analysis (it can be any valid selectable SQL  expression  on  the  data
+              set's fields); multiple expressions can be provided, separated by commas (forming a valid SQL
+              expression).  In this case a row will be created for each combination of values  of  each  of
+              the expression.
+      </comment>
+      <comment></comment>
+      <comment>The @COLUMN_FIELDS@ defines  the  fields from the data set from which each individual value
+              will yield to a column in the analysis. Its syntax is similar to the @ROW_FIELDS@ one. If not
+              specified  (or  if  specified  as a single dash ("-") caracter), then only one column will be
+              created.  Note that, if the @DATA_FIELDS@ argument is specified each column created from  the
+              @COLUMN_FIELDS@  will  in  fact  lead to the creation of as many @DATA_FIELDS@ arguments proâ
+              vided.
+      </comment>
+      <comment></comment>
+      <comment>The @DATA_FIELDS@ arguments are entirely optional and indicates the way data summarization is
+              done  for  each pair of (row,column) values (the default is to count occurrences). The syntax
+              for each @DATA_FIELDS@ argument is: [aggregate] SQL_expression@, where the aggregate part  is
+              optional  and,  if  present  must be among [SUM], [COUNT], [AVG], [MIN] or [MAX], and the SQL
+              expression is a valid selectable SQL expression of the data set's fields.
+      </comment>
+    </usage>
+    <example>
+      <comment>Suppose for these example that we have a table named "student" where students of schools are
+      are listed (this example comes from the HTSQL tutorial database, see http://htsql.org/doc/tutorial.html).
+      Part of this table's contents is the following:
+      </comment>
+      <raw>name                | gender | dob        | school_code | program_code | start_date
+--------------------+--------+------------+-------------+--------------+-----------
+Linda Wright        | f      | 1988-10-03 | ns          | umth         | 2007-08-15
+Beth Thompson       | f      | 1988-01-24 | ns          | gmth         | 2007-08-15
+Sheri Sanchez       | f      | 1985-05-14 | edu         | gedu         | 2007-08-15
+John Stone          | m      | 1984-01-28 | bus         | pbusad       | 2007-08-15
+Helen Johnson       | f      | 1986-02-03 | eng         | ucompsci     | 2007-08-15
+Anna Carroll        | f      | 1985-03-29 | edu         | gedu         | 2007-08-15
+Carol Walden        | f      | 1988-04-09 | ns          | uphys        | 2007-08-15</raw>
+
+      <synopsis>.pivot "select * from student" gender</synopsis>
+      <comment>The output will show one line per gender and will show the number of students for each gender
+      </comment>
+      <raw>gender |    
+-------+----
+f      | 284
+m      | 172
+(2 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>pivot "select name, gender, strftime ('%Y', dob) as year_of_birth from student order by year_of_birth" gender year_of_birth</synopsis>
+      <comment>This example displays, by gender of students, the number of students for each year where
+      at least one student is born</comment>
+      <raw>gender | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992
+-------+------+------+------+------+------+------+------+------+------+------+-----
+m      |   11 |   26 |   39 |   50 |   30 |   13 |    3 |      |      |      |     
+f      |      |      |      |   12 |   38 |   36 |   56 |   61 |   33 |   37 |   11
+(2 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>.pivot "select name, gender, strftime ('%Y', dob) as year_of_birth from student order by year_of_birth" year_of_birth gender</synopsis>
+      <comment>This example displays the same information as the one above, but with one row per year</comment>
+      <raw>year_of_birth | m  | f 
+--------------+----+---
+1982          | 11 |   
+1983          | 26 |   
+1984          | 39 |   
+1985          | 50 | 12
+1986          | 30 | 38
+1987          | 13 | 36
+1988          |  3 | 56
+1989          |    | 61
+1990          |    | 33
+1991          |    | 37
+1992          |    | 11
+(11 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>.pivot "select name, gender, strftime ('%Y', dob) as year_of_birth, school_code from student order by year_of_birth" year_of_birth school_code</synopsis>
+      <comment>This example is similar to the one above, but replaces the gender by the school_code for the columns</comment>
+      <raw>year_of_birth | art | bus | edu | eng | la | ns | ph
+--------------+-----+-----+-----+-----+----+----+---
+1982          |  11 |     |     |     |    |    |   
+1983          |  18 |   8 |     |     |    |    |   
+1984          |  15 |  18 |   6 |     |    |    |   
+1985          |  16 |  18 |  18 |  10 |    |    |   
+1986          |   2 |  12 |  23 |  17 | 14 |    |   
+1987          |     |   2 |  16 |  16 | 12 |  3 |   
+1988          |     |     |   6 |  14 | 14 | 22 |  3
+1989          |     |     |     |   5 | 22 | 13 | 21
+1990          |     |     |     |     | 10 |  7 | 16
+1991          |     |     |     |     |    | 16 | 21
+1992          |     |     |     |     |    |    | 11
+(11 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>.pivot "select school_code, program_code, julianday(Date('now')) - julianday(start_date) as days from vs;" program_code - [avg]days</synopsis>
+      <comment>This example displays, for each program code, the average number of days since the course
+      was started</comment>
+      <raw>program_code | avg_days   
+-------------+------------
+umth         | 1163.153846
+gmth         | 1106.923077
+gedu         | 1180.909091
+pbusad       | 1134.846154
+ucompsci     | 1186.583333
+uphys        | 1206.777778
+psci         | 1156.125000
+uspan        | 1137.800000
+[...]
+(39 rows)</raw>
+    </example>
+
+    <example>
+      <synopsis>.pivot "select school_code, program_code, (julianday(Date('now')) - julianday(start_date))::int as days from vs;" program_code school_code [max]days</synopsis>
+      <comment>This example is similar to the one above, but it shows the maximum number of days since the course was started, and is split in columns by school code</comment>
+      <raw>program_code | ns[max_days] | edu[max_days] | bus[max_days] | eng[max_days] | la[max_days] | ph[max_days] | art[max_days]
+-------------+--------------+---------------+---------------+---------------+--------------+--------------+--------------
+umth         |         1613 |               |               |               |              |              |              
+gmth         |         1613 |               |               |               |              |              |              
+gedu         |              |          1613 |               |               |              |              |              
+pbusad       |              |               |          1613 |               |              |              |              
+ucompsci     |              |               |               |          1613 |              |              |              
+uphys        |         1613 |               |               |               |              |              |              
+psci         |              |          1613 |               |               |              |              |              
+uspan        |              |               |               |               |         1613 |              |
+[...]
+(39 rows)</raw>
+    </example>
+  </command>
+
+  <!-- ".set" command -->
+  <command name="set">
+    <shortdescription>Set or show internal parameter, or list all if no parameter specified
+    </shortdescription>
+    <usage>
+      <synopsis>.set [ NAME@ [ VALUE@|_null_]]</synopsis>
+      <comment>Use this command to define or re-define variables which can later be used in stataments. Use the ".unset" command to undefine a variable. If you want set a variable to the SQL NULL, then use the "_null_" constant value.</comment>
+    </usage>
+    <example>
+      <synopsis>.set ID 23</synopsis>
+      <synopsis>.set ID</synopsis>
+      <comment>This example defines the ID variabe (beware, case sensitive) ID to 23. Later you can then run a query like "SELECT * FROM customers WHERE id=##ID::int"</comment>
+    </example>
+  </command>
+</gda-sql-help>
\ No newline at end of file
diff --git a/tools/help/Makefile.am b/tools/help/Makefile.am
new file mode 100644
index 0000000..5776ef3
--- /dev/null
+++ b/tools/help/Makefile.am
@@ -0,0 +1,10 @@
+include $(top_srcdir)/gnome-doc-utils.make
+
+DOC_ID = gda-sql
+
+DOC_PAGES = \
+	gda-sql-help.xml
+
+DOC_LINGUAS = 
+
+dist-hook: doc-dist-hook



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