libgda r3360 - in trunk: . doc/C doc/C/tmpl libgda samples samples/SqlBuilder
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3360 - in trunk: . doc/C doc/C/tmpl libgda samples samples/SqlBuilder
- Date: Thu, 19 Mar 2009 17:28:35 +0000 (UTC)
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]