libgda r3360 - in trunk: . doc/C doc/C/tmpl libgda samples samples/SqlBuilder



Author: vivien
Date: Thu Mar 19 17:28:35 2009
New Revision: 3360
URL: http://svn.gnome.org/viewvc/libgda?rev=3360&view=rev

Log:
2009-03-19  Vivien Malerba <malerba gnome-db org>

        * libgda/Makefile.am:
        * libgda/libgda.h.in:
        * libgda/gda-sql-builder.[ch]: new object to build GdaStatement iterativaly; this is
        * Makefile.am:
        * samples/: new example illustrating how to use the new #GdaSqlBuilder object
        * doc/C:
          - document GdaSqlBuilder
          - have 'make distcheck' work again


Added:
   trunk/doc/C/tmpl/gda-sql-builder.sgml
   trunk/libgda/gda-sql-builder.c
   trunk/libgda/gda-sql-builder.h
   trunk/samples/SqlBuilder/
   trunk/samples/SqlBuilder/Makefile
   trunk/samples/SqlBuilder/README
   trunk/samples/SqlBuilder/example.c
Modified:
   trunk/ChangeLog
   trunk/Makefile.am
   trunk/doc/C/Makefile.am
   trunk/doc/C/libgda-4.0-docs.sgml
   trunk/doc/C/libgda-4.0-sections.txt
   trunk/doc/C/libgda-4.0.types.in
   trunk/doc/C/tmpl/gda-statement.sgml
   trunk/libgda/Makefile.am
   trunk/libgda/libgda.h.in
   trunk/samples/Makefile
   trunk/samples/README

Modified: trunk/Makefile.am
==============================================================================
--- trunk/Makefile.am	(original)
+++ trunk/Makefile.am	Thu Mar 19 17:28:35 2009
@@ -68,7 +68,10 @@
 	samples/MetaStore/example.c \
 	samples/Tree/Makefile \
 	samples/Tree/README \
-	samples/Tree/example.c
+	samples/Tree/example.c \
+	samples/SqlBuilder/Makefile \
+        samples/SqlBuilder/README \
+        samples/SqlBuilder/example.c
 
 EXTRA_DIST = \
 	COPYING \

Modified: trunk/doc/C/Makefile.am
==============================================================================
--- trunk/doc/C/Makefile.am	(original)
+++ trunk/doc/C/Makefile.am	Thu Mar 19 17:28:35 2009
@@ -43,7 +43,7 @@
 MKDB_OPTIONS=--sgml-mode --output-format=xml --ignore-files="parser.c binreloc.c libcsv.c md5c.c"
 
 # Extra SGML files that are included by $(DOC_MAIN_SGML_FILE)
-content_files = fdl-appendix.sgml 
+content_files = fdl-appendix.sgml version.xml
 
 # Images to copy into HTML directory
 HTML_IMAGES = DataModels.png \

Modified: trunk/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- trunk/doc/C/libgda-4.0-docs.sgml	(original)
+++ trunk/doc/C/libgda-4.0-docs.sgml	Thu Mar 19 17:28:35 2009
@@ -123,6 +123,7 @@
 <!ENTITY libgda-GdaTreeMgrSchemas SYSTEM "xml/gda-tree-mgr-schemas.xml">
 <!ENTITY libgda-GdaTreeMgrTables SYSTEM "xml/gda-tree-mgr-tables.xml">
 <!ENTITY libgda-GdaTreeMgrColumns SYSTEM "xml/gda-tree-mgr-columns.xml">
+<!ENTITY libgda-GdaSqlBuilder SYSTEM "xml/gda-sql-builder.xml">
 ]>
 
 <book id="index">
@@ -541,6 +542,7 @@
       &libgda-convenient;
       &libgda-GdaConnection;
       &libgda-GdaSqlParser;
+      &libgda-GdaSqlBuilder;
       &libgda-GdaStatement;
       &libgda-GdaBatch;
       &libgda-GdaHolder;

Modified: trunk/doc/C/libgda-4.0-sections.txt
==============================================================================
--- trunk/doc/C/libgda-4.0-sections.txt	(original)
+++ trunk/doc/C/libgda-4.0-sections.txt	Thu Mar 19 17:28:35 2009
@@ -1630,3 +1630,27 @@
 GDA_TYPE_TREE_MGR_SELECT
 gda_tree_mgr_select_get_type
 </SECTION>
+
+<SECTION>
+<FILE>gda-sql-builder</FILE>
+<TITLE>GdaSqlBuilder</TITLE>
+GdaSqlBuilder
+gda_sql_builder_new
+gda_sql_builder_get_statement
+gda_sql_builder_get_sql_statement
+<SUBSECTION>
+gda_sql_builder_set_table
+gda_sql_builder_add_field_value
+<SUBSECTION>
+gda_sql_builder_literal
+gda_sql_builder_expr
+gda_sql_builder_param
+<SUBSECTION>
+gda_sql_builder_cond2
+<SUBSECTION Standard>
+GDA_SQL_BUILDER
+GDA_SQL_BUILDER_GET_CLASS
+GDA_IS_SQL_BUILDER
+GDA_TYPE_SQL_BUILDER
+gda_sql_builder_get_type
+</SECTION>

Modified: trunk/doc/C/libgda-4.0.types.in
==============================================================================
--- trunk/doc/C/libgda-4.0.types.in	(original)
+++ trunk/doc/C/libgda-4.0.types.in	Thu Mar 19 17:28:35 2009
@@ -63,3 +63,4 @@
 gda_tree_mgr_select_get_type
 gda_tree_mgr_tables_get_type
 gda_tree_node_get_type
+gda_sql_builder_get_type

Added: trunk/doc/C/tmpl/gda-sql-builder.sgml
==============================================================================
--- (empty file)
+++ trunk/doc/C/tmpl/gda-sql-builder.sgml	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,151 @@
+<!-- ##### SECTION Title ##### -->
+GdaSqlBuilder
+
+<!-- ##### SECTION Short_Description ##### -->
+Factory object for statements
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+  The #GdaSqlBuilder can be used to build a #GdaStatement from its structural description,
+  much in the same way a #GdaSqlParser can be used to build a #GdaStatement from an SQL
+  string.
+</para>
+<para>
+  The #GdaBuilder internally constructs a #GdaSqlStatement and uses it when requested to produce
+  a #GdaStatement (see gda_sql_builder_get_statement()), or a #GdaSqlStatement (see
+  gda_sql_builder_get_sql_statement()).
+</para>
+<para>
+  During the building process, some pieces of the statement are constructed, and assembled into the
+  final statement. Each of these pieces can be reused anytime in the same #GdaBuilder object, and each
+  is identified using a single unsigned integer ID. That ID can either be specified by the user, or
+  be dynamically allocated by the object (pass 0 as the requested ID).
+</para>
+<para>
+  The following example builds the equivalent of the <![CDATA["name='joe' AND age >= ##ageparam::int"]]> expression:
+  <programlisting><![CDATA[
+GdaSqlBuilder *b=...
+gda_sql_builder_literal (b, 1, "name"); // build the "name" literal with requested ID=1
+gda_sql_builder_expr (b, 2, NULL, G_TYPE_STRING, "joe"); // 'joe' expression, requested ID=2
+gda_sql_builder_cond2 (b, 3, GDA_SQL_OPERATOR_TYPE_EQ, 1, 2); // "name='joe'", requested ID=3
+
+gda_sql_builder_cond2 (b, 4, GDA_SQL_OPERATOR_TYPE_GT, // requested ID=4
+       gda_sql_builder_literal (b, 0, "age"), // build the "age" literal, no specific ID
+       gda_sql_builder_param (b, 0, "ageparam", G_TYPE_INT, FALSE) // parameter, no specific ID
+      );
+gda_sql_builder_cond2 (b, 5, GDA_SQL_OPERATOR_TYPE_AND, 3, 4); // whole expression, requested ID=5
+]]></programlisting>
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+ 
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GdaSqlBuilder ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gda_sql_builder_new ##### -->
+<para>
+
+</para>
+
+ stmt_type: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_get_statement ##### -->
+<para>
+
+</para>
+
+ builder: 
+ error: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_get_sql_statement ##### -->
+<para>
+
+</para>
+
+ builder: 
+ copy_it: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_set_table ##### -->
+<para>
+
+</para>
+
+ builder: 
+ table_name: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_add_field_value ##### -->
+<para>
+
+</para>
+
+ builder: 
+ field_name: 
+ value_id: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_literal ##### -->
+<para>
+
+</para>
+
+ builder: 
+ id: 
+ string: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_expr ##### -->
+<para>
+
+</para>
+
+ builder: 
+ id: 
+ dh: 
+ type: 
+ Varargs: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_param ##### -->
+<para>
+
+</para>
+
+ builder: 
+ id: 
+ param_name: 
+ type: 
+ nullok: 
+ Returns: 
+
+
+<!-- ##### FUNCTION gda_sql_builder_cond2 ##### -->
+<para>
+
+</para>
+
+ builder: 
+ id: 
+ op: 
+ op1: 
+ op2: 
+ Returns: 
+
+

Modified: trunk/doc/C/tmpl/gda-statement.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-statement.sgml	(original)
+++ trunk/doc/C/tmpl/gda-statement.sgml	Thu Mar 19 17:28:35 2009
@@ -9,8 +9,8 @@
   The #GdaStatement represents a single SQL statement (multiple statements can be grouped in a #GdaBatch object).
 </para>
 <para>
-  A #GdaStatement can either be built "manually" by building a #GdaSqlStatement structure, or from an SQL statement using
-  a #GdaSqlParser object.
+  A #GdaStatement can either be built by describing its constituing parts using a #GdaSqlBuilder object,
+  or from an SQL statement using a #GdaSqlParser object.
 </para>
 <para>
   A #GdaConnection can use a #GdaStatement to:

Modified: trunk/libgda/Makefile.am
==============================================================================
--- trunk/libgda/Makefile.am	(original)
+++ trunk/libgda/Makefile.am	Thu Mar 19 17:28:35 2009
@@ -70,6 +70,7 @@
 	gda-server-provider-private.h \
 	gda-statement.h \
 	gda-statement-extra.h \
+	gda-sql-builder.h \
 	gda-transaction-status.h \
 	gda-transaction-status-private.h \
 	gda-tree.h \
@@ -135,6 +136,7 @@
 	gda-server-provider.c \
 	gda-server-provider-extra.c \
 	gda-statement.c \
+	gda-sql-builder.c \
 	gda-transaction-status.c \
 	gda-tree.c \
 	gda-tree-mgr-columns.c \

Added: trunk/libgda/gda-sql-builder.c
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-sql-builder.c	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,740 @@
+/* gda-sql-builder.c
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * 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.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <stdarg.h>
+#include <libgda/gda-sql-builder.h>
+#include <libgda/gda-statement.h>
+#include <libgda/gda-data-handler.h>
+#include <libgda/gda-easy.h>
+
+/*
+ * Main static functions
+ */
+static void gda_sql_builder_class_init (GdaSqlBuilderClass *klass);
+static void gda_sql_builder_init (GdaSqlBuilder *builder);
+static void gda_sql_builder_dispose (GObject *object);
+static void gda_sql_builder_finalize (GObject *object);
+
+static void gda_sql_builder_set_property (GObject *object,
+					 guint param_id,
+					 const GValue *value,
+					 GParamSpec *pspec);
+static void gda_sql_builder_get_property (GObject *object,
+					 guint param_id,
+					 GValue *value,
+					 GParamSpec *pspec);
+
+static GStaticRecMutex init_mutex = G_STATIC_REC_MUTEX_INIT;
+
+
+typedef struct {
+	GdaSqlAnyPart *part;
+	gboolean       to_free; /* TRUE if @part is not included in a GdaSqlStatement, and needs to be freed */
+}  SqlPart;
+
+struct _GdaSqlBuilderPrivate {
+	GdaSqlStatement *main_stmt;
+	GHashTable *parts_hash; /* key = part ID as an guint, value = SqlPart */
+	guint next_assigned_id;
+};
+
+
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+/* signals */
+enum {
+	LAST_SIGNAL
+};
+
+static gint gda_sql_builder_signals[LAST_SIGNAL] = { };
+
+/* properties */
+enum {
+	PROP_0,
+};
+
+/* module error */
+GQuark gda_sql_builder_error_quark (void) {
+	static GQuark quark;
+	if (!quark)
+		quark = g_quark_from_static_string ("gda_sql_builder_error");
+	return quark;
+}
+
+GType
+gda_sql_builder_get_type (void) {
+	static GType type = 0;
+	
+	if (G_UNLIKELY (type == 0)) {
+		static const GTypeInfo info = {
+			sizeof (GdaSqlBuilderClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_sql_builder_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaSqlBuilder),
+			0,
+			(GInstanceInitFunc) gda_sql_builder_init
+		};
+		
+		g_static_rec_mutex_lock (&init_mutex);
+		if (type == 0)
+			type = g_type_register_static (G_TYPE_OBJECT, "GdaSqlBuilder", &info, 0);
+		g_static_rec_mutex_unlock (&init_mutex);
+	}
+	return type;
+}
+
+
+static void
+gda_sql_builder_class_init (GdaSqlBuilderClass *klass) 
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+	
+	/* Properties */
+	object_class->set_property = gda_sql_builder_set_property;
+	object_class->get_property = gda_sql_builder_get_property;
+	object_class->dispose = gda_sql_builder_dispose;
+	object_class->finalize = gda_sql_builder_finalize;
+}
+
+static void
+any_part_free (SqlPart *part)
+{
+	if (part->to_free) {
+		TO_IMPLEMENT;
+	}
+	g_free (part);
+}
+
+static void
+gda_sql_builder_init (GdaSqlBuilder *builder) 
+{
+	builder->priv = g_new0 (GdaSqlBuilderPrivate, 1);
+	builder->priv->main_stmt = NULL;
+	builder->priv->parts_hash = g_hash_table_new_full (g_int_hash, g_int_equal,
+							   g_free, (GDestroyNotify) any_part_free);
+	builder->priv->next_assigned_id = G_MAXUINT;
+}
+
+
+/**
+ * gda_sql_builder_new
+ * @stmt_type: the type of statement to build
+ *
+ * Create a new #GdaSqlBuilder object to build #GdaStatement or #GdaSqlStatement
+ * objects of type @stmt_type
+ *
+ * Returns: the newly created object, or %NULL if an error occurred (such as unsupported
+ * statement type)
+ *
+ * Since: 4.2
+ */
+GdaSqlBuilder *
+gda_sql_builder_new (GdaSqlStatementType stmt_type) 
+{
+	GdaSqlBuilder *builder;
+
+	g_return_val_if_fail ((stmt_type == GDA_SQL_STATEMENT_SELECT) ||
+			      (stmt_type == GDA_SQL_STATEMENT_UPDATE) ||
+			      (stmt_type == GDA_SQL_STATEMENT_INSERT) ||
+			      (stmt_type == GDA_SQL_STATEMENT_DELETE), NULL);
+	builder = (GdaSqlBuilder*) g_object_new (GDA_TYPE_SQL_BUILDER, NULL);
+	builder->priv->main_stmt = gda_sql_statement_new (stmt_type);
+	/* FIXME: use a property here and check type for SELECT, INSERT, UPDATE or DELETE only */
+	return builder;
+}
+
+
+static void
+gda_sql_builder_dispose (GObject *object) 
+{
+	GdaSqlBuilder *builder;
+	
+	g_return_if_fail (GDA_IS_SQL_BUILDER (object));
+	
+	builder = GDA_SQL_BUILDER (object);
+	if (builder->priv) {
+		if (builder->priv->main_stmt) {
+			gda_sql_statement_free (builder->priv->main_stmt);
+			builder->priv->main_stmt = NULL;
+		}
+		if (builder->priv->parts_hash) {
+			g_hash_table_destroy (builder->priv->parts_hash);
+			builder->priv->parts_hash = NULL;
+		}
+	}
+	
+	/* parent class */
+	parent_class->dispose (object);
+}
+
+static void
+gda_sql_builder_finalize (GObject *object)
+{
+	GdaSqlBuilder *builder;
+	
+	g_return_if_fail (object != NULL);
+	g_return_if_fail (GDA_IS_SQL_BUILDER (object));
+	
+	builder = GDA_SQL_BUILDER (object);
+	if (builder->priv) {
+		g_free (builder->priv);
+		builder->priv = NULL;
+	}
+	
+	/* parent class */
+	parent_class->finalize (object);
+}
+
+static void
+gda_sql_builder_set_property (GObject *object,
+			     guint param_id,
+			     const GValue *value,
+			     GParamSpec *pspec) 
+{
+	GdaSqlBuilder *builder;
+	
+	builder = GDA_SQL_BUILDER (object);
+	if (builder->priv) {
+		switch (param_id) {
+		}
+	}
+}
+
+static void
+gda_sql_builder_get_property (GObject *object,
+			     guint param_id,
+			     GValue *value,
+			     GParamSpec *pspec) 
+{
+	GdaSqlBuilder *builder;
+	builder = GDA_SQL_BUILDER (object);
+	
+	if (builder->priv) {
+		switch (param_id) {
+		}
+	}
+}
+
+static guint
+add_part (GdaSqlBuilder *builder, guint id, GdaSqlAnyPart *part)
+{
+	SqlPart *p;
+	guint *realid = g_new0 (guint, 1);
+	if (id == 0)
+		id = builder->priv->next_assigned_id --;
+	*realid = id;
+	p = g_new0 (SqlPart, 1);
+	p->part = part;
+	p->to_free = TRUE; /* p->part not used yet in GdaSqlStatement */
+	g_hash_table_insert (builder->priv->parts_hash, realid, p);
+	return id;
+}
+
+static SqlPart *
+get_part (GdaSqlBuilder *builder, guint id, GdaSqlAnyPartType req_type)
+{
+	SqlPart *p;
+	guint lid = id;
+	if (id == 0)
+		return NULL;
+	p = g_hash_table_lookup (builder->priv->parts_hash, &lid);
+	if (!p) {
+		g_warning (_("Unknown part ID %u"), id);
+		return NULL;
+	}
+	if (p->part->type != req_type) {
+		g_warning (_("Unknown part type"));
+		return NULL;
+	}
+	return p;
+}
+
+static GdaSqlAnyPart *
+use_part (SqlPart *p, GdaSqlAnyPart *parent)
+{
+	if (!p)
+		return NULL;
+
+	if (p->to_free) {
+		/* take ownership */
+		p->to_free = FALSE;
+		p->part->parent = parent;
+		return p->part;
+	}
+	else {
+		/* copy */
+		GdaSqlAnyPart *anyp = NULL;
+		switch (p->part->type) {
+		case GDA_SQL_ANY_EXPR:
+			anyp = (GdaSqlAnyPart*) gda_sql_expr_copy ((GdaSqlExpr*) p->part);
+			break;
+		default:
+			TO_IMPLEMENT;
+			return NULL;
+		}
+		if (anyp)
+			anyp->parent = parent;
+		return anyp;
+	}
+}
+
+/**
+ * gda_sql_builder_get_statement
+ * @builder: a #GdaSqlBuilder object
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #GdaStatement statement from @builder's contents.
+ *
+ * Returns: a new #GdaStatement object, or %NULL if an error occurred
+ *
+ * Since: 4.2
+ */
+GdaStatement *
+gda_sql_builder_get_statement (GdaSqlBuilder *builder, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), NULL);
+	if (!builder->priv->main_stmt) {
+		g_set_error (error, GDA_SQL_BUILDER_ERROR, GDA_SQL_BUILDER_MISUSE_ERROR,
+			     _("SqlBuilder is empty"));
+		return NULL;
+	}
+	if (! gda_sql_statement_check_structure (builder->priv->main_stmt, error))
+		return NULL;
+
+	return (GdaStatement*) g_object_new (GDA_TYPE_STATEMENT, "structure", builder->priv->main_stmt, NULL);
+}
+
+/**
+ * gda_sql_builder_get_sql_statement
+ * @builder: a #GdaSqlBuilder object
+ * @copy_it: set to %TRUE to be able to reuse @builder
+ *
+ * Creates a new #GdaSqlStatement structure from @builder's contents.
+ *
+ * If @copy_it is %FALSE, then the returned pointer is considered to be stolen from @builder's internal
+ * representation and will make it unuseable anymore (resulting in a %GDA_SQL_BUILDER_MISUSE_ERROR error or
+ * some warnings if one tries to reuse it).
+ * If, on the other
+ * hand it is set to %TRUE, then the returned #GdaSqlStatement is a copy of the on @builder uses
+ * internally, making it reuseable.
+ *
+ * Returns: a #GdaSqlStatement pointer
+ *
+ * Since: 4.2
+ */
+GdaSqlStatement *
+gda_sql_builder_get_sql_statement (GdaSqlBuilder *builder, gboolean copy_it)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), NULL);
+	if (!builder->priv->main_stmt) 
+		return NULL;
+	if (copy_it)
+		return gda_sql_statement_copy (builder->priv->main_stmt);
+	else {
+		GdaSqlStatement *stmt = builder->priv->main_stmt;
+		builder->priv->main_stmt = NULL;
+		return stmt;
+	}
+}
+
+/**
+ * gda_sql_builder_set_table
+ * @builder: a #GdaSqlBuilder object
+ * @table_name: a table name
+ *
+ * Valid only for: INSERT, UPDATE, DELETE statements
+ *
+ * Sets the name of the table on which the built statement operates.
+ *
+ * Since: 4.2
+ */
+void
+gda_sql_builder_set_table (GdaSqlBuilder *builder, const gchar *table_name)
+{
+	g_return_if_fail (GDA_IS_SQL_BUILDER (builder));
+	g_return_if_fail (builder->priv->main_stmt);
+	g_return_if_fail (table_name && *table_name);
+
+	GdaSqlTable *table = NULL;
+
+	switch (builder->priv->main_stmt->stmt_type) {
+	case GDA_SQL_STATEMENT_DELETE: {
+		GdaSqlStatementDelete *del = (GdaSqlStatementDelete*) builder->priv->main_stmt->contents;
+		if (!del->table)
+			del->table = gda_sql_table_new (GDA_SQL_ANY_PART (del));
+		table = del->table;
+		break;
+	}
+	case GDA_SQL_STATEMENT_UPDATE: {
+		GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) builder->priv->main_stmt->contents;
+		if (!upd->table)
+			upd->table = gda_sql_table_new (GDA_SQL_ANY_PART (upd));
+		table = upd->table;
+		break;
+	}
+	case GDA_SQL_STATEMENT_INSERT: {
+		GdaSqlStatementInsert *ins = (GdaSqlStatementInsert*) builder->priv->main_stmt->contents;
+		if (!ins->table)
+			ins->table = gda_sql_table_new (GDA_SQL_ANY_PART (ins));
+		table = ins->table;
+		break;
+	}
+	default:
+		g_warning (_("Wrong statement type"));
+		break;
+	}
+
+	g_assert (table);
+	if (table->table_name)
+		g_free (table->table_name);
+	table->table_name = g_strdup (table_name);
+}
+
+/**
+ * gda_sql_builder_set_where
+ * @builder: a #GdaSqlBuilder object
+ * @cond_id: the ID of the expression to set as WHERE condition, or 0 to unset any previous WHERE condition
+ *
+ * Valid only for: UPDATE, DELETE, SELECT statements
+ *
+ * Sets the WHERE condition of the statement
+ *
+ * Since: 4.2
+ */
+void
+gda_sql_builder_set_where (GdaSqlBuilder *builder, guint cond_id)
+{
+	g_return_if_fail (GDA_IS_SQL_BUILDER (builder));
+	g_return_if_fail (builder->priv->main_stmt);
+
+	SqlPart *p = NULL;
+	if (cond_id > 0) {
+		p = get_part (builder, cond_id, GDA_SQL_ANY_EXPR);
+		if (!p)
+			return;
+	}
+
+	switch (builder->priv->main_stmt->stmt_type) {
+	case GDA_SQL_STATEMENT_UPDATE: {
+		GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) builder->priv->main_stmt->contents;
+		if (upd->cond)
+			gda_sql_expr_free (upd->cond);
+		upd->cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (upd));
+		break;
+	}
+	case GDA_SQL_STATEMENT_DELETE:{
+		GdaSqlStatementDelete *del = (GdaSqlStatementDelete*) builder->priv->main_stmt->contents;
+		if (del->cond)
+			gda_sql_expr_free (del->cond);
+		del->cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (del));
+		break;
+	}
+	case GDA_SQL_STATEMENT_SELECT:{
+		GdaSqlStatementSelect *sel = (GdaSqlStatementSelect*) builder->priv->main_stmt->contents;
+		if (sel->where_cond)
+			gda_sql_expr_free (sel->where_cond);
+		sel->where_cond = (GdaSqlExpr*) use_part (p, GDA_SQL_ANY_PART (sel));
+		break;
+	}
+	default:
+		g_warning (_("Wrong statement type"));
+		break;
+	}
+}
+
+
+/**
+ * gda_sql_builder_add_field_value
+ * @builder: a #GdaSqlBuilder object
+ * @field_name: a field name
+ * @value_id: the ID of the value to set the field to
+ *
+ * Valid only for: INSERT, UPDATE statements
+ *
+ * Specifies that the field named @field_name will be set to the value identified by @value_id.
+ *
+ * Since: 4.2
+ */
+void
+gda_sql_builder_add_field_value (GdaSqlBuilder *builder, const gchar *field_name, guint value_id)
+{
+	g_return_if_fail (GDA_IS_SQL_BUILDER (builder));
+	g_return_if_fail (builder->priv->main_stmt);
+	g_return_if_fail (field_name && *field_name);
+	g_return_if_fail (value_id > 0);
+
+	SqlPart *p;
+	p = get_part (builder, value_id, GDA_SQL_ANY_EXPR);
+	if (!p)
+		return;
+
+	GdaSqlField *field = gda_sql_field_new (GDA_SQL_ANY_PART (builder->priv->main_stmt->contents));
+	field->field_name = g_strdup (field_name);
+
+	switch (builder->priv->main_stmt->stmt_type) {
+	case GDA_SQL_STATEMENT_UPDATE: {
+		GdaSqlStatementUpdate *upd = (GdaSqlStatementUpdate*) builder->priv->main_stmt->contents;
+		upd->fields_list = g_slist_append (upd->fields_list, field);
+		upd->expr_list = g_slist_append (upd->expr_list, use_part (p, GDA_SQL_ANY_PART (upd)));
+
+		break;
+	}
+	case GDA_SQL_STATEMENT_INSERT:{
+		GdaSqlStatementInsert *ins = (GdaSqlStatementInsert*) builder->priv->main_stmt->contents;
+		ins->fields_list = g_slist_append (ins->fields_list, field);
+
+		
+		if (! ins->values_list)
+			ins->values_list = g_slist_append (NULL,
+							   g_slist_append (NULL, use_part (p, GDA_SQL_ANY_PART (ins))));
+		else
+			ins->values_list->data = g_slist_append ((GSList*) ins->values_list->data, 
+								 use_part (p, GDA_SQL_ANY_PART (ins)));
+		break;
+	}
+	default:
+		g_warning (_("Wrong statement type"));
+		break;
+	}
+}
+
+/**
+ * gda_sql_builder_expr
+ * @builder: a #GdaSqlBuilder object
+ * @id: the requested ID, or 0 if to be determined by @builder
+ * @dh: a #GdaDataHandler to use, or %NULL
+ * @type: the GType of the following argument
+ * @...: value to set the expression to, of the type specified by @type
+ *
+ * Defines an expression in @builder which may be reused to build other parts of a statement.
+ *
+ * The new expression will contain the value passed as the @... argument. It is possible to
+ * customize how the value has to be interpreted by passing a specific #GdaDataHandler object as @dh.
+ *
+ * For example:
+ * <programlisting>
+ * gda_sql_builder_expr (b, 0, G_TYPE_INT, 15);
+ * gda_sql_builder_expr (b, 5, G_TYPE_STRING, "joe")
+ * </programlisting>
+ *
+ * will be rendered as SQL as:
+ * <programlisting>
+ * 15
+ * 'joe'
+ * </programlisting>
+ *
+ * Returns: the ID of the new expression, or 0 if there was an error
+ *
+ * Since: 4.2
+ */
+guint
+gda_sql_builder_expr (GdaSqlBuilder *builder, guint id, GdaDataHandler *dh, GType type, ...)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0);
+	g_return_val_if_fail (builder->priv->main_stmt, 0);
+	
+	va_list ap;
+	gchar *str;
+	GValue *v = NULL;
+
+	if (!dh)
+		dh = gda_get_default_handler (type);
+	else {
+		if (! gda_data_handler_accepts_g_type (dh, type)) {
+			g_warning (_("Unhandled data type '%s'"), g_type_name (type));
+			return 0;
+		}
+	}
+	if (!dh) {
+		g_warning (_("Unhandled data type '%s'"), g_type_name (type));
+		return 0;
+	}
+
+	va_start (ap, type);
+	if (type == G_TYPE_STRING) {
+		g_value_set_string ((v = gda_value_new (G_TYPE_STRING)), va_arg (ap, gchar*));
+		str = gda_data_handler_get_sql_from_value (dh, v);
+	}
+	else if (type == G_TYPE_INT) {
+		g_value_set_int ((v = gda_value_new (G_TYPE_INT)), va_arg (ap, gint));
+		str = gda_data_handler_get_sql_from_value (dh, v);
+	}
+	va_end (ap);
+
+	if (v)
+		gda_value_free (v);
+
+	if (str) {
+		GdaSqlExpr *expr;
+		expr = gda_sql_expr_new (NULL);
+		expr->value = gda_value_new (G_TYPE_STRING);
+		g_value_take_string (expr->value, str);
+		return add_part (builder, id, (GdaSqlAnyPart *) expr);
+	}
+	else {
+		g_warning (_("Could not convert value to type '%s'"), g_type_name (type));
+		return 0;
+	}
+}
+
+/**
+ * gda_sql_builder_literal
+ * @builder: a #GdaSqlBuilder object
+ * @id: the requested ID, or 0 if to be determined by @builder
+ * @string: a string
+ *
+ * Defines an expression in @builder which may be reused to build other parts of a statement.
+ *
+ * The new expression will contain the @string literal.
+ * For example:
+ * <programlisting>
+ * gda_sql_builder_expr_liretal (b, 0, "name")
+ * </programlisting>
+ *
+ * will be rendered as SQL as:
+ * <programlisting>
+ * name
+ * </programlisting>
+ *
+ * Returns: the ID of the new expression, or 0 if there was an error
+ *
+ * Since: 4.2
+ */
+guint
+gda_sql_builder_literal (GdaSqlBuilder *builder, guint id, const gchar *string)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0);
+	g_return_val_if_fail (builder->priv->main_stmt, 0);
+	
+	GdaSqlExpr *expr;
+	expr = gda_sql_expr_new (NULL);
+	if (string) {
+		expr->value = gda_value_new (G_TYPE_STRING);
+		g_value_set_string (expr->value, string);
+	}
+	
+	return add_part (builder, id, (GdaSqlAnyPart *) expr);
+}
+
+/**
+ * gda_sql_builder_param
+ * @builder: a #GdaSqlBuilder object
+ * @id: the requested ID, or 0 if to be determined by @builder
+ * @param_name: parameter's name
+ * @type: parameter's type
+ * @nullok: TRUE if the parameter can be set to %NULL
+ *
+ * Defines a parameter in @builder which may be reused to build other parts of a statement.
+ *
+ * The new expression will contain the @string literal.
+ * For example:
+ * <programlisting>
+ * gda_sql_builder_param (b, 0, "age", G_TYPE_INT, FALSE)
+ * </programlisting>
+ *
+ * will be rendered as SQL as:
+ * <programlisting><![CDATA[
+ * ##age::int
+ * ]]>
+ * </programlisting>
+ *
+ * Returns: the ID of the new expression, or 0 if there was an error
+ *
+ * Since: 4.2
+ */
+guint
+gda_sql_builder_param (GdaSqlBuilder *builder, guint id, const gchar *param_name, GType type, gboolean nullok)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0);
+	g_return_val_if_fail (builder->priv->main_stmt, 0);
+	g_return_val_if_fail (param_name && *param_name, 0);
+	
+	GdaSqlExpr *expr;
+	expr = gda_sql_expr_new (NULL);
+	expr->param_spec = g_new0 (GdaSqlParamSpec, 1);
+	expr->param_spec->name = g_strdup (param_name);
+	expr->param_spec->is_param = TRUE;
+	expr->param_spec->nullok = nullok;
+	expr->param_spec->g_type = type;
+
+	return add_part (builder, id, (GdaSqlAnyPart *) expr);
+}
+
+guint
+gda_sql_builder_cond1 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1)
+{
+	TO_IMPLEMENT;
+	return 0;
+}
+
+
+/**
+ * gda_sql_builder_cond2
+ * @builder: a #GdaSqlBuilder object
+ * @id: the requested ID, or 0 if to be determined by @builder
+ * @op: type of condition
+ * @op1: the ID of the 1st argument (not 0)
+ * @op2: the ID of the 2nd argument (not 0)
+ *
+ * Builds a new expression which reprenents a condition (or operation) with two operands.
+ *
+ * Returns: the ID of the new expression, or 0 if there was an error
+ *
+ * Since: 4.2
+ */
+guint
+gda_sql_builder_cond2 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1, guint op2)
+{
+	g_return_val_if_fail (GDA_IS_SQL_BUILDER (builder), 0);
+	g_return_val_if_fail (builder->priv->main_stmt, 0);
+
+	SqlPart *p1, *p2;
+	p1 = get_part (builder, op1, GDA_SQL_ANY_EXPR);
+	if (!p1)
+		return 0;
+	p2 = get_part (builder, op2, GDA_SQL_ANY_EXPR);
+	if (!p2)
+		return 0;
+	
+	GdaSqlExpr *expr;
+	expr = gda_sql_expr_new (NULL);
+	expr->cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
+	expr->cond->operator_type = op;
+	expr->cond->operands = g_slist_append (NULL, use_part (p1, GDA_SQL_ANY_PART (expr->cond)));
+	expr->cond->operands = g_slist_append (expr->cond->operands, use_part (p2, GDA_SQL_ANY_PART (expr->cond)));
+
+	return add_part (builder, id, (GdaSqlAnyPart *) expr);
+}
+
+
+guint
+gda_sql_builder_cond3 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1, guint op2, guint op3)
+{
+	TO_IMPLEMENT;
+	return 0;
+}

Added: trunk/libgda/gda-sql-builder.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-sql-builder.h	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,89 @@
+/* gda-sql-builder.h
+ *
+ * Copyright (C) 2009 Vivien Malerba
+ *
+ * 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_SQL_BUILDER_H_
+#define __GDA_SQL_BUILDER_H_
+
+#include <glib-object.h>
+#include <sql-parser/gda-sql-statement.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_SQL_BUILDER          (gda_sql_builder_get_type())
+#define GDA_SQL_BUILDER(obj)          G_TYPE_CHECK_INSTANCE_CAST (obj, gda_sql_builder_get_type(), GdaSqlBuilder)
+#define GDA_SQL_BUILDER_CLASS(klass)  G_TYPE_CHECK_CLASS_CAST (klass, gda_sql_builder_get_type (), GdaSqlBuilderClass)
+#define GDA_IS_SQL_BUILDER(obj)       G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_sql_builder_get_type ())
+
+typedef struct _GdaSqlBuilder        GdaSqlBuilder;
+typedef struct _GdaSqlBuilderClass   GdaSqlBuilderClass;
+typedef struct _GdaSqlBuilderPrivate GdaSqlBuilderPrivate;
+
+/* error reporting */
+extern GQuark gda_sql_builder_error_quark (void);
+#define GDA_SQL_BUILDER_ERROR gda_sql_builder_error_quark ()
+
+typedef enum {
+	GDA_SQL_BUILDER_WRONG_TYPE_ERROR,
+	GDA_SQL_BUILDER_MISUSE_ERROR
+} GdaSqlBuilderError;
+
+
+/* struct for the object's data */
+struct _GdaSqlBuilder
+{
+	GObject               object;
+	GdaSqlBuilderPrivate  *priv;
+};
+
+/* struct for the object's class */
+struct _GdaSqlBuilderClass
+{
+	GObjectClass              parent_class;
+
+	/* Padding for future expansion */
+	void (*_gda_reserved1) (void);
+	void (*_gda_reserved2) (void);
+	void (*_gda_reserved3) (void);
+	void (*_gda_reserved4) (void);
+};
+
+GType             gda_sql_builder_get_type       (void) G_GNUC_CONST;
+GdaSqlBuilder    *gda_sql_builder_new            (GdaSqlStatementType stmt_type);
+GdaStatement     *gda_sql_builder_get_statement (GdaSqlBuilder *builder, GError **error);
+GdaSqlStatement  *gda_sql_builder_get_sql_statement (GdaSqlBuilder *builder, gboolean copy_it);
+
+/* Expression API */
+guint              gda_sql_builder_literal (GdaSqlBuilder *builder, guint id, const gchar *string);
+guint              gda_sql_builder_expr (GdaSqlBuilder *builder, guint id, GdaDataHandler *dh, GType type, ...);
+guint              gda_sql_builder_param (GdaSqlBuilder *builder, guint id, const gchar *param_name, GType type, gboolean nullok);
+
+guint              gda_sql_builder_cond1 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1);
+guint              gda_sql_builder_cond2 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1, guint op2);
+guint              gda_sql_builder_cond3 (GdaSqlBuilder *builder, guint id, GdaSqlOperatorType op, guint op1, guint op2, guint op3);
+
+/* General Statement API */
+void              gda_sql_builder_set_table (GdaSqlBuilder *builder, const gchar *table_name);
+void              gda_sql_builder_set_where (GdaSqlBuilder *builder, guint cond_id);
+
+void              gda_sql_builder_add_field_value (GdaSqlBuilder *builder, const gchar *field_name, guint value_id);
+
+G_END_DECLS
+
+#endif

Modified: trunk/libgda/libgda.h.in
==============================================================================
--- trunk/libgda/libgda.h.in	(original)
+++ trunk/libgda/libgda.h.in	Thu Mar 19 17:28:35 2009
@@ -80,6 +80,8 @@
 #include <libgda/gda-tree-mgr-tables.h> 
 #include <libgda/gda-tree-node.h>
 
+#include <libgda/gda-sql-builder.h>
+
 #include <libgda/gda-meta-store.h>
 
 #include <libgda/gda-mutex.h>

Modified: trunk/samples/Makefile
==============================================================================
--- trunk/samples/Makefile	(original)
+++ trunk/samples/Makefile	Thu Mar 19 17:28:35 2009
@@ -1,5 +1,5 @@
 SHELL= /bin/sh 
-SUBDIRS = BDB DDL DirDataModel F-Spot Report SimpleExample SqlParserConsole TableCopy Virtual XSLT MetaStore Tree
+SUBDIRS = BDB DDL DirDataModel F-Spot Report SimpleExample SqlParserConsole TableCopy Virtual XSLT MetaStore Tree SqlBuilder
 all:
 	for dir in ${SUBDIRS} ; do ( cd $$dir ; ${MAKE} ) ; done
 clean:

Modified: trunk/samples/README
==============================================================================
--- trunk/samples/README	(original)
+++ trunk/samples/README	Thu Mar 19 17:28:35 2009
@@ -18,5 +18,6 @@
 * in SqlParserConsole/: simple console to test how the GdaSqlParser object parses strings
 * in MetaStore/: simple example to show how to use and update a GdaMetaStore
 * in Tree/: simple example to show how to use the GdaTree object
+* in SqlBuilder: simple example to show how to use GdaSqlBuilder object to build various statements
 
 Good luck and happy hacking!

Added: trunk/samples/SqlBuilder/Makefile
==============================================================================
--- (empty file)
+++ trunk/samples/SqlBuilder/Makefile	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,12 @@
+CFLAGS = -Wall -g -DGDA_DISABLE_DEPRECATED `pkg-config --cflags libgda-4.0`
+LDFLAGS = `pkg-config --libs libgda-4.0`
+
+all: example
+
+example: example.c
+	$(CC) -o example example.c $(CFLAGS) $(LDFLAGS)
+
+clean:
+	rm -f *~
+	rm -f *.o
+	rm -f example

Added: trunk/samples/SqlBuilder/README
==============================================================================
--- (empty file)
+++ trunk/samples/SqlBuilder/README	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,24 @@
+Libgda simple example
+=====================
+
+Description:
+------------
+
+The example in this directory illustrate how to use a GdaSqlBuilder to build statement from their structure
+
+Compiling and running:
+----------------------
+
+To compile (make sure Libgda is installed prior to this):
+> make
+
+and to run:
+> ./example
+
+Output:
+-------
+Running should produce the following output:
+
+SQL: INSERT INTO customers (e, f, g) VALUES (##p1::string, 15, 'joe')
+SQL: UPDATE products SET ref='A0E''FESP' WHERE id = 14
+SQL: UPDATE products SET ref='A0E''FESP' WHERE id = ##theid::int

Added: trunk/samples/SqlBuilder/example.c
==============================================================================
--- (empty file)
+++ trunk/samples/SqlBuilder/example.c	Thu Mar 19 17:28:35 2009
@@ -0,0 +1,77 @@
+#include <libgda/libgda.h>
+
+void render_as_sql (GdaSqlBuilder *b);
+
+int
+main (int argc, char *argv[])
+{
+	gda_init ();
+
+	GdaSqlBuilder *b;
+	
+
+	/* INSERT INTO customers (e, f, g) VALUES (##p1::string, 15, 'joe') */
+	b = gda_sql_builder_new (GDA_SQL_STATEMENT_INSERT);
+
+	gda_sql_builder_set_table (b, "customers");
+
+	gda_sql_builder_add_field_value (b, "e", gda_sql_builder_param (b, 0, "p1", G_TYPE_STRING, FALSE));
+	gda_sql_builder_add_field_value (b, "f", gda_sql_builder_expr (b, 0, NULL, G_TYPE_INT, 15));
+	gda_sql_builder_add_field_value (b, "g", gda_sql_builder_expr (b, 0, NULL, G_TYPE_STRING, "joe"));
+	
+	render_as_sql (b);
+	g_object_unref (b);
+
+
+	/* UPDATE products set ref='A0E''FESP' WHERE id = 14 */
+	b = gda_sql_builder_new (GDA_SQL_STATEMENT_UPDATE);
+
+	gda_sql_builder_set_table (b, "products");
+	gda_sql_builder_add_field_value (b, "ref", gda_sql_builder_expr (b, 10, NULL, G_TYPE_STRING, "A0E'FESP"));
+	gda_sql_builder_literal (b, 1, "id");
+	gda_sql_builder_expr (b, 2, NULL, G_TYPE_INT, 14);
+	gda_sql_builder_cond2 (b, 3, GDA_SQL_OPERATOR_TYPE_EQ, 1, 2);
+	gda_sql_builder_set_where (b, 3);
+
+	render_as_sql (b);
+
+	/* reuse the same GdaSqlBuilder object to change the WHERE condition to: WHERE id = ##theid::int */
+	gda_sql_builder_set_where (b,
+				   gda_sql_builder_cond2 (b, 0, GDA_SQL_OPERATOR_TYPE_EQ,
+							  1,
+							  gda_sql_builder_param (b, 0, "theid", G_TYPE_INT, FALSE)));
+	render_as_sql (b);
+	g_object_unref (b);
+
+	return 0;
+}
+
+void
+render_as_sql (GdaSqlBuilder *b)
+{
+	GdaStatement *stmt;
+	GError *error = NULL;
+
+	stmt = gda_sql_builder_get_statement (b, &error);
+	if (!stmt) {
+		g_print ("Statement error: %s\n",
+			 error && error->message ? error->message : "No detail");
+		if (error)
+			g_error_free (error);
+	}
+	else {
+		gchar *sql;
+		sql = gda_statement_to_sql (stmt, NULL, &error);
+		if (!sql) {
+			g_print ("SQL rendering error: %s\n",
+				 error && error->message ? error->message : "No detail");
+			if (error)
+				g_error_free (error);
+		}
+		else {
+			g_print ("SQL: %s\n", sql);
+			g_free (sql);
+		}		
+		g_object_unref (stmt);
+	}
+}



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