libgda r3122 - in trunk: . providers providers/mysql
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3122 - in trunk: . providers providers/mysql
- Date: Sun, 6 Apr 2008 17:06:43 +0100 (BST)
Author: vivien
Date: Sun Apr 6 17:06:43 2008
New Revision: 3122
URL: http://svn.gnome.org/viewvc/libgda?rev=3122&view=rev
Log:
2008-04-06 Vivien Malerba <malerba gnome-db org>
* configure.in:
* providers/Makefile.am:
* providers/mysql/*: merged Carlos Savoretti's preliminary MySQL provider's
rework
Added:
trunk/providers/mysql/gda-mysql-blob-op.c
trunk/providers/mysql/gda-mysql-blob-op.h
trunk/providers/mysql/gda-mysql-meta.c
trunk/providers/mysql/gda-mysql-meta.h
trunk/providers/mysql/gda-mysql-parser.c
trunk/providers/mysql/gda-mysql-parser.h
trunk/providers/mysql/gda-mysql-pstmt.c
trunk/providers/mysql/gda-mysql-pstmt.h
trunk/providers/mysql/gda-mysql-util.c
trunk/providers/mysql/gda-mysql-util.h
trunk/providers/mysql/gen_def.c
trunk/providers/mysql/parser.y
Modified:
trunk/ChangeLog
trunk/configure.in
trunk/providers/Makefile.am
trunk/providers/mysql/ (props changed)
trunk/providers/mysql/Makefile.am
trunk/providers/mysql/gda-mysql-provider.c
trunk/providers/mysql/gda-mysql-provider.h
trunk/providers/mysql/gda-mysql-recordset.c
trunk/providers/mysql/gda-mysql-recordset.h
trunk/providers/mysql/gda-mysql.h
trunk/providers/mysql/libgda-mysql-4.0.pc.in
trunk/providers/mysql/libmain.c
Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in (original)
+++ trunk/configure.in Sun Apr 6 17:06:43 2008
@@ -1190,6 +1190,8 @@
providers/bdb/libgda-bdb-4.0.pc
providers/mdb/Makefile
providers/mdb/libgda-mdb-4.0.pc
+providers/mysql/Makefile
+providers/mysql/libgda-mysql-4.0.pc
providers/postgres/Makefile
providers/postgres/libgda-postgres-4.0.pc
providers/sqlite/Makefile
@@ -1232,7 +1234,7 @@
dnl echo " FreeTDS = `if test x$freetdsdir != x; then echo yes; else echo no; fi`"
dnl echo " IBM DB2 = `if test x$ibmdb2dir != x; then echo yes; else echo no; fi`"
echo " MDB (MS Access) = `if test x$mdbdir != x; then echo yes; else echo no; fi`"
-dnl echo " MySQL = `if test x$mysqldir != x; then echo yes; else echo no; fi`"
+echo " MySQL = `if test x$mysqldir != x; then echo yes; else echo no; fi`"
dnl echo " mSQL = `if test x$msqldir != x; then echo yes; else echo no; fi`"
dnl echo " ODBC = `if test x$odbcdir != x; then echo yes; else echo no; fi`"
dnl echo " Oracle = `if test x$oracledir != x; then echo yes; else echo no; fi`"
Modified: trunk/providers/Makefile.am
==============================================================================
--- trunk/providers/Makefile.am (original)
+++ trunk/providers/Makefile.am Sun Apr 6 17:06:43 2008
@@ -55,11 +55,11 @@
skel-implementation \
$(GDA_BDB_SERVER) \
$(GDA_MDB_SERVER) \
- $(GDA_POSTGRES_SERVER)
+ $(GDA_POSTGRES_SERVER) \
+ $(GDA_MYSQL_SERVER)
# $(GDA_FREETDS_SERVER) \
# $(GDA_IBMDB2_SERVER) \
# $(GDA_FIREBIRD_SERVER) \
-# $(GDA_MYSQL_SERVER) \
# $(GDA_MSQL_SERVER) \
# $(GDA_ODBC_SERVER) \
# $(GDA_ORACLE_SERVER) \
Modified: trunk/providers/mysql/Makefile.am
==============================================================================
--- trunk/providers/mysql/Makefile.am (original)
+++ trunk/providers/mysql/Makefile.am Sun Apr 6 17:06:43 2008
@@ -1,29 +1,54 @@
providerdir=$(libdir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/providers
provider_LTLIBRARIES = libgda-mysql.la
+#Rem: MYSQL_CFLAGS and MYSQL_LIBS are the compile and link flags necessary to use the
+# C API. It is specific to the API and should be computed in the configure.in script.
+
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(top_srcdir)/libgda \
-I$(top_builddir) \
- $(LIBGDA_CFLAGS) \
- $(MYSQL_CFLAGS) \
- -DGDA_PACKAGE_VERSION=\""$(PACKAGE_VERSION)"\"
+ $(LIBGDA_CFLAGS) $(MYSQL_CFLAGS)
+
+# parser generation
+parser.c parser.h: parser.y $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD)
+ - $(top_builddir)/libgda/sql-parser/lemon$(EXEEXT_FOR_BUILD) parser.y
+
+gen_def$(EXEEXT_FOR_BUILD): gen_def.c
+ $(CC_FOR_BUILD) -o gen_def$(EXEEXT_FOR_BUILD) -DIMPOSED_HEADER=\""$(top_builddir)/libgda/sql-parser/parser_tokens.h"\" gen_def.c
+
+mysql_token_types.h: gen_def$(EXEEXT_FOR_BUILD) parser.h
+ ./gen_def$(EXEEXT_FOR_BUILD) > mysql_token_types.h
+
+$(OBJECTS) $(libgda_mysql_la_OBJECTS): mysql_token_types.h
libgda_mysql_la_SOURCES = \
+ gda-mysql-blob-op.c \
+ gda-mysql-blob-op.h \
gda-mysql-ddl.c \
- gda-mysql-ddl.h \
+ gda-mysql-ddl.h \
+ gda-mysql-parser.c \
+ gda-mysql-parser.h \
gda-mysql-provider.c \
gda-mysql-provider.h \
+ gda-mysql-meta.c \
+ gda-mysql-meta.h \
gda-mysql-recordset.c \
gda-mysql-recordset.h \
+ gda-mysql-util.c \
+ gda-mysql-util.h \
+ gda-mysql-pstmt.c \
+ gda-mysql-pstmt.h \
gda-mysql.h \
libmain.c \
- utils.c
+ parser.h \
+ parser.c \
+ mysql_token_types.h
+
libgda_mysql_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED)
libgda_mysql_la_LIBADD = \
$(top_builddir)/libgda/libgda-4.0.la \
- $(LIBGDA_LIBS) \
- $(MYSQL_LIBS)
+ $(LIBGDA_LIBS) $(MYSQL_LIBS)
xmldir = $(datadir)/libgda-4.0
xml_in_files = \
@@ -47,5 +72,7 @@
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = libgda-mysql-4.0.pc
-EXTRA_DIST = $(xml_in_files) libgda-mysql-4.0.pc.in
+EXTRA_DIST = $(xml_in_files) libgda-mysql-4.0.pc.in parser.y
DISTCLEANFILES = $(xml_DATA)
+
+CLEANFILES = parser.h parser.c parser.out mysql_token_types.h gen_def$(EXEEXT_FOR_BUILD)
Added: trunk/providers/mysql/gda-mysql-blob-op.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-blob-op.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,198 @@
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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 <glib/gi18n-lib.h>
+#include <string.h>
+#include <libgda/libgda.h>
+#include "gda-mysql.h"
+#include "gda-mysql-blob-op.h"
+
+struct _GdaMysqlBlobOpPrivate {
+ GdaConnection *cnc;
+ /* TO_ADD: specific information describing a Blob in the C API */
+};
+
+static void gda_mysql_blob_op_class_init (GdaMysqlBlobOpClass *klass);
+static void gda_mysql_blob_op_init (GdaMysqlBlobOp *blob,
+ GdaMysqlBlobOpClass *klass);
+static void gda_mysql_blob_op_finalize (GObject *object);
+
+static glong gda_mysql_blob_op_get_length (GdaBlobOp *op);
+static glong gda_mysql_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
+static glong gda_mysql_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and finalize
+ */
+GType
+gda_mysql_blob_op_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdaMysqlBlobOpClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_mysql_blob_op_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaMysqlBlobOp),
+ 0,
+ (GInstanceInitFunc) gda_mysql_blob_op_init
+ };
+ type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaMysqlBlobOp", &info, 0);
+ }
+ return type;
+}
+
+static void
+gda_mysql_blob_op_init (GdaMysqlBlobOp *op,
+ GdaMysqlBlobOpClass *klass)
+{
+ g_print ("*** %s\n", __func__);
+ g_return_if_fail (GDA_IS_MYSQL_BLOB_OP (op));
+
+ op->priv = g_new0 (GdaMysqlBlobOpPrivate, 1);
+
+ /* initialize specific structure */
+ TO_IMPLEMENT;
+}
+
+static void
+gda_mysql_blob_op_class_init (GdaMysqlBlobOpClass *klass)
+{
+ g_print ("*** %s\n", __func__);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
+
+ parent_class = g_type_class_peek_parent (klass);
+
+ object_class->finalize = gda_mysql_blob_op_finalize;
+ blob_class->get_length = gda_mysql_blob_op_get_length;
+ blob_class->read = gda_mysql_blob_op_read;
+ blob_class->write = gda_mysql_blob_op_write;
+}
+
+static void
+gda_mysql_blob_op_finalize (GObject * object)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlBlobOp *pgop = (GdaMysqlBlobOp *) object;
+
+ g_return_if_fail (GDA_IS_MYSQL_BLOB_OP (pgop));
+
+ /* free specific information */
+ TO_IMPLEMENT;
+
+ g_free (pgop->priv);
+ pgop->priv = NULL;
+
+ parent_class->finalize (object);
+}
+
+GdaBlobOp *
+gda_mysql_blob_op_new (GdaConnection *cnc)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlBlobOp *pgop;
+
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+
+ pgop = g_object_new (GDA_TYPE_MYSQL_BLOB_OP, NULL);
+ pgop->priv->cnc = cnc;
+
+ return GDA_BLOB_OP (pgop);
+}
+
+/*
+ * Get length request
+ */
+static glong
+gda_mysql_blob_op_get_length (GdaBlobOp *op)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlBlobOp *pgop;
+
+ g_return_val_if_fail (GDA_IS_MYSQL_BLOB_OP (op), -1);
+ pgop = GDA_MYSQL_BLOB_OP (op);
+ g_return_val_if_fail (pgop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+
+ TO_IMPLEMENT;
+ return -1;
+}
+
+/*
+ * Blob read request
+ */
+static glong
+gda_mysql_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlBlobOp *pgop;
+ GdaBinary *bin;
+
+ g_return_val_if_fail (GDA_IS_MYSQL_BLOB_OP (op), -1);
+ pgop = GDA_MYSQL_BLOB_OP (op);
+ g_return_val_if_fail (pgop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+ if (offset >= G_MAXINT)
+ return -1;
+ g_return_val_if_fail (blob, -1);
+
+ bin = (GdaBinary *) blob;
+ if (bin->data)
+ g_free (bin->data);
+ bin->data = g_new0 (gchar, size);
+ bin->binary_length = 0;
+
+ /* fetch blob data using C API into bin->data, and set bin->binary_length */
+ TO_IMPLEMENT;
+
+ return bin->binary_length;
+}
+
+/*
+ * Blob write request
+ */
+static glong
+gda_mysql_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlBlobOp *pgop;
+ GdaBinary *bin;
+
+ g_return_val_if_fail (GDA_IS_MYSQL_BLOB_OP (op), -1);
+ pgop = GDA_MYSQL_BLOB_OP (op);
+ g_return_val_if_fail (pgop->priv, -1);
+ g_return_val_if_fail (GDA_IS_CONNECTION (pgop->priv->cnc), -1);
+ g_return_val_if_fail (blob, -1);
+
+ /* write blob using bin->data and bin->binary_length */
+ bin = (GdaBinary *) blob;
+ TO_IMPLEMENT;
+
+ return -1;
+}
Added: trunk/providers/mysql/gda-mysql-blob-op.h
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-blob-op.h Sun Apr 6 17:06:43 2008
@@ -0,0 +1,57 @@
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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_MYSQL_BLOB_OP_H__
+#define __GDA_MYSQL_BLOB_OP_H__
+
+#include <libgda/gda-blob-op.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_MYSQL_BLOB_OP (gda_mysql_blob_op_get_type())
+#define GDA_MYSQL_BLOB_OP(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_MYSQL_BLOB_OP, GdaMysqlBlobOp))
+#define GDA_MYSQL_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_MYSQL_BLOB_OP, GdaMysqlBlobOpClass))
+#define GDA_IS_MYSQL_BLOB_OP(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_MYSQL_BLOB_OP))
+#define GDA_IS_MYSQL_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_MYSQL_BLOB_OP))
+
+typedef struct _GdaMysqlBlobOp GdaMysqlBlobOp;
+typedef struct _GdaMysqlBlobOpClass GdaMysqlBlobOpClass;
+typedef struct _GdaMysqlBlobOpPrivate GdaMysqlBlobOpPrivate;
+
+struct _GdaMysqlBlobOp {
+ GdaBlobOp parent;
+ GdaMysqlBlobOpPrivate *priv;
+};
+
+struct _GdaMysqlBlobOpClass {
+ GdaBlobOpClass parent_class;
+};
+
+GType gda_mysql_blob_op_get_type (void) G_GNUC_CONST;
+GdaBlobOp *gda_mysql_blob_op_new (GdaConnection *cnc);
+
+/* TO_ADD: more convenient API to create a GdaBlobOp with some specific information as argument */
+
+G_END_DECLS
+
+#endif
+
Added: trunk/providers/mysql/gda-mysql-meta.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-meta.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,494 @@
+/* GDA mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Carlos Savoretti <csavoretti gmail com>
+ *
+ * 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 "gda-mysql.h"
+#include "gda-mysql-meta.h"
+#include "gda-mysql-provider.h"
+#include <libgda/gda-meta-store.h>
+#include <libgda/sql-parser/gda-sql-parser.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-connection-private.h>
+#include <libgda/gda-data-model-array.h>
+#include <libgda/gda-set.h>
+#include <libgda/gda-holder.h>
+
+static gboolean append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...);
+
+/*
+ * predefined statements' IDs
+ */
+typedef enum {
+ I_STMT_CATALOG,
+ I_STMT_BTYPES,
+} InternalStatementItem;
+
+
+/*
+ * predefined statements' SQL
+ */
+static gchar *internal_sql[] = {
+ /* I_STMT_CATALOG */
+ "SELECT database()",
+
+ /* I_STMT_BTYPES */
+ "SELECT DISTINCT data_type, CONCAT(table_schema, '.', data_type), CASE data_type WHEN 'bigint' THEN 'gint' WHEN 'blob' THEN 'GdaBinary' WHEN 'date' THEN 'GDate' WHEN 'time' THEN 'GdaTime' WHEN 'double' THEN 'gdouble' WHEN 'timestamp' THEN 'GdaTimestamp' ELSE 'string' END , CONCAT('Desc:', data_type), NULL, 0 FROM information_schema.columns WHERE table_schema = SCHEMA() ORDER BY 1"
+};
+
+/*
+ * predefined statements' GdaStatement
+ */
+static GdaStatement **internal_stmt;
+static GdaSet *i_set;
+
+/*
+ * global static values
+ */
+static GdaSqlParser *internal_parser = NULL;
+/* TO_ADD: other static values */
+
+
+/*
+ * Meta initialization
+ */
+void
+_gda_mysql_provider_meta_init (GdaServerProvider *provider)
+{
+ InternalStatementItem i;
+
+ internal_parser = gda_server_provider_internal_get_parser (provider);
+
+ internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
+ for (i = I_STMT_CATALOG; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+ internal_stmt[i] = gda_sql_parser_parse_string (internal_parser, internal_sql[i], NULL, NULL);
+ if (!internal_stmt[i])
+ g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
+ }
+
+ /* initialize static values here */
+ i_set = gda_set_new_inline (3, "cat", G_TYPE_STRING, "",
+ "name", G_TYPE_STRING, "",
+ "schema", G_TYPE_STRING, "");
+}
+
+gboolean
+_gda_mysql_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ GdaDataModel *model;
+ gboolean retval;
+
+ model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_CATALOG], NULL, error);
+ if (!model)
+ return FALSE;
+
+ retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+ g_object_unref (model);
+
+ return retval;
+}
+
+gboolean
+_gda_mysql_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ GdaDataModel *model;
+ gboolean retval = TRUE;
+ GType col_types[] = {
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_NONE
+ };
+ model = gda_connection_statement_execute_select_full (cnc, internal_stmt[I_STMT_BTYPES], NULL,
+ GDA_STATEMENT_MODEL_RANDOM_ACCESS, col_types, error);
+ if (!model)
+ return FALSE;
+
+ if (retval)
+ retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+ g_object_unref (G_OBJECT(model));
+
+ return retval;
+}
+
+gboolean
+_gda_mysql_meta__udt (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_udt (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema)
+{
+ GdaDataModel *model;
+ gboolean retval = TRUE;
+
+ /* set internal holder's values from the arguments */
+ gda_holder_set_value (gda_set_get_holder (i_set, "cat"), udt_catalog);
+ gda_holder_set_value (gda_set_get_holder (i_set, "schema"), udt_schema);
+
+ TO_IMPLEMENT;
+ /* fill in @model, with something like:
+ * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error);
+ */
+ if (!model)
+ return FALSE;
+ retval = gda_meta_store_modify_with_context (store, context, model, error);
+ g_object_unref (model);
+
+ return retval;
+}
+
+
+gboolean
+_gda_mysql_meta__udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__enums (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_enums (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+
+gboolean
+_gda_mysql_meta__domains (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_domains (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_constraints_dom (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema,
+ const GValue *domain_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__el_types (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__collations (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_collations (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *collation_catalog, const GValue *collation_schema,
+ const GValue *collation_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__character_sets (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_character_sets (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *chset_catalog, const GValue *chset_schema,
+ const GValue *chset_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *catalog_name, const GValue *schema_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__view_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_view_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *view_catalog, const GValue *view_schema,
+ const GValue *view_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__check_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_check_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__triggers (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_triggers (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__routines (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_routines (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *routine_catalog, const GValue *routine_schema,
+ const GValue *routine_name_n)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_routine_col (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema,
+ const GValue *rout_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta__routine_par (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
+
+gboolean
+_gda_mysql_meta_routine_par (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema,
+ const GValue *rout_name)
+{
+ TO_IMPLEMENT;
+ return TRUE;
+}
Added: trunk/providers/mysql/gda-mysql-meta.h
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-meta.h Sun Apr 6 17:06:43 2008
@@ -0,0 +1,194 @@
+/* GDA mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_MYSQL_META_H__
+#define __GDA_MYSQL_META_H__
+
+#include <libgda/gda-server-provider.h>
+
+G_BEGIN_DECLS
+
+void _gda_mysql_provider_meta_init (GdaServerProvider *provider);
+
+/* _information_schema_catalog_name */
+gboolean _gda_mysql_meta__info (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+
+/* _builtin_data_types */
+gboolean _gda_mysql_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+
+/* _udt */
+gboolean _gda_mysql_meta__udt (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_udt (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema);
+
+/* _udt_columns */
+gboolean _gda_mysql_meta__udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+
+/* _enums */
+gboolean _gda_mysql_meta__enums (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_enums (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+
+/* _domains */
+gboolean _gda_mysql_meta__domains (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_domains (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema);
+
+/* _domain_constraints */
+gboolean _gda_mysql_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_constraints_dom (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *domain_catalog, const GValue *domain_schema,
+ const GValue *domain_name);
+
+/* _element_types */
+gboolean _gda_mysql_meta__el_types (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+
+/* _collations */
+gboolean _gda_mysql_meta__collations (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_collations (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *collation_catalog, const GValue *collation_schema,
+ const GValue *collation_name_n);
+
+/* _character_sets */
+gboolean _gda_mysql_meta__character_sets (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_character_sets (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *chset_catalog, const GValue *chset_schema,
+ const GValue *chset_name_n);
+
+/* _schemata */
+gboolean _gda_mysql_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *catalog_name, const GValue *schema_name_n);
+
+/* _tables or _views */
+gboolean _gda_mysql_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name_n);
+
+/* _columns */
+gboolean _gda_mysql_meta__columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name);
+
+/* _view_column_usage */
+gboolean _gda_mysql_meta__view_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_view_cols (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *view_catalog, const GValue *view_schema,
+ const GValue *view_name);
+
+/* _table_constraints */
+gboolean _gda_mysql_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name_n);
+
+/* _referential_constraints */
+gboolean _gda_mysql_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema, const GValue *table_name,
+ const GValue *constraint_name);
+
+/* _key_column_usage */
+gboolean _gda_mysql_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name);
+
+/* _check_column_usage */
+gboolean _gda_mysql_meta__check_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_check_columns (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name, const GValue *constraint_name);
+
+/* _triggers */
+gboolean _gda_mysql_meta__triggers (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_triggers (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *table_catalog, const GValue *table_schema,
+ const GValue *table_name);
+
+/* _routines */
+gboolean _gda_mysql_meta__routines (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_routines (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *routine_catalog, const GValue *routine_schema,
+ const GValue *routine_name_n);
+
+/* _routine_columns */
+gboolean _gda_mysql_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_routine_col (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema,
+ const GValue *rout_name);
+
+/* _parameters */
+gboolean _gda_mysql_meta__routine_par (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_mysql_meta_routine_par (GdaServerProvider *prov, GdaConnection *cnc,
+ GdaMetaStore *store, GdaMetaContext *context, GError **error,
+ const GValue *rout_catalog, const GValue *rout_schema,
+ const GValue *rout_name);
+
+
+G_END_DECLS
+
+#endif
+
Added: trunk/providers/mysql/gda-mysql-parser.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-parser.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,82 @@
+/* GDA Mysql provider
+ *
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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 "gda-mysql-parser.h"
+#include "mysql_token_types.h"
+#include <string.h>
+
+/*
+ * Main static functions
+ */
+static void gda_mysql_parser_class_init (GdaMysqlParserClass *klass);
+static void gda_mysql_parser_init (GdaMysqlParser *stmt);
+
+GType
+gda_mysql_parser_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdaMysqlParserClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_mysql_parser_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaMysqlParser),
+ 0,
+ (GInstanceInitFunc) gda_mysql_parser_init
+ };
+
+ type = g_type_register_static (GDA_TYPE_SQL_PARSER, "GdaMysqlParser", &info, 0);
+ }
+ return type;
+}
+
+/*
+ * The interface to the LEMON-generated parser
+ */
+void *gda_lemon_mysql_parserAlloc (void*(*)(size_t));
+void gda_lemon_mysql_parserFree (void*, void(*)(void*));
+void gda_lemon_mysql_parserTrace (void*, char *);
+void gda_lemon_mysql_parser (void*, int, GValue *, GdaSqlParserIface *);
+
+static void
+gda_mysql_parser_class_init (GdaMysqlParserClass * klass)
+{
+ g_print ("*** %s\n", __func__);
+ GdaSqlParserClass *pclass = GDA_SQL_PARSER_CLASS (klass);
+
+ pclass->parser_alloc = gda_lemon_mysql_parserAlloc;
+ pclass->parser_free = gda_lemon_mysql_parserFree;
+ pclass->parser_trace = gda_lemon_mysql_parserTrace;
+ pclass->parser_parse = gda_lemon_mysql_parser;
+ pclass->parser_tokens_trans = mysql_parser_tokens;
+}
+
+static void
+gda_mysql_parser_init (GdaMysqlParser *parser)
+{
+ g_print ("*** %s\n", __func__);
+}
Added: trunk/providers/mysql/gda-mysql-parser.h
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-parser.h Sun Apr 6 17:06:43 2008
@@ -0,0 +1,59 @@
+/* GDA Mysql provider
+ *
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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_MYSQL_PARSER_H_
+#define __GDA_MYSQL_PARSER_H_
+
+#include <sql-parser/gda-sql-parser.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_MYSQL_PARSER (gda_mysql_parser_get_type())
+#define GDA_MYSQL_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_MYSQL_PARSER, GdaMysqlParser))
+#define GDA_MYSQL_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_MYSQL_PARSER, GdaMysqlParserClass))
+#define GDA_IS_MYSQL_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_MYSQL_PARSER))
+#define GDA_IS_MYSQL_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_MYSQL_PARSER))
+
+typedef struct _GdaMysqlParser GdaMysqlParser;
+typedef struct _GdaMysqlParserClass GdaMysqlParserClass;
+typedef struct _GdaMysqlParserPrivate GdaMysqlParserPrivate;
+
+/* struct for the object's data */
+struct _GdaMysqlParser
+{
+ GdaSqlParser object;
+ GdaMysqlParserPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _GdaMysqlParserClass
+{
+ GdaSqlParserClass parent_class;
+};
+
+GType gda_mysql_parser_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
Modified: trunk/providers/mysql/gda-mysql-provider.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-provider.c (original)
+++ trunk/providers/mysql/gda-mysql-provider.c Sun Apr 6 17:06:43 2008
@@ -1,12 +1,8 @@
-
-/* GDA MySQL provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation.
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
- * Bas Driessen <bas driessen xobas com>
+ * Carlos Savoretti <csavoretti gmail com>
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -24,183 +20,274 @@
* Boston, MA 02111-1307, USA.
*/
-#include <libgda/gda-data-model-array.h>
-#include <libgda/gda-data-model-private.h>
-#include <libgda/gda-column-index.h>
-#include <libgda/gda-util.h>
-#include <libgda/gda-data-handler.h>
-#include <libgda/gda-parameter-list.h>
-#include <libgda/gda-server-provider-extra.h>
-#include <glib/gi18n-lib.h>
+#include <stdio.h>
#include <stdlib.h>
+#include <errno.h>
#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <libgda/libgda.h>
+#include <libgda/gda-data-model-private.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include <libgda/gda-statement-extra.h>
+#include <sql-parser/gda-sql-parser.h>
#include "gda-mysql.h"
+#include "gda-mysql-provider.h"
#include "gda-mysql-recordset.h"
#include "gda-mysql-ddl.h"
+#include "gda-mysql-meta.h"
-#include <libgda/handlers/gda-handler-numerical.h>
-#include <libgda/handlers/gda-handler-bin.h>
-#include <libgda/handlers/gda-handler-boolean.h>
-#include <libgda/handlers/gda-handler-time.h>
-#include <libgda/handlers/gda-handler-string.h>
-#include <libgda/handlers/gda-handler-type.h>
-
-#include <libgda/sql-parser/gda-sql-parser.h>
-#include <libgda/sql-delimiter/gda-sql-delimiter.h>
-#include <libgda/gda-connection-private.h>
-#include <libgda/binreloc/gda-binreloc.h>
+#include "gda-mysql-util.h"
+#include "gda-mysql-parser.h"
-#define PARENT_TYPE GDA_TYPE_SERVER_PROVIDER
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
-static void gda_mysql_provider_class_init (GdaMysqlProviderClass *klass);
-static void gda_mysql_provider_init (GdaMysqlProvider *provider,
- GdaMysqlProviderClass *klass);
-static void gda_mysql_provider_finalize (GObject *object);
-
-static const gchar *gda_mysql_provider_get_version (GdaServerProvider *provider);
-
-static gboolean gda_mysql_provider_open_connection (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaQuarkList *params,
- const gchar *username,
- const gchar *password);
-
-static gboolean gda_mysql_provider_close_connection (GdaServerProvider *provider,
- GdaConnection *cnc);
-
-static const gchar *gda_mysql_provider_get_server_version (GdaServerProvider *provider,
- GdaConnection *cnc);
-
-static const gchar *gda_mysql_provider_get_database (GdaServerProvider *provider,
- GdaConnection *cnc);
-
-static gboolean gda_mysql_provider_change_database (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name);
-
-static gboolean gda_mysql_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type, GdaParameterList *options);
-static GdaServerOperation *gda_mysql_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type,
- GdaParameterList *options, GError **error);
-static gchar *gda_mysql_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, GError **error);
-
-static gboolean gda_mysql_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, GError **error);
-
-static GList *gda_mysql_provider_execute_command (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaCommand *cmd,
- GdaParameterList *params);
-
-static gchar *gda_mysql_provider_get_last_insert_id (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaDataModel *recset);
-
-static gboolean gda_mysql_provider_begin_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GdaTransactionIsolation level,
- GError **error);
-
-static gboolean gda_mysql_provider_commit_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GError **error);
-
-static gboolean gda_mysql_provider_rollback_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GError **error);
-
-static gboolean gda_mysql_provider_supports (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaConnectionFeature feature);
-
-static GdaServerProviderInfo *gda_mysql_provider_get_info (GdaServerProvider *provider,
- GdaConnection *cnc);
-
-static GdaDataModel *gda_mysql_provider_get_schema (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaConnectionSchema schema,
- GdaParameterList *params);
-static GdaDataHandler *gda_mysql_provider_get_data_handler (GdaServerProvider *provider,
- GdaConnection *cnc,
- GType g_type,
- const gchar *dbms_type);
-static const gchar* gda_mysql_provider_get_default_dbms_type (GdaServerProvider *provider,
- GdaConnection *cnc,
- GType type);
+/*
+ * GObject methods
+ */
+static void gda_mysql_provider_class_init (GdaMysqlProviderClass *klass);
+static void gda_mysql_provider_init (GdaMysqlProvider *provider,
+ GdaMysqlProviderClass *klass);
+static GObjectClass *parent_class = NULL;
-static GdaSqlParser *gda_mysql_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc);
+/*
+ * GdaServerProvider's virtual methods
+ */
+/* connection management */
+static gboolean gda_mysql_provider_open_connection (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaQuarkList *params,
+ GdaQuarkList *auth,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data);
+static gboolean gda_mysql_provider_close_connection (GdaServerProvider *provider,
+ GdaConnection *cnc);
+static const gchar *gda_mysql_provider_get_server_version (GdaServerProvider *provider,
+ GdaConnection *cnc);
+static const gchar *gda_mysql_provider_get_database (GdaServerProvider *provider,
+ GdaConnection *cnc);
+
+/* DDL operations */
+static gboolean gda_mysql_provider_supports_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperationType type,
+ GdaSet *options);
+static GdaServerOperation *gda_mysql_provider_create_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperationType type,
+ GdaSet *options,
+ GError **error);
+static gchar *gda_mysql_provider_render_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperation *op,
+ GError **error);
+
+static gboolean gda_mysql_provider_perform_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperation *op,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data,
+ GError **error);
+/* transactions */
+static gboolean gda_mysql_provider_begin_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GdaTransactionIsolation level,
+ GError **error);
+static gboolean gda_mysql_provider_commit_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name, GError **error);
+static gboolean gda_mysql_provider_rollback_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error);
+static gboolean gda_mysql_provider_add_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error);
+static gboolean gda_mysql_provider_rollback_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error);
+static gboolean gda_mysql_provider_delete_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error);
+
+/* information retrieval */
+static const gchar *gda_mysql_provider_get_version (GdaServerProvider *provider);
+static gboolean gda_mysql_provider_supports_feature (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaConnectionFeature feature);
+
+static const gchar *gda_mysql_provider_get_name (GdaServerProvider *provider);
+
+static GdaDataHandler *gda_mysql_provider_get_data_handler (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GType g_type,
+ const gchar *dbms_type);
+
+static const gchar* gda_mysql_provider_get_default_dbms_type (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GType type);
+/* statements */
+static GdaSqlParser *gda_mysql_provider_create_parser (GdaServerProvider *provider,
+ GdaConnection *cnc);
+static gchar *gda_mysql_provider_statement_to_sql (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GdaStatementSqlFlag flags,
+ GSList **params_used,
+ GError **error);
+static gboolean gda_mysql_provider_statement_prepare (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GError **error);
+static GObject *gda_mysql_provider_statement_execute (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types,
+ GdaSet **last_inserted_row,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data,
+ GError **error);
+/*
+ * private connection data destroy
+ */
+static void gda_mysql_free_cnc_data (MysqlConnectionData *cdata);
-static GObjectClass *parent_class = NULL;
/*
- * GdaMysqlProvider class implementation
+ * Prepared internal statements
+ * TO_ADD: any prepared statement to be used internally by the provider should be
+ * declared here, as constants and as SQL statements
*/
+GdaStatement **internal_stmt;
+
+typedef enum {
+ INTERNAL_STMT1
+} InternalStatementItem;
+
+gchar *internal_sql[] = {
+ "SQL for INTERNAL_STMT1"
+};
+/*
+ * GdaMysqlProvider class implementation
+ */
static void
-gda_mysql_provider_class_init (GdaMysqlProviderClass *klass)
+gda_mysql_provider_class_init (GdaMysqlProviderClass *klass)
{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ g_print ("*** %s\n", __func__);
GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
- object_class->finalize = gda_mysql_provider_finalize;
-
provider_class->get_version = gda_mysql_provider_get_version;
provider_class->get_server_version = gda_mysql_provider_get_server_version;
- provider_class->get_info = gda_mysql_provider_get_info;
- provider_class->supports_feature = gda_mysql_provider_supports;
- provider_class->get_schema = gda_mysql_provider_get_schema;
+ provider_class->get_name = gda_mysql_provider_get_name;
+ provider_class->supports_feature = gda_mysql_provider_supports_feature;
provider_class->get_data_handler = gda_mysql_provider_get_data_handler;
- provider_class->string_to_value = NULL;
provider_class->get_def_dbms_type = gda_mysql_provider_get_default_dbms_type;
- provider_class->create_connection = NULL;
provider_class->open_connection = gda_mysql_provider_open_connection;
provider_class->close_connection = gda_mysql_provider_close_connection;
provider_class->get_database = gda_mysql_provider_get_database;
- provider_class->change_database = gda_mysql_provider_change_database;
provider_class->supports_operation = gda_mysql_provider_supports_operation;
- provider_class->create_operation = gda_mysql_provider_create_operation;
- provider_class->render_operation = gda_mysql_provider_render_operation;
- provider_class->perform_operation = gda_mysql_provider_perform_operation;
-
- provider_class->execute_command = gda_mysql_provider_execute_command;
- provider_class->execute_query = NULL;
- provider_class->get_last_insert_id = gda_mysql_provider_get_last_insert_id;
+ provider_class->create_operation = gda_mysql_provider_create_operation;
+ provider_class->render_operation = gda_mysql_provider_render_operation;
+ provider_class->perform_operation = gda_mysql_provider_perform_operation;
provider_class->begin_transaction = gda_mysql_provider_begin_transaction;
provider_class->commit_transaction = gda_mysql_provider_commit_transaction;
provider_class->rollback_transaction = gda_mysql_provider_rollback_transaction;
- provider_class->add_savepoint = NULL;
- provider_class->rollback_savepoint = NULL;
- provider_class->delete_savepoint = NULL;
+ provider_class->add_savepoint = gda_mysql_provider_add_savepoint;
+ provider_class->rollback_savepoint = gda_mysql_provider_rollback_savepoint;
+ provider_class->delete_savepoint = gda_mysql_provider_delete_savepoint;
provider_class->create_parser = gda_mysql_provider_create_parser;
- provider_class->statement_to_sql = NULL;
- provider_class->statement_prepare = NULL;
- provider_class->statement_execute = NULL;
-}
+ provider_class->statement_to_sql = gda_mysql_provider_statement_to_sql;
+ provider_class->statement_prepare = gda_mysql_provider_statement_prepare;
+ provider_class->statement_execute = gda_mysql_provider_statement_execute;
-static void
-gda_mysql_provider_init (GdaMysqlProvider *myprv, GdaMysqlProviderClass *klass)
-{
+ provider_class->is_busy = NULL;
+ provider_class->cancel = NULL;
+ provider_class->create_connection = NULL;
+
+ memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
+ provider_class->meta_funcs._info = _gda_mysql_meta__info;
+ provider_class->meta_funcs._btypes = _gda_mysql_meta__btypes;
+ provider_class->meta_funcs._udt = _gda_mysql_meta__udt;
+ provider_class->meta_funcs.udt = _gda_mysql_meta_udt;
+ provider_class->meta_funcs._udt_cols = _gda_mysql_meta__udt_cols;
+ provider_class->meta_funcs.udt_cols = _gda_mysql_meta_udt_cols;
+ provider_class->meta_funcs._enums = _gda_mysql_meta__enums;
+ provider_class->meta_funcs.enums = _gda_mysql_meta_enums;
+ provider_class->meta_funcs._domains = _gda_mysql_meta__domains;
+ provider_class->meta_funcs.domains = _gda_mysql_meta_domains;
+ provider_class->meta_funcs._constraints_dom = _gda_mysql_meta__constraints_dom;
+ provider_class->meta_funcs.constraints_dom = _gda_mysql_meta_constraints_dom;
+ provider_class->meta_funcs._el_types = _gda_mysql_meta__el_types;
+ provider_class->meta_funcs._collations = _gda_mysql_meta__collations;
+ provider_class->meta_funcs.collations = _gda_mysql_meta_collations;
+ provider_class->meta_funcs._character_sets = _gda_mysql_meta__character_sets;
+ provider_class->meta_funcs.character_sets = _gda_mysql_meta_character_sets;
+ provider_class->meta_funcs._schemata = _gda_mysql_meta__schemata;
+ provider_class->meta_funcs.schemata = _gda_mysql_meta_schemata;
+ provider_class->meta_funcs._tables_views = _gda_mysql_meta__tables_views;
+ provider_class->meta_funcs.tables_views = _gda_mysql_meta_tables_views;
+ provider_class->meta_funcs._columns = _gda_mysql_meta__columns;
+ provider_class->meta_funcs.columns = _gda_mysql_meta_columns;
+ provider_class->meta_funcs._view_cols = _gda_mysql_meta__view_cols;
+ provider_class->meta_funcs.view_cols = _gda_mysql_meta_view_cols;
+ provider_class->meta_funcs._constraints_tab = _gda_mysql_meta__constraints_tab;
+ provider_class->meta_funcs.constraints_tab = _gda_mysql_meta_constraints_tab;
+ provider_class->meta_funcs._constraints_ref = _gda_mysql_meta__constraints_ref;
+ provider_class->meta_funcs.constraints_ref = _gda_mysql_meta_constraints_ref;
+ provider_class->meta_funcs._key_columns = _gda_mysql_meta__key_columns;
+ provider_class->meta_funcs.key_columns = _gda_mysql_meta_key_columns;
+ provider_class->meta_funcs._check_columns = _gda_mysql_meta__check_columns;
+ provider_class->meta_funcs.check_columns = _gda_mysql_meta_check_columns;
+ provider_class->meta_funcs._triggers = _gda_mysql_meta__triggers;
+ provider_class->meta_funcs.triggers = _gda_mysql_meta_triggers;
+ provider_class->meta_funcs._routines = _gda_mysql_meta__routines;
+ provider_class->meta_funcs.routines = _gda_mysql_meta_routines;
+ provider_class->meta_funcs._routine_col = _gda_mysql_meta__routine_col;
+ provider_class->meta_funcs.routine_col = _gda_mysql_meta_routine_col;
+ provider_class->meta_funcs._routine_par = _gda_mysql_meta__routine_par;
+ provider_class->meta_funcs.routine_par = _gda_mysql_meta_routine_par;
}
static void
-gda_mysql_provider_finalize (GObject *object)
+gda_mysql_provider_init (GdaMysqlProvider *mysql_prv,
+ GdaMysqlProviderClass *klass)
{
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) object;
+ g_print ("*** %s\n", __func__);
+ InternalStatementItem i;
+ GdaSqlParser *parser;
- g_return_if_fail (GDA_IS_MYSQL_PROVIDER (myprv));
+ parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) mysql_prv);
+ internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
+ for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+ internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
+ if (!internal_stmt[i])
+ g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
+ }
+
+ /* meta data init */
+ _gda_mysql_provider_meta_init ((GdaServerProvider*) mysql_prv);
- /* chain to parent class */
- parent_class->finalize (object);
+ /* TO_ADD: any other provider's init should be added here */
}
GType
@@ -219,55 +306,60 @@
0,
(GInstanceInitFunc) gda_mysql_provider_init
};
- type = g_type_register_static (PARENT_TYPE, "GdaMysqlProvider", &info, 0);
+ type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaMysqlProvider",
+ &info, 0);
}
return type;
}
-GdaServerProvider *
-gda_mysql_provider_new (void)
-{
- GdaMysqlProvider *provider;
- provider = g_object_new (gda_mysql_provider_get_type (), NULL);
- return GDA_SERVER_PROVIDER (provider);
+/*
+ * Get provider name request
+ */
+static const gchar *
+gda_mysql_provider_get_name (GdaServerProvider *provider)
+{
+ g_print ("*** %s\n", __func__);
+ return MYSQL_PROVIDER_NAME;
}
-/* get_version handler for the GdaMysqlProvider class */
+/*
+ * Get provider's version, no need to change this
+ */
static const gchar *
-gda_mysql_provider_get_version (GdaServerProvider *provider)
+gda_mysql_provider_get_version (GdaServerProvider *provider)
{
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
-
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), NULL);
-
- return GDA_PACKAGE_VERSION;
+ g_print ("*** %s\n", __func__);
+ return PACKAGE_VERSION;
}
-/* generic function to open a MYSQL connection */
+
+/*
+ * Open a MYSQL connection.
+ */
static MYSQL *
-real_open_connection (const gchar *host, gint port, const gchar *socket,
- const gchar *db,
- const gchar *login, const gchar *password,
- gboolean usessl, GError **error)
-{
- MYSQL *mysql;
- MYSQL *mysql_ret;
- unsigned int mysqlflags = 0;
-#if MYSQL_VERSION_ID < 32200
- gint err;
-#endif
-
- /* we can't have both a host/pair AND a unix_socket */
- if ((host || (port >= 0)) && socket) {
- g_set_error (error, 0, 0,
- _("You cannot provide a UNIX SOCKET if you also provide"
- " either a HOST or a PORT."));
- return NULL;
- }
+real_open_connection (const gchar *host,
+ gint port,
+ const gchar *socket,
+ const gchar *db,
+ const gchar *username,
+ const gchar *password,
+ gboolean use_ssl,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ unsigned int flags = 0;
+
+ /* Exclusive: host/pair otherwise unix socket. */
+ if ((host || port >= 0) && socket) {
+ g_set_error (error, 0, 0,
+ _("Cannot give a UNIX SOCKET if you also provide "
+ "either a HOST or a PORT"));
+ return NULL;
+ }
- /* provide the default of localhost:3306 if neither is provided */
+ /* Defaults. */
if (!socket) {
if (!host)
host = "localhost";
@@ -275,2187 +367,1091 @@
port = 3306;
}
- if (usessl)
- mysqlflags |= CLIENT_SSL;
+ if (use_ssl)
+ flags |= CLIENT_SSL;
+
+ MYSQL *mysql = g_new0 (MYSQL, 1);
+ mysql_init (mysql);
- mysql = g_new0 (MYSQL, 1);
- mysql_init (mysql);
- mysql_ret = mysql_real_connect (mysql, host, login, password,
+ MYSQL *return_mysql = mysql_real_connect (mysql, host,
+ username, password,
#if MYSQL_VERSION_ID >= 32200
- db,
+ db,
#endif
- port > 0? port : 0,
- socket,
- mysqlflags);
-
-
- if (!mysql_ret) {
+ (port > 0) ? port : 0,
+ socket, flags);
+ if (!return_mysql || mysql != return_mysql) {
g_set_error (error, 0, 0, mysql_error (mysql));
g_free (mysql);
- return NULL;
+ mysql = NULL;
}
-
+
+ /* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
+
#if MYSQL_VERSION_ID < 32200
- err = mysql_select_db (mysql, db);
- if (err != 0) {
+ if (mysql &&
+ mysql_select_db (mysql, db) != 0) {
g_set_error (error, 0, 0, mysql_error (mysql));
- mysql_close (mysql);
-
- return NULL;
+ g_free (mysql);
+ mysql = NULL;
}
#endif
#if MYSQL_VERSION_ID >= 50007
- if (mysql_set_character_set (mysql, "utf8"))
- g_warning ("Could not set client character set to UTF8 (using %s), expect problems with non UTF-8 characters\n",
+ if (mysql &&
+ mysql_set_character_set (mysql, "utf8")) {
+ g_warning (_("Could not set client charset to UTF8. "
+ "Using %s. It'll be problems with non UTF-8 characters"),
mysql_character_set_name (mysql));
+ }
#endif
-
+
return mysql;
}
-/* open_connection handler for the GdaMysqlProvider class */
-static gboolean
-gda_mysql_provider_open_connection (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaQuarkList *params,
- const gchar *username,
- const gchar *password)
-{
- const gchar *t_host = NULL;
- const gchar *t_db = NULL;
- const gchar *t_user = NULL;
- const gchar *t_password = NULL;
- const gchar *t_port = NULL;
- const gchar *t_unix_socket = NULL;
- const gchar *t_use_ssl = NULL;
-
- MYSQL *mysql;
- GdaConnectionEvent *error;
- GError *gerror = NULL;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
+static gchar *
+get_mysql_version (MYSQL *mysql)
+{
+ g_print ("*** %s\n", __func__);
+ g_return_val_if_fail (mysql != NULL, NULL);
+ unsigned long version_long;
+ version_long = mysql_get_server_version (mysql);
+ return g_strdup_printf ("%lu.%lu.%lu",
+ version_long/10000,
+ (version_long%10000)/100,
+ (version_long%100));
+}
+
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
+/*
+ * Open connection request
+ *
+ * In this function, the following _must_ be done:
+ * - check for the presence and validify of the parameters required to actually open a connection,
+ * using @params
+ * - open the real connection to the database using the parameters previously checked
+ * - create a MysqlConnectionData structure and associate it to @cnc
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ */
+static gboolean
+gda_mysql_provider_open_connection (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaQuarkList *params,
+ GdaQuarkList *auth,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data)
+{
+ g_print ("*** %s\n", __func__);
+ g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (provider), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- /* get all parameters received */
- t_host = gda_quark_list_find (params, "HOST");
- t_db = gda_quark_list_find (params, "DB_NAME");
- if (!t_db) {
- const gchar *str;
-
- str = gda_quark_list_find (params, "DATABASE");
- if (!str) {
- gda_connection_add_event_string (cnc,
- _("The connection string must contain a DB_NAME value"));
- return FALSE;
- }
- else {
- g_warning (_("The connection string format has changed: replace DATABASE with "
- "DB_NAME and the same contents"));
- t_db = str;
- }
+ /* If asynchronous connection opening is not supported, then exit now */
+ if (async_cb) {
+ gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
+ return FALSE;
}
- t_user = gda_quark_list_find (params, "USER");
- t_password = gda_quark_list_find (params, "PASSWORD");
- t_port = gda_quark_list_find (params, "PORT");
- t_unix_socket = gda_quark_list_find (params, "UNIX_SOCKET");
- t_use_ssl = gda_quark_list_find (params, "USE_SSL");
-
- if (username && *username != '\0')
- t_user = username;
- if (password && *password != '\0')
- t_password = password;
+ /* Check for connection parameters */
+ /* TO_ADD: your own connection parameters */
+ const gchar *db_name;
+ db_name = gda_quark_list_find (params, "DB_NAME");
+ if (!db_name) {
+ gda_connection_add_event_string (cnc,
+ _("The connection string must contain the DB_NAME values"));
+ return FALSE;
+ }
+
+ const gchar *host;
+ host = gda_quark_list_find (params, "HOST");
- mysql = real_open_connection (t_host, t_port ? atoi (t_port) : 0, t_unix_socket,
- t_db, t_user, t_password, t_use_ssl ? TRUE : FALSE, &gerror);
+ const gchar *user, *password;
+ user = gda_quark_list_find (params, "USER");
+ password = gda_quark_list_find (params, "PASSWORD");
+
+ const gchar *port, *unix_socket, *use_ssl;
+ port = gda_quark_list_find (params, "PORT");
+ unix_socket = gda_quark_list_find (params, "UNIX_SOCKET");
+ use_ssl = gda_quark_list_find (params, "USE_SSL");
+
+
+ /* open the real connection to the database */
+ /* TO_ADD: C API specific function calls;
+ * if it fails, add a connection event and return FALSE */
+ // TO_IMPLEMENT;
+
+ GError *error = NULL;
+ MYSQL *mysql = real_open_connection (host, (port != NULL) ? atoi (port) : 0,
+ unix_socket, db_name,
+ user, password,
+ (use_ssl != NULL) ? TRUE : FALSE,
+ &error);
if (!mysql) {
- error = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
- gda_connection_event_set_description (error, gerror && gerror->message ?
- gerror->message : "NO DESCRIPTION");
- gda_connection_event_set_code (error, gerror ? gerror->code : -1);
- if (gerror)
- g_error_free (gerror);
- gda_connection_add_event (cnc, error);
+ _gda_mysql_make_error (cnc, mysql, NULL);
+ return FALSE;
+ }
+
+ MYSQL_STMT *mysql_stmt = mysql_stmt_init (mysql);
+ if (!mysql_stmt) {
+ _gda_mysql_make_error (cnc, mysql, NULL);
+ return FALSE;
+ }
+ my_bool update_max_length = 1;
+ if (mysql_stmt_attr_set (mysql_stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (const void *) &update_max_length)) {
+ _gda_mysql_make_error (cnc, mysql, NULL);
return FALSE;
}
- g_object_set_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE, mysql);
+
+
+ /* Create a new instance of the provider specific data associated to a connection (MysqlConnectionData),
+ * and set its contents */
+ MysqlConnectionData *cdata;
+ cdata = g_new0 (MysqlConnectionData, 1);
+ gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_mysql_free_cnc_data);
+ // TO_IMPLEMENT; /* cdata->... = ... */
+
+ cdata->cnc = cnc;
+ cdata->mysql = mysql;
+ cdata->mysql_stmt = mysql_stmt;
+
+ cdata->version_long = mysql_get_server_version (mysql);
+ cdata->version = get_mysql_version (mysql);
+
+
+ /* Optionnally set some attributes for the newly opened connection (encoding to UTF-8 for example )*/
+ // TO_IMPLEMENT;
return TRUE;
}
-/* close_connection handler for the GdaMysqlProvider class */
+/*
+ * Close connection request
+ *
+ * In this function, the following _must_ be done:
+ * - Actually close the connection to the database using @cnc's associated MysqlConnectionData structure
+ * - Free the MysqlConnectionData structure and its contents
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ */
static gboolean
-gda_mysql_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
+gda_mysql_provider_close_connection (GdaServerProvider *provider,
+ GdaConnection *cnc)
{
- MYSQL *mysql;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql)
+ /* Close the connection using the C API */
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return FALSE;
+ // TO_IMPLEMENT;
- mysql_close (mysql);
- g_object_set_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE, NULL);
+ /* Free the MysqlConnectionData structure and its contents*/
+ gda_mysql_free_cnc_data (cdata);
+ gda_connection_internal_set_provider_data (cnc, NULL, NULL);
return TRUE;
}
-/* get_server_version handler for the GdaMysqlProvider class */
+/*
+ * Server version request
+ *
+ * Returns the server version as a string, which should be stored in @cnc's associated MysqlConnectionData structure
+ */
static const gchar *
-gda_mysql_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
+gda_mysql_provider_get_server_version (GdaServerProvider *provider,
+ GdaConnection *cnc)
{
- MYSQL *mysql;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), NULL);
- if (cnc)
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- else
- return NULL;
-
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- return (const gchar *) mysql->server_version;
-}
-
-static GList *
-process_sql_commands (GList *reclist, GdaConnection *cnc, const gchar *sql)
-{
- MYSQL *mysql;
- gchar **arr;
- GdaConnectionOptions options;
-
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return NULL;
- }
-
- options = gda_connection_get_options (cnc);
-
- /* parse SQL string, which can contain several commands, separated by ';' */
- arr = gda_delimiter_split_sql (sql);
- if (arr) {
- gint n = 0;
- gboolean allok = TRUE;
-
- while (arr[n] && allok) {
- gint rc;
- MYSQL_RES *mysql_res;
- GdaMysqlRecordset *recset;
- gchar *tststr;
- GdaConnectionEvent *error = NULL;
-
- /* if the connection is in read-only mode, just allow SELECT,
- SHOW commands */
- if (options & GDA_CONNECTION_OPTIONS_READ_ONLY) {
- gchar *s;
-
- /* FIXME: maybe there's a better way of doing this? */
- s = g_strstrip (g_strdup (arr[n]));
- if (g_ascii_strncasecmp (s, "select", strlen ("select")) &&
- g_ascii_strncasecmp (s, "show", strlen ("show"))) {
- gda_connection_add_event_string (
- cnc, "Command '%s' cannot be executed in read-only mode", arr[n]);
- reclist = g_list_append (reclist, NULL);
- allok = FALSE;
- break;
- }
-
- g_free (s);
- }
-
- /* execute the command on the server */
- rc = gda_mysql_real_query_wrap (cnc, mysql, arr[n], strlen (arr[n]));
- if (rc != 0) {
- error = gda_mysql_make_error (mysql);
- gda_connection_add_event (cnc, error);
- reclist = g_list_append (reclist, NULL);
- allok = FALSE;
- }
- else {
- /* command was executed OK */
- g_strchug (arr[n]);
- tststr = arr[n];
- if (! g_ascii_strncasecmp (tststr, "SELECT", 6) ||
- ! g_ascii_strncasecmp (tststr, "SHOW", 4) ||
- ! g_ascii_strncasecmp (tststr, "DESCRIBE", 6) ||
- ! g_ascii_strncasecmp (tststr, "EXPLAIN", 7)) {
- mysql_res = mysql_store_result (mysql);
- recset = gda_mysql_recordset_new (cnc, mysql_res, mysql);
- if (GDA_IS_MYSQL_RECORDSET (recset)) {
- g_object_set (G_OBJECT (recset),
- "command_text", arr[n],
- "command_type", GDA_COMMAND_TYPE_SQL, NULL);
- reclist = g_list_append (reclist, recset);
- }
- else
- reclist = g_list_append (reclist, NULL);
- }
- else {
- int changes;
- GdaConnectionEvent *event;
- gchar *str, *tmp, *ptr;
-
- changes = mysql_affected_rows (mysql);
- reclist = g_list_append (reclist,
- gda_parameter_list_new_inline (NULL,
- "IMPACTED_ROWS", G_TYPE_INT, changes,
- NULL));
-
- /* generate a notice about changes */
- event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
- ptr = tststr;
- while (*ptr && (*ptr != ' ') && (*ptr != '\t') &&
- (*ptr != '\n'))
- ptr++;
- *ptr = 0;
- tmp = g_ascii_strup (tststr, -1);
- if (!strcmp (tmp, "INSERT")) {
- if (mysql_insert_id (mysql) != 0)
- str = g_strdup_printf ("%s %lld %d", tmp,
- mysql_insert_id (mysql),
- changes);
- else
- str = g_strdup_printf ("%s NOID %d", tmp, changes);
- }
- else
- str = g_strdup_printf ("%s %d", tmp, changes);
- gda_connection_event_set_description (event, str);
- g_free (str);
- g_free (tmp);
- gda_connection_add_event (cnc, event);
- }
- }
-
- gda_connection_internal_treat_sql (cnc, arr[n], error);
- n++;
- }
-
- g_strfreev (arr);
- }
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
- return reclist;
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+ TO_IMPLEMENT;
+ return NULL;
}
-/* get_database handler for the GdaMysqlProvider class */
+/*
+ * Get database request
+ *
+ * Returns the server version as a string, which should be stored in @cnc's associated MysqlConnectionData structure
+ */
static const gchar *
-gda_mysql_provider_get_database (GdaServerProvider *provider,
- GdaConnection *cnc)
+gda_mysql_provider_get_database (GdaServerProvider *provider,
+ GdaConnection *cnc)
{
- MYSQL *mysql;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), NULL);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return NULL;
- }
-
- return (const gchar *) mysql->db;
+ TO_IMPLEMENT;
+ return NULL;
}
-/* change_database handler for the GdaMysqlProvider class */
+/*
+ * Support operation request
+ *
+ * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
+ * - create a mysql_specs_....xml.in file describing the required and optional parameters for the operation
+ * - add it to the Makefile.am
+ * - make this method return TRUE for the operation type
+ * - implement the gda_mysql_provider_render_operation() and gda_mysql_provider_perform_operation() methods
+ *
+ * In this example, the GDA_SERVER_OPERATION_CREATE_TABLE is implemented
+ */
static gboolean
-gda_mysql_provider_change_database (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name)
-{
- gint rc;
- MYSQL *mysql;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
-
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- g_return_val_if_fail (name != NULL, FALSE);
-
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return FALSE;
+gda_mysql_provider_supports_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperationType type,
+ GdaSet *options)
+{
+ g_print ("*** %s\n", __func__);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
}
- rc = mysql_select_db (mysql, name);
- if (rc != 0) {
- gda_connection_add_event (cnc, gda_mysql_make_error (mysql));
+ switch (type) {
+ case GDA_SERVER_OPERATION_CREATE_DB:
+ case GDA_SERVER_OPERATION_DROP_DB:
return FALSE;
- }
- return TRUE;
-}
-
-static gboolean
-gda_mysql_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type, GdaParameterList *options)
-{
- switch (type) {
- case GDA_SERVER_OPERATION_CREATE_DB:
- case GDA_SERVER_OPERATION_DROP_DB:
-
- case GDA_SERVER_OPERATION_CREATE_TABLE:
- case GDA_SERVER_OPERATION_DROP_TABLE:
- case GDA_SERVER_OPERATION_RENAME_TABLE:
+ case GDA_SERVER_OPERATION_CREATE_TABLE:
+ return TRUE;
+ case GDA_SERVER_OPERATION_DROP_TABLE:
+ case GDA_SERVER_OPERATION_RENAME_TABLE:
- case GDA_SERVER_OPERATION_ADD_COLUMN:
- case GDA_SERVER_OPERATION_DROP_COLUMN:
+ case GDA_SERVER_OPERATION_ADD_COLUMN:
- case GDA_SERVER_OPERATION_CREATE_INDEX:
- case GDA_SERVER_OPERATION_DROP_INDEX:
+ case GDA_SERVER_OPERATION_CREATE_INDEX:
+ case GDA_SERVER_OPERATION_DROP_INDEX:
- case GDA_SERVER_OPERATION_CREATE_VIEW:
- case GDA_SERVER_OPERATION_DROP_VIEW:
- return TRUE;
- default:
- return FALSE;
- }
+ case GDA_SERVER_OPERATION_CREATE_VIEW:
+ case GDA_SERVER_OPERATION_DROP_VIEW:
+ default:
+ return FALSE;
+ }
}
+/*
+ * Create operation request
+ *
+ * Creates a #GdaServerOperation. The following code is generic and should only be changed
+ * if some further initialization is required, or if operation's contents is dependant on @cnc
+ */
static GdaServerOperation *
-gda_mysql_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperationType type,
- GdaParameterList *options, GError **error)
-{
- gchar *file;
- GdaServerOperation *op;
- gchar *str;
+gda_mysql_provider_create_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperationType type,
+ GdaSet *options,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ gchar *file;
+ GdaServerOperation *op;
+ gchar *str;
gchar *dir;
-
- file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
- str = g_strdup_printf ("mysql_specs_%s.xml", file);
- g_free (file);
+
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+ }
+
+ file = g_utf8_strdown (gda_server_operation_op_type_to_string (type), -1);
+ str = g_strdup_printf ("mysql_specs_%s.xml", file);
+ g_free (file);
dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
- file = gda_server_provider_find_file (provider, dir, str);
+ file = gda_server_provider_find_file (provider, dir, str);
g_free (dir);
+ g_free (str);
- if (! file) {
- g_set_error (error, 0, 0, _("Missing spec. file '%s'"), str);
- g_free (str);
- return NULL;
- }
- g_free (str);
+ if (! file) {
+ g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
+ return NULL;
+ }
- op = gda_server_operation_new (type, file);
- g_free (file);
+ op = gda_server_operation_new (type, file);
+ g_free (file);
- return op;
+ return op;
}
+/*
+ * Render operation request
+ */
static gchar *
-gda_mysql_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, GError **error)
-{
- gchar *sql = NULL;
- gchar *file;
- gchar *str;
+gda_mysql_provider_render_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperation *op,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ gchar *sql = NULL;
+ gchar *file;
+ gchar *str;
gchar *dir;
- file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
- str = g_strdup_printf ("mysql_specs_%s.xml", file);
- g_free (file);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+ }
+
+ /* test @op's validity */
+ file = g_utf8_strdown (gda_server_operation_op_type_to_string (gda_server_operation_get_op_type (op)), -1);
+ str = g_strdup_printf ("mysql_specs_%s.xml", file);
+ g_free (file);
dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
- file = gda_server_provider_find_file (provider, dir, str);
+ file = gda_server_provider_find_file (provider, dir, str);
g_free (dir);
- g_free (str);
+ g_free (str);
- if (! file) {
- g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
- return NULL;
- }
- if (!gda_server_operation_is_valid (op, file, error)) {
- g_free (file);
- return NULL;
- }
- g_free (file);
+ if (! file) {
+ g_set_error (error, 0, 0, _("Missing spec. file '%s'"), file);
+ return NULL;
+ }
+ if (!gda_server_operation_is_valid (op, file, error)) {
+ g_free (file);
+ return NULL;
+ }
+ g_free (file);
- switch (gda_server_operation_get_op_type (op)) {
- case GDA_SERVER_OPERATION_CREATE_DB:
- sql = gda_mysql_render_CREATE_DB (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_DROP_DB:
- sql = gda_mysql_render_DROP_DB (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_CREATE_TABLE:
- sql = gda_mysql_render_CREATE_TABLE (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_DROP_TABLE:
- sql = gda_mysql_render_DROP_TABLE (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_RENAME_TABLE:
- sql = gda_mysql_render_RENAME_TABLE (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_ADD_COLUMN:
- sql = gda_mysql_render_ADD_COLUMN (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_DROP_COLUMN:
- sql = gda_mysql_render_DROP_COLUMN (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_CREATE_INDEX:
- sql = gda_mysql_render_CREATE_INDEX (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_DROP_INDEX:
- sql = gda_mysql_render_DROP_INDEX (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_CREATE_VIEW:
- sql = gda_mysql_render_CREATE_VIEW (provider, cnc, op, error);
- break;
- case GDA_SERVER_OPERATION_DROP_VIEW:
- sql = gda_mysql_render_DROP_VIEW (provider, cnc, op, error);
- break;
- default:
- g_assert_not_reached ();
- }
- return sql;
+ /* actual rendering */
+ switch (gda_server_operation_get_op_type (op)) {
+ case GDA_SERVER_OPERATION_CREATE_DB:
+ case GDA_SERVER_OPERATION_DROP_DB:
+ sql = NULL;
+ break;
+ case GDA_SERVER_OPERATION_CREATE_TABLE:
+ sql = gda_mysql_render_CREATE_TABLE (provider, cnc, op, error);
+ break;
+ case GDA_SERVER_OPERATION_DROP_TABLE:
+ case GDA_SERVER_OPERATION_RENAME_TABLE:
+ case GDA_SERVER_OPERATION_ADD_COLUMN:
+ case GDA_SERVER_OPERATION_CREATE_INDEX:
+ case GDA_SERVER_OPERATION_DROP_INDEX:
+ case GDA_SERVER_OPERATION_CREATE_VIEW:
+ case GDA_SERVER_OPERATION_DROP_VIEW:
+ sql = NULL;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ return sql;
}
+/*
+ * Perform operation request
+ */
static gboolean
-gda_mysql_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
- GdaServerOperation *op, GError **error)
-{
- GdaServerOperationType optype;
-
- optype = gda_server_operation_get_op_type (op);
- if (!cnc &&
- ((optype == GDA_SERVER_OPERATION_CREATE_DB) ||
- (optype == GDA_SERVER_OPERATION_DROP_DB))) {
- const GValue *value;
- MYSQL *mysql;
- const gchar *login = NULL;
- const gchar *password = NULL;
- const gchar *host = NULL;
- gint port = -1;
- const gchar *socket = NULL;
- gboolean usessl = FALSE;
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/HOST");
- if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
- host = g_value_get_string (value);
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/PORT");
- if (value && G_VALUE_HOLDS (value, G_TYPE_INT) && (g_value_get_int (value) > 0))
- port = g_value_get_int (value);
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/UNIX_SOCKET");
- if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
- socket = g_value_get_string (value);
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/USE_SSL");
- if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
- usessl = TRUE;
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/ADM_LOGIN");
- if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
- login = g_value_get_string (value);
-
- value = gda_server_operation_get_value_at (op, "/SERVER_CNX_P/ADM_PASSWORD");
- if (value && G_VALUE_HOLDS (value, G_TYPE_STRING) && g_value_get_string (value))
- password = g_value_get_string (value);
-
- mysql = real_open_connection (host, port, socket,
- "mysql", login, password, usessl, error);
- if (!mysql)
- return FALSE;
- else {
- gchar *sql;
- int res;
-
- sql = gda_server_provider_render_operation (provider, cnc, op, error);
- if (!sql)
- return FALSE;
-
- GdaConnectionEvent *event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
- gda_connection_event_set_description (event, sql);
- gda_connection_add_event (cnc, event);
+gda_mysql_provider_perform_operation (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaServerOperation *op,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ GdaServerOperationType optype;
+
+ /* If asynchronous connection opening is not supported, then exit now */
+ if (async_cb) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ _("Provider does not support asynchronous server operation"));
+ return FALSE;
+ }
- res = mysql_query (mysql, sql);
- g_free (sql);
-
- if (res) {
- g_set_error (error, 0, 0, mysql_error (mysql));
- mysql_close (mysql);
- return FALSE;
- }
- else {
- mysql_close (mysql);
- return TRUE;
- }
- }
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
}
- else {
+ optype = gda_server_operation_get_op_type (op);
+ switch (optype) {
+ case GDA_SERVER_OPERATION_CREATE_DB:
+ case GDA_SERVER_OPERATION_DROP_DB:
+ default:
/* use the SQL from the provider to perform the action */
- gchar *sql;
- GdaCommand *cmd;
-
- sql = gda_server_provider_render_operation (provider, cnc, op, error);
- if (!sql)
- return FALSE;
-
- cmd = gda_command_new (sql, GDA_COMMAND_TYPE_SQL, GDA_COMMAND_OPTION_STOP_ON_ERRORS);
- g_free (sql);
- if (gda_connection_execute_non_select_command (cnc, cmd, NULL, error) != -1) {
- gda_command_free (cmd);
- return TRUE;
- }
- else {
- gda_command_free (cmd);
- return FALSE;
- }
+ return gda_server_provider_perform_operation_default (provider, cnc, op, error);
}
}
+/*
+ * Begin transaction request
+ */
+static gboolean
+gda_mysql_provider_begin_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GdaTransactionIsolation level,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
-/* execute_command handler for the GdaMysqlProvider class */
-static GList *
-gda_mysql_provider_execute_command (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaCommand *cmd,
- GdaParameterList *params)
-{
- GList *reclist = NULL;
- gchar *str;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
-
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), NULL);
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (cmd != NULL, NULL);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- switch (gda_command_get_command_type (cmd)) {
- case GDA_COMMAND_TYPE_SQL :
- reclist = process_sql_commands (reclist, cnc, gda_command_get_text (cmd));
- break;
- case GDA_COMMAND_TYPE_TABLE :
- str = g_strdup_printf ("SELECT * FROM %s", gda_command_get_text (cmd));
- reclist = process_sql_commands (reclist, cnc, str);
- if (reclist && GDA_IS_DATA_MODEL (reclist->data))
- g_object_set (G_OBJECT (reclist->data),
- "command_text", gda_command_get_text (cmd),
- "command_type", GDA_COMMAND_TYPE_TABLE, NULL);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
- g_free (str);
- break;
- default: break;
- }
+ TO_IMPLEMENT;
- return reclist;
+ return FALSE;
}
-/* get_last_insert_id handler for the GdaMysqlProvider class */
-static gchar *
-gda_mysql_provider_get_last_insert_id (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaDataModel *recset)
+/*
+ * Commit transaction request
+ */
+static gboolean
+gda_mysql_provider_commit_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error)
{
- MYSQL *mysql;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), NULL);
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- if (recset) {
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), NULL);
- TO_IMPLEMENT;
- return NULL;
- }
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return NULL;
- }
+ TO_IMPLEMENT;
- return g_strdup_printf ("%ld", (unsigned long int ) mysql_insert_id (mysql));
+ return FALSE;
}
-/* begin_transaction handler for the GdaMysqlProvider class */
+/*
+ * Rollback transaction request
+ */
static gboolean
-gda_mysql_provider_begin_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GdaTransactionIsolation level,
- GError **error)
-{
- MYSQL *mysql;
- gint rc;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
- GdaConnectionEvent *event = NULL;
+gda_mysql_provider_rollback_transaction (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
- gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode"));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return FALSE;
- }
- /* set isolation level */
- switch (level) {
- case GDA_TRANSACTION_ISOLATION_READ_COMMITTED :
- rc = gda_mysql_real_query_wrap (cnc, mysql, "SET TRANSACTION ISOLATION LEVEL READ COMMITTED", 46);
- break;
- case GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED :
- rc = gda_mysql_real_query_wrap (cnc, mysql, "SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED", 48);
- break;
- case GDA_TRANSACTION_ISOLATION_REPEATABLE_READ :
- rc = gda_mysql_real_query_wrap (cnc, mysql, "SET TRANSACTION ISOLATION LEVEL REPEATABLE READ", 47);
- break;
- case GDA_TRANSACTION_ISOLATION_SERIALIZABLE :
- rc = gda_mysql_real_query_wrap (cnc, mysql, "SET TRANSACTION ISOLATION LEVEL SERIALIZABLE", 44);
- break;
- default :
- rc = 0;
- }
+ TO_IMPLEMENT;
- if (rc != 0) {
- event = gda_mysql_make_error (mysql);
- gda_connection_add_event (cnc, event);
- }
- else {
- /* start the transaction */
- rc = gda_mysql_real_query_wrap (cnc, mysql, "BEGIN", 5);
- if (rc != 0) {
- event = gda_mysql_make_error (mysql);
- gda_connection_add_event (cnc, event);
- }
- }
-
- gda_connection_internal_treat_sql (cnc, "BEGIN", event);
- return event ? FALSE : TRUE;
+ return FALSE;
}
-/* commit_transaction handler for the GdaMysqlProvider class */
+/*
+ * Add savepoint request
+ */
static gboolean
-gda_mysql_provider_commit_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GError **error)
-{
- MYSQL *mysql;
- gint rc;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
- GdaConnectionEvent *event = NULL;
+gda_mysql_provider_add_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
- gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode"));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return FALSE;
- }
- rc = gda_mysql_real_query_wrap (cnc, mysql, "COMMIT", 6);
- if (rc != 0) {
- event = gda_mysql_make_error (mysql);
- gda_connection_add_event (cnc, event);
- }
+ TO_IMPLEMENT;
- gda_connection_internal_treat_sql (cnc, "COMMIT", event);
- return event ? FALSE : TRUE;
+ return FALSE;
}
-/* rollback_transaction handler for the GdaMysqlProvider class */
-static gboolean
-gda_mysql_provider_rollback_transaction (GdaServerProvider *provider,
- GdaConnection *cnc,
- const gchar *name, GError **error)
-{
- MYSQL *mysql;
- gint rc;
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
- GdaConnectionEvent *event = NULL;
+/*
+ * Rollback savepoint request
+ */
+static gboolean
+gda_mysql_provider_rollback_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- if (gda_connection_get_options (cnc) & GDA_CONNECTION_OPTIONS_READ_ONLY) {
- gda_connection_add_event_string (cnc, _("Transactions are not supported in read-only mode"));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return FALSE;
- }
- rc = gda_mysql_real_query_wrap (cnc, mysql, "ROLLBACK", 8);
- if (rc != 0) {
- event = gda_mysql_make_error (mysql);
- gda_connection_add_event (cnc, event);
- }
-
- gda_connection_internal_treat_sql (cnc, "ROLLBACK", event);
- return event ? FALSE : TRUE;
-}
-
-/* supports handler for the GdaMysqlProvider class */
-static gboolean
-gda_mysql_provider_supports (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaConnectionFeature feature)
-{
- GdaMysqlProvider *myprv = (GdaMysqlProvider *) provider;
-
- g_return_val_if_fail (GDA_IS_MYSQL_PROVIDER (myprv), FALSE);
-
- switch (feature) {
- case GDA_CONNECTION_FEATURE_AGGREGATES :
- case GDA_CONNECTION_FEATURE_SQL :
- case GDA_CONNECTION_FEATURE_TRANSACTIONS :
- return TRUE;
- default : break;
- }
+ TO_IMPLEMENT;
return FALSE;
}
-static GdaServerProviderInfo *
-gda_mysql_provider_get_info (GdaServerProvider *provider, GdaConnection *cnc)
+/*
+ * Delete savepoint request
+ */
+static gboolean
+gda_mysql_provider_delete_savepoint (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const gchar *name,
+ GError **error)
{
- static GdaServerProviderInfo info = {
- "MySQL",
- TRUE,
- TRUE,
- TRUE,
- TRUE,
- TRUE,
- FALSE
- };
-
- return &info;
-}
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
-static void
-add_aggregate_row (GdaDataModelArray *recset, const gchar *str, const gchar *comments)
-{
- GList *list;
- GValue *tmpval;
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
- g_return_if_fail (GDA_IS_DATA_MODEL_ARRAY (recset));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
- /* 1st the name */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), str);
- list = g_list_append (NULL, tmpval);
- /* 2nd the unique id */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), str);
- list = g_list_append (list, tmpval);
- /* 3rd the owner */
- list = g_list_append (list, gda_value_new_null ());
- /* 4th the comments */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), comments);
- list = g_list_append (list, tmpval);
- /* 5th the return type */
- list = g_list_append (list, gda_value_new_null ());
- /* 6th the argument type */
- list = g_list_append (list, gda_value_new_null ());
- /* 7th the SQL definition */
- list = g_list_append (list, gda_value_new_null ());
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset), list, NULL);
+ TO_IMPLEMENT;
- g_list_foreach (list, (GFunc) gda_value_free, NULL);
- g_list_free (list);
+ return FALSE;
}
-static GdaDataModel *
-get_mysql_aggregates (GdaConnection *cnc, GdaParameterList *params)
+/*
+ * Feature support request
+ */
+static gboolean
+gda_mysql_provider_supports_feature (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaConnectionFeature feature)
{
- GdaDataModelArray *recset;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- /* create the recordset */
- recset = (GdaDataModelArray *) gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_AGGREGATES));
- gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_AGGREGATES);
-
- /* fill the recordset */
- add_aggregate_row (recset, "abs", "");
- add_aggregate_row (recset, "acos", "");
- add_aggregate_row (recset, "adddate", "");
- add_aggregate_row (recset, "ascii", "");
- add_aggregate_row (recset, "asin", "");
- add_aggregate_row (recset, "atan", "");
- add_aggregate_row (recset, "atan2", "");
- add_aggregate_row (recset, "benchmark", "");
- add_aggregate_row (recset, "bin", "");
- add_aggregate_row (recset, "bit_count", "");
- add_aggregate_row (recset, "ceiling", "");
- add_aggregate_row (recset, "char", "");
- add_aggregate_row (recset, "char_length", "");
- add_aggregate_row (recset, "character_length", "");
- add_aggregate_row (recset, "coalesce", "");
- add_aggregate_row (recset, "concat", "");
- add_aggregate_row (recset, "concat_ws", "");
- add_aggregate_row (recset, "connection_id", "");
- add_aggregate_row (recset, "conv", "");
- add_aggregate_row (recset, "cos", "");
- add_aggregate_row (recset, "cot", "");
- add_aggregate_row (recset, "count", "");
- add_aggregate_row (recset, "curdate", "");
- add_aggregate_row (recset, "current_date", "");
- add_aggregate_row (recset, "current_time", "");
- add_aggregate_row (recset, "current_timestamp", "");
- add_aggregate_row (recset, "curtime", "");
- add_aggregate_row (recset, "database", "");
- add_aggregate_row (recset, "date_add", "");
- add_aggregate_row (recset, "date_format", "");
- add_aggregate_row (recset, "date_sub", "");
- add_aggregate_row (recset, "dayname", "");
- add_aggregate_row (recset, "dayofmonth", "");
- add_aggregate_row (recset, "dayofweek", "");
- add_aggregate_row (recset, "dayofyear", "");
- add_aggregate_row (recset, "decode", "");
- add_aggregate_row (recset, "degrees", "");
- add_aggregate_row (recset, "elt", "");
- add_aggregate_row (recset, "encode", "");
- add_aggregate_row (recset, "encrypt", "");
- add_aggregate_row (recset, "exp", "");
- add_aggregate_row (recset, "export_set", "");
- add_aggregate_row (recset, "extract", "");
- add_aggregate_row (recset, "field", "");
- add_aggregate_row (recset, "find_in_set", "");
- add_aggregate_row (recset, "floor", "");
- add_aggregate_row (recset, "format", "");
- add_aggregate_row (recset, "from_days", "");
- add_aggregate_row (recset, "from_unixtime", "");
- add_aggregate_row (recset, "get_lock", "");
- add_aggregate_row (recset, "greatest", "");
- add_aggregate_row (recset, "hex", "");
- add_aggregate_row (recset, "hour", "");
- add_aggregate_row (recset, "if", "");
- add_aggregate_row (recset, "ifnull", "");
- add_aggregate_row (recset, "inet_aton", "");
- add_aggregate_row (recset, "inet_ntoa", "");
- add_aggregate_row (recset, "insert", "");
- add_aggregate_row (recset, "instr", "");
- add_aggregate_row (recset, "interval", "");
- add_aggregate_row (recset, "isnull", "");
- add_aggregate_row (recset, "last_insert_id", "");
- add_aggregate_row (recset, "lcase", "");
- add_aggregate_row (recset, "least", "");
- add_aggregate_row (recset, "left", "");
- add_aggregate_row (recset, "length", "");
- add_aggregate_row (recset, "load_file", "");
- add_aggregate_row (recset, "locate", "");
- add_aggregate_row (recset, "log", "");
- add_aggregate_row (recset, "log10", "");
- add_aggregate_row (recset, "lower", "");
- add_aggregate_row (recset, "lpad", "");
- add_aggregate_row (recset, "ltrim", "");
- add_aggregate_row (recset, "make_set", "");
- add_aggregate_row (recset, "master_pos_wait", "");
- add_aggregate_row (recset, "match", "");
- add_aggregate_row (recset, "max", "");
- add_aggregate_row (recset, "md5", "");
- add_aggregate_row (recset, "mid", "");
- add_aggregate_row (recset, "min", "");
- add_aggregate_row (recset, "minute", "");
- add_aggregate_row (recset, "mod", "");
- add_aggregate_row (recset, "month", "");
- add_aggregate_row (recset, "monthname", "");
- add_aggregate_row (recset, "now", "");
- add_aggregate_row (recset, "nullif", "");
- add_aggregate_row (recset, "oct", "");
- add_aggregate_row (recset, "octet_length", "");
- add_aggregate_row (recset, "ord", "");
- add_aggregate_row (recset, "password", "");
- add_aggregate_row (recset, "period_add", "");
- add_aggregate_row (recset, "period_diff", "");
- add_aggregate_row (recset, "pi", "");
- add_aggregate_row (recset, "position", "");
- add_aggregate_row (recset, "pow", "");
- add_aggregate_row (recset, "power", "");
- add_aggregate_row (recset, "quarter", "");
- add_aggregate_row (recset, "radians", "");
- add_aggregate_row (recset, "rand", "");
- add_aggregate_row (recset, "release_lock", "");
- add_aggregate_row (recset, "repeat", "");
- add_aggregate_row (recset, "replace", "");
- add_aggregate_row (recset, "reverse", "");
- add_aggregate_row (recset, "right", "");
- add_aggregate_row (recset, "round", "");
- add_aggregate_row (recset, "rpad", "");
- add_aggregate_row (recset, "rtrim", "");
- add_aggregate_row (recset, "second", "");
- add_aggregate_row (recset, "sec_to_time", "");
- add_aggregate_row (recset, "session_user", "");
- add_aggregate_row (recset, "sign", "");
- add_aggregate_row (recset, "sin", "");
- add_aggregate_row (recset, "soundex", "");
- add_aggregate_row (recset, "space", "");
- add_aggregate_row (recset, "sqrt", "");
- add_aggregate_row (recset, "strcmp", "");
- add_aggregate_row (recset, "subdate", "");
- add_aggregate_row (recset, "substring", "");
- add_aggregate_row (recset, "substring_index", "");
- add_aggregate_row (recset, "sysdate", "");
- add_aggregate_row (recset, "system_user", "");
- add_aggregate_row (recset, "tan", "");
- add_aggregate_row (recset, "time_format", "");
- add_aggregate_row (recset, "time_to_sec", "");
- add_aggregate_row (recset, "to_days", "");
- add_aggregate_row (recset, "trim", "");
- add_aggregate_row (recset, "truncate", "");
- add_aggregate_row (recset, "ucase", "");
- add_aggregate_row (recset, "unix_timestamp", "");
- add_aggregate_row (recset, "upper", "");
- add_aggregate_row (recset, "user", "");
- add_aggregate_row (recset, "version", "");
- add_aggregate_row (recset, "week", "");
- add_aggregate_row (recset, "weekday", "");
- add_aggregate_row (recset, "year", "");
- add_aggregate_row (recset, "yearweek", "");
+ g_print ("*** %s\n", __func__);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+ }
- return GDA_DATA_MODEL (recset);
+ switch (feature) {
+ case GDA_CONNECTION_FEATURE_SQL :
+ return TRUE;
+ default:
+ return FALSE;
+ }
}
-static GdaDataModel *
-get_mysql_databases (GdaConnection *cnc, GdaParameterList *params)
-{
- GList *reclist;
- GdaMysqlRecordset *recset;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- reclist = process_sql_commands (NULL, cnc, "show databases");
- if (!reclist)
- return NULL;
+/*
+ * Get data handler request
+ *
+ * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
+ * must be considered only if @type is not a valid GType).
+ *
+ * A data handler allows one to convert a value between its different representations which are a human readable string,
+ * an SQL representation and a GValue.
+ *
+ * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
+ * for further usage, using the gda_server_provider_handler_declare() method.
+ *
+ * The implementation shown here does not define any specific data handler, but there should be some for at least
+ * binary and time related types.
+ */
+static GdaDataHandler *
+gda_mysql_provider_get_data_handler (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GType type,
+ const gchar *dbms_type)
+{
+ g_print ("*** %s\n", __func__);
+ GdaDataHandler *dh;
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+ }
- recset = GDA_MYSQL_RECORDSET (reclist->data);
- g_list_free (reclist);
+ if (type == G_TYPE_INVALID) {
+ TO_IMPLEMENT; /* use @dbms_type */
+ dh = NULL;
+ }
+ else if ((type == GDA_TYPE_BINARY) ||
+ (type == GDA_TYPE_BLOB)) {
+ TO_IMPLEMENT; /* define data handlers for these types */
+ dh = NULL;
+ }
+ else if ((type == GDA_TYPE_TIME) ||
+ (type == GDA_TYPE_TIMESTAMP) ||
+ (type == G_TYPE_DATE)) {
+ TO_IMPLEMENT; /* define data handlers for these types */
+ dh = NULL;
+ }
+ else
+ dh = gda_server_provider_get_data_handler_default (provider, cnc, type, dbms_type);
- return GDA_DATA_MODEL (recset);
+ return dh;
}
-static GdaDataModel *
-get_mysql_tables (GdaConnection *cnc, GdaParameterList *params)
+/*
+ * Get default DBMS type request
+ *
+ * This method returns the "preferred" DBMS type for GType
+ */
+static const gchar*
+gda_mysql_provider_get_default_dbms_type (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GType type)
{
- GList *reclist;
- GdaMysqlRecordset *recset;
- GdaDataModel *model;
- gint rows, r;
- GdaParameter *par = NULL;
- const gchar *tablename = NULL;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- if (params) {
- par = gda_parameter_list_find_param (params, "name");
- if (par)
- tablename = g_value_get_string ((GValue *) gda_parameter_get_value (par));
+ g_print ("*** %s\n", __func__);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
}
- reclist = process_sql_commands (NULL, cnc, "show table status");
- if (!reclist)
- return NULL;
-
- recset = (GdaMysqlRecordset *) reclist->data;
- g_list_free (reclist);
- if (!GDA_IS_MYSQL_RECORDSET (recset))
- return NULL;
-
- /* add the extra information */
- model = gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_TABLES));
- gda_server_provider_init_schema_model (model, GDA_CONNECTION_SCHEMA_TABLES);
-
- rows = gda_data_model_get_n_rows (GDA_DATA_MODEL (recset));
- for (r = 0; r < rows; r++) {
- GList *value_list = NULL;
- const gchar *name;
- gchar *str;
- GValue *tmpval;
+ TO_IMPLEMENT;
- if (tablename) {
- const GValue *cvalue;
-
- cvalue = gda_data_model_get_value_at (GDA_DATA_MODEL (recset), 0, r);
- if (strcmp (tablename, g_value_get_string (cvalue)))
- continue;
- }
-
- /* 1st, the name of the table */
- tmpval = gda_value_copy ((GValue *) gda_data_model_get_value_at (GDA_DATA_MODEL (recset), 0, r));
- name = g_value_get_string (tmpval);
- value_list = g_list_append (value_list, tmpval);
-
- /* 2nd, the owner */
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- /* 3rd, the comments */
- tmpval = gda_value_copy ((GValue *) gda_data_model_get_value_at (GDA_DATA_MODEL (recset), 14, r));
- value_list = g_list_append (value_list, tmpval);
-
- /* 4th, the SQL command */
- str = g_strdup_printf ("SHOW CREATE TABLE %s", name);
- reclist = process_sql_commands (NULL, cnc, str);
- g_free (str);
- if (reclist && GDA_IS_DATA_MODEL (reclist->data)) {
- tmpval = gda_value_copy ((GValue *) gda_data_model_get_value_at (GDA_DATA_MODEL (reclist->data), 1, 0));
- value_list = g_list_append (value_list, tmpval);
-
- g_list_foreach (reclist, (GFunc) g_object_unref, NULL);
- g_list_free (reclist);
- }
- else
- value_list = g_list_append (value_list, gda_value_new_null ());
+ if ((type == G_TYPE_INT64) ||
+ (type == G_TYPE_INT) ||
+ (type == GDA_TYPE_SHORT) ||
+ (type == GDA_TYPE_USHORT) ||
+ (type == G_TYPE_CHAR) ||
+ (type == G_TYPE_UCHAR) ||
+ (type == G_TYPE_ULONG) ||
+ (type == G_TYPE_UINT) ||
+ (type == G_TYPE_UINT64))
+ return "integer";
+
+ if ((type == GDA_TYPE_BINARY) ||
+ (type == GDA_TYPE_BLOB))
+ return "blob";
- gda_data_model_append_values (model, value_list, NULL);
+ if (type == G_TYPE_BOOLEAN)
+ return "boolean";
+
+ if ((type == G_TYPE_DATE) ||
+ (type == GDA_TYPE_GEOMETRIC_POINT) ||
+ (type == G_TYPE_OBJECT) ||
+ (type == GDA_TYPE_LIST) ||
+ (type == G_TYPE_STRING) ||
+ (type == GDA_TYPE_TIME) ||
+ (type == GDA_TYPE_TIMESTAMP) ||
+ (type == G_TYPE_INVALID))
+ return "string";
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- }
+ if ((type == G_TYPE_DOUBLE) ||
+ (type == GDA_TYPE_NUMERIC) ||
+ (type == G_TYPE_FLOAT))
+ return "real";
+
+ if (type == GDA_TYPE_TIME)
+ return "time";
+ if (type == GDA_TYPE_TIMESTAMP)
+ return "timestamp";
+ if (type == G_TYPE_DATE)
+ return "date";
- return model;
+ return "text";
}
-static GdaDataModel *
-get_mysql_views (GdaConnection *cnc, GdaParameterList *params)
+/*
+ * Create parser request
+ *
+ * This method is responsible for creating a #GdaSqlParser object specific to the SQL dialect used
+ * by the database. See the PostgreSQL provider implementation for an example.
+ */
+static GdaSqlParser *
+gda_mysql_provider_create_parser (GdaServerProvider *provider,
+ GdaConnection *cnc)
{
- GdaDataModel *model;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- /* add the extra information */
- model = gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_VIEWS));
- gda_server_provider_init_schema_model (model, GDA_CONNECTION_SCHEMA_VIEWS);
-
- /* views are not yet supported in MySql => return an empty set */
-
- return model;
-}
-
-static GdaDataModel *
-get_mysql_procedures (GdaConnection *cnc, GdaParameterList *params)
-{
- GdaDataModel *model;
- gint i;
-
- struct {
- const gchar *name;
- const gchar *id;
- /*const gchar *owner; "" */
- const gchar *comments;
- const gchar *rettype;
- gint nb_args;
- const gchar *argtypes;
- /*const gchar *definition; NULL */
- } procs[] = {
- { "ascii", "ascii", "", "smallint", 1, "text"},
- { "bin", "bin", "", "text", 1, "bigint"},
- { "bit_length", "bit_length", "", "int", 1, "text"},
- { "char", "char", "", "text", -1, "-"}
- };
-
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- /* add the extra information */
- model = gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_PROCEDURES));
- gda_server_provider_init_schema_model (model, GDA_CONNECTION_SCHEMA_PROCEDURES);
-
- /* fill the recordset */
- for (i = 0; i < sizeof (procs) / sizeof (procs[0]); i++) {
- GList *value_list = NULL;
- GValue *tmpval;
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), procs[i].name);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), procs[i].id);
- value_list = g_list_append (value_list, tmpval);
-
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), procs[i].comments);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), procs[i].rettype);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), procs[i].nb_args);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), procs[i].argtypes);
- value_list = g_list_append (value_list, tmpval);
-
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- gda_data_model_append_values (GDA_DATA_MODEL (model), value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- }
-
- return model;
-}
-
-
-static GdaDataModel *
-get_mysql_types (GdaConnection *cnc, GdaParameterList *params)
-{
- GdaDataModelArray *recset;
- gint i;
- struct {
- const gchar *name;
- const gchar *owner;
- const gchar *comments;
- GType type;
- const gchar *synonyms;
- } types[] = {
- { "bool", "", "Boolean type", G_TYPE_BOOLEAN, "boolean" },
- { "blob", "", "Binary blob (up to 65535 bytes)", GDA_TYPE_BINARY, NULL },
- { "bigint", "", "Big integer, range is -9223372036854775808 to 9223372036854775807", G_TYPE_INT64, NULL },
- { "bigint unsigned", "", "Big unsigned integer, range is 0 to 18446744073709551615", G_TYPE_UINT64, NULL },
- { "char", "", "Char", G_TYPE_STRING, "binary" },
- { "date", "", "Date", G_TYPE_DATE, NULL },
- { "datetime", "", "Date and time", GDA_TYPE_TIMESTAMP, NULL },
- { "decimal", "", "Decimal number", GDA_TYPE_NUMERIC, "dec,numeric,fixed" },
- { "double", "", "Double precision number", G_TYPE_DOUBLE, "double precision,real" },
- { "double unsigned", "", "Unsigned double precision number", G_TYPE_DOUBLE, "double precision unsigned,real unsigned" },
- { "enum", "", "Enumeration: a string object that can have only one value, chosen from the list of values 'value1', 'value2', ..., NULL or the special '' error value. An ENUM column can have a maximum of 65,535 distinct values", G_TYPE_STRING, NULL },
- { "float", "", "Floating point number", G_TYPE_FLOAT , NULL },
- { "float unsigned", "", "Unsigned floating point number", G_TYPE_FLOAT , NULL },
- { "int", "", "Integer, range is -2147483648 to 2147483647", G_TYPE_INT, "integer" },
- { "int unsigned", "", "Unsigned integer, range is 0 to 4294967295", G_TYPE_UINT, "integer unsigned" },
- { "long", "", "Long integer", G_TYPE_LONG, NULL },
- { "long unsigned", "", "Long unsigned integer", G_TYPE_ULONG, NULL },
- { "longblob", "", "Long blob (up to 4Gb)", GDA_TYPE_BINARY, NULL },
- { "longtext", "", "Long text (up to 4Gb characters)", GDA_TYPE_BINARY, NULL },
- { "mediumint", "", "Medium integer, range is -8388608 to 8388607", G_TYPE_INT, NULL },
- { "mediumint unsigned", "", "Medium unsigned integer, range is 0 to 16777215", G_TYPE_INT, NULL },
- { "mediumblob", "", "Medium blob (up to 16777215 bytes)", GDA_TYPE_BINARY, NULL },
- { "mediumtext", "", "Medium text (up to 16777215 characters)", GDA_TYPE_BINARY, NULL },
- { "set", "", "Set: a string object that can have zero or more values, each of which must be chosen from the list of values 'value1', 'value2', ... A SET column can have a maximum of 64 members", G_TYPE_STRING, NULL },
- { "smallint", "", "Small integer, range is -32768 to 32767", GDA_TYPE_SHORT, NULL },
- { "smallint unsigned", "", "Small unsigned integer, range is 0 to 65535", GDA_TYPE_USHORT, NULL },
- { "text", "", "Text (up to 65535 characters)", GDA_TYPE_BINARY, NULL },
- { "tinyint", "", "Tiny integer, range is -128 to 127", G_TYPE_CHAR, "bit" },
- { "tinyint unsigned", "", "Tiny unsigned integer, range is 0 to 255", G_TYPE_UCHAR, NULL },
- { "tinyblob", "", "Tiny blob (up to 255 bytes)", GDA_TYPE_BINARY, NULL },
- { "tinytext", "", "Tiny text (up to 255 characters)", GDA_TYPE_BINARY, NULL },
- { "time", "", "Time", GDA_TYPE_TIME, NULL },
- { "timestamp", "", "Time stamp", GDA_TYPE_TIMESTAMP, NULL },
- { "varchar", "", "Variable Length Char", G_TYPE_STRING, "varbinary" },
- { "year", "", "Year", G_TYPE_INT, NULL }
- };
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
-
- /* create the recordset */
- recset = (GdaDataModelArray *) gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_TYPES));
- gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_TYPES);
-
- /* fill the recordset */
- for (i = 0; i < sizeof (types) / sizeof (types[0]); i++) {
- GList *value_list = NULL;
- GValue *tmpval;
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), types[i].name);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), types[i].owner);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), types[i].comments);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_ulong (tmpval = gda_value_new (G_TYPE_ULONG), types[i].type);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), types[i].synonyms);
- value_list = g_list_append (value_list, tmpval);
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset), value_list, NULL);
+ g_print ("*** %s\n", __func__);
+ // TO_IMPLEMENT;
+ return (GdaSqlParser *) g_object_new (GDA_TYPE_MYSQL_PARSER,
+ "tokenizer-flavour", GDA_SQL_PARSER_FLAVOUR_MYSQL,
+ NULL);
+}
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
+/*
+ * GdaStatement to SQL request
+ *
+ * This method renders a #GdaStatement into its SQL representation.
+ *
+ * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
+ * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
+ * and SQLite's specialized rendering for more details
+ */
+static gchar *
+gda_mysql_provider_statement_to_sql (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GdaStatementSqlFlag flags,
+ GSList **params_used,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
}
- return GDA_DATA_MODEL (recset);
+ return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
}
-static GList *
-field_row_to_value_list (MYSQL *mysql, MYSQL_ROW mysql_row)
-{
- gchar **arr;
- GList *value_list = NULL;
- GValue *tmpval;
-
- g_return_val_if_fail (mysql_row != NULL, NULL);
-
- /* field name */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), mysql_row[0]);
- value_list = g_list_append (value_list, tmpval);
-
- /* type and size */
- arr = g_strsplit_set ((const gchar *) mysql_row[1], "() ", 0);
- if (!arr) {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
+/*
+ * Statement prepare request
+ *
+ * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
+ * specific in its implementation details to the C API used here. If successfull, it must create
+ * a new #GdaMysqlPStmt object and declare it to @cnc.
+ */
+static gboolean
+gda_mysql_provider_statement_prepare (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlPStmt *ps;
+ MysqlConnectionData *cdata;
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), -1);
- value_list = g_list_append (value_list, tmpval);
- }
- else {
- if (!strcmp (arr[0], "enum") ||
- !strcmp (arr[0], "set")) {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), arr[0]);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), -1);
- value_list = g_list_append (value_list, tmpval);
- }
- else {
- if (arr[0] && arr[1]) {
- gint i, len;
- len = g_strv_length (arr);
- for (i = 2; (i < len) && strcmp (arr[i], "unsigned"); i++);
- if (i < len) {
- gchar *type;
-
- type = g_strdup_printf ("%s unsigned", arr[0]);
- g_value_take_string (tmpval = gda_value_new (G_TYPE_STRING), type);
- }
- else
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), arr[0]);
- value_list = g_list_append (value_list, tmpval);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, FALSE);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
- /* if arr[0] is an int type, hard code its size instead of
- * using arr[1] which is an indication of display padding */
- if (!strcmp (arr[0], "int"))
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 4);
- else if (!strcmp (arr[0], "tinyint"))
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 1);
- else if (!strcmp (arr[0], "smallint"))
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 2);
- else if (!strcmp (arr[0], "mediumint"))
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 3);
- else if (!strcmp (arr[0], "bigint"))
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 8);
- else
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), atoi (arr[1]));
+ /* fetch prepares stmt if already done */
+ ps = gda_connection_get_prepared_statement (cnc, stmt);
+ if (ps)
+ return TRUE;
- value_list = g_list_append (value_list, tmpval);
- }
- else {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), arr[0]);
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), -1);
- value_list = g_list_append (value_list, tmpval);
- }
- }
+ /* prepare @stmt using the C API, creates @ps */
+ // TO_IMPLEMENT;
+
- g_strfreev (arr);
- }
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+ /* Render as SQL understood by Mysql. */
+ GdaSet *set;
+ if (!gda_statement_get_parameters (stmt, &set, error))
+ return FALSE;
- /* scale */
- g_value_set_int (tmpval = gda_value_new (G_TYPE_INT), 0);
- value_list = g_list_append (value_list, tmpval);
+ GSList *used_set = NULL;
+ gchar *sql = gda_mysql_provider_statement_to_sql
+ (provider, cnc, stmt, set,
+ GDA_STATEMENT_SQL_PARAMS_AS_QMARK, &used_set, error);
- /* Not null? */
- if (mysql_row[2] && !strcmp (mysql_row[2], "YES"))
- g_value_set_boolean (tmpval = gda_value_new (G_TYPE_BOOLEAN), FALSE);
- else
- g_value_set_boolean (tmpval = gda_value_new (G_TYPE_BOOLEAN), TRUE);
- value_list = g_list_append (value_list, tmpval);
+
+ if (!sql)
+ goto cleanup;
- /* Primary key? */
- if (mysql_row[3] && !strcmp (mysql_row[3], "PRI"))
- g_value_set_boolean (tmpval = gda_value_new (G_TYPE_BOOLEAN), TRUE);
- else
- g_value_set_boolean (tmpval = gda_value_new (G_TYPE_BOOLEAN), FALSE);
- value_list = g_list_append (value_list, tmpval);
+ if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
+ GdaConnectionEvent *event = _gda_mysql_make_error
+ (cdata->cnc, cdata->mysql, NULL);
+ goto cleanup;
+ }
+
+ GSList *param_ids = NULL, *current;
+ for (current = used_set; current; current = current->next) {
+ const gchar *id = gda_holder_get_id
+ (GDA_HOLDER(current->data));
+ if (id) {
+ param_ids = g_slist_append (param_ids,
+ g_strdup (id));
+ g_print ("MYSQL preparation: param id=%s\n", id);
+ } else {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+ _("Unnamed holder is not allowed in prepared statement."));
+ g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+ g_slist_free (param_ids);
+ param_ids = NULL;
- /* Unique index? */
- g_value_set_boolean (tmpval = gda_value_new (G_TYPE_BOOLEAN), FALSE);
- value_list = g_list_append (value_list, tmpval);
-
- /* references */
- if (atoi (mysql->server_version) < 5) {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
- }
- else {
- if (mysql_row[6] && mysql_row[7]) {
- gchar *str = g_strdup_printf ("%s.%s", mysql_row[6], mysql_row[7]);
- g_value_take_string (tmpval = gda_value_new (G_TYPE_STRING), str);
- value_list = g_list_append (value_list, tmpval);
+ goto cleanup;
}
- else {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
- }
- }
-
- /* default value */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), mysql_row[4]);
- value_list = g_list_append (value_list, tmpval);
-
- /* Extra column */
- if (!strcmp (mysql_row[5], "auto_increment"))
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "AUTO_INCREMENT");
- else
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
-
- return value_list;
-}
-
-static GdaDataModel *
-get_table_fields (GdaConnection *cnc, GdaParameterList *params)
-{
- const gchar *table_name;
- GdaParameter *par;
- gchar *cmd_str;
- GdaDataModelArray *recset;
- gint rows, r;
- gint rc;
- MYSQL *mysql;
- MYSQL_RES *mysql_res;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (params != NULL, NULL);
-
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return NULL;
- }
-
- /* get parameters sent by client */
- par = gda_parameter_list_find_param (params, "name");
- if (!par) {
- gda_connection_add_event_string (
- cnc,
- _("Table name is needed but none specified in parameter list"));
- return NULL;
}
- table_name = g_value_get_string ((GValue *) gda_parameter_get_value (par));
- if (!table_name) {
- gda_connection_add_event_string (
- cnc,
- _("Table name is needed but none specified in parameter list"));
- return NULL;
- }
-
- /* execute command on server */
- if (atoi (mysql->server_version) < 5)
- cmd_str = g_strdup_printf ("SHOW COLUMNS FROM %s", table_name);
+ /* Create prepared statement. */
+ ps = gda_mysql_pstmt_new (cnc, cdata->mysql, cdata->mysql_stmt);
+
+ if (!ps)
+ return FALSE;
else {
- /* with MySQL >= 5.0 there are foreign keys: add support for those */
- cmd_str = g_strdup_printf ("SELECT c.COLUMN_NAME, c.COLUMN_TYPE, c.IS_NULLABLE, c.COLUMN_KEY, "
- "c.COLUMN_DEFAULT, c.EXTRA, "
- "u.REFERENCED_TABLE_NAME, u.REFERENCED_COLUMN_NAME "
- "FROM INFORMATION_SCHEMA.COLUMNS c "
- "LEFT OUTER JOIN "
- "(SELECT sub.TABLE_SCHEMA, sub.COLUMN_NAME, sub.TABLE_NAME, "
- "sub.REFERENCED_TABLE_NAME, sub.REFERENCED_COLUMN_NAME "
- "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE sub where sub.TABLE_NAME='%s' "
- "AND sub.REFERENCED_TABLE_NAME IS NOT NULL) u "
- "ON (c.TABLE_NAME = u.TABLE_NAME AND c.TABLE_SCHEMA = u.TABLE_SCHEMA "
- "AND c.COLUMN_NAME = u.COLUMN_NAME) "
- "WHERE c.TABLE_NAME = '%s' AND c.TABLE_SCHEMA = DATABASE() "
- "ORDER BY c.ORDINAL_POSITION",
- table_name, table_name);
- }
-
- rc = gda_mysql_real_query_wrap (cnc, mysql, cmd_str, strlen (cmd_str));
- g_free (cmd_str);
- if (rc != 0) {
- gda_connection_add_event (cnc, gda_mysql_make_error (mysql));
- return NULL;
- }
-
- mysql_res = mysql_store_result (mysql);
- rows = mysql_num_rows (mysql_res);
-
- /* fill in the recordset to be returned */
- recset = (GdaDataModelArray *) gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_FIELDS));
- gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_FIELDS);
-
- for (r = 0; r < rows; r++) {
- GList *value_list;
- MYSQL_ROW mysql_row;
-
- mysql_data_seek (mysql_res, r);
- mysql_row = mysql_fetch_row (mysql_res);
- if (!mysql_row) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
-
- value_list = field_row_to_value_list (mysql, mysql_row);
- if (!value_list) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
+
+ gda_pstmt_set_gda_statement (_GDA_PSTMT(ps), stmt);
+ _GDA_PSTMT(ps)->param_ids = param_ids;
+ _GDA_PSTMT(ps)->sql = sql;
+
+ gda_connection_add_prepared_statement (cnc, stmt, ps);
+ return TRUE;
}
+
+ cleanup:
- mysql_free_result (mysql_res);
+ if (set)
+ g_object_unref (G_OBJECT(set));
+ if (used_set)
+ g_slist_free (used_set);
+ g_free (sql);
- return GDA_DATA_MODEL (recset);
+ return FALSE;
}
-static void
-mysql_get_constraints_form_create_table_line (GdaDataModelArray *recset, gchar *pos)
-{
- /* try to parse a line like this:
- * " CONSTRAINT `name` FOREIGN KEY (`fid1`,`fid2`) REFERENCES othertable(`id1`,`id2`)"
- */
- gchar *cname = 0, *start, *stop;
- GString *kname;
- gchar *tname = 0;
- GString *fname;
- GList *value_list;
- gchar *temp;
- GValue *tmpval;
-
- /* remove prefix spaces */
- while ( *pos==' ')
- pos++;
-
- /* "CONSTRAINT "? */
- if ( strncmp (pos, "CONSTRAINT ", 11) )
- return;
-
- pos += 11; /* strlen("CONSTRAINT ") */
-
- /* find the start of the constraint name.. it should be a ` char */
- if ( ! ( start = strchr (pos, '`') ) )
- return;
- /* we want the first character from the name */
- start++;
-
- /* find the ending constraint name.. it should be a ` char */
- if ( ! ( stop = strchr (start, '`') ) )
- return;
-
- /* allocate cname, and store the constraint name */
- cname = g_malloc ( stop - start + 1);
- g_strlcpy (cname, start, stop - start + 1);
-
- pos = stop + 1;
-
- /* remove spaces again */
- while ( *pos == ' ' )
- pos++;
-
- /* "FOREIGN KEY "? */
- if ( strncmp (pos, "FOREIGN KEY ", 12) )
- goto cname_out;
- /* this is a foreign key constraint */
- pos += 12; /* strlen("FOREIGN KEY ") */
-
- /* we should be able to locate a ( inside our string */
- if ( ! ( pos = strchr (pos, '(') ) )
- goto cname_out;
- pos++;
-
- /* we should now be at the character behind the ( */
-
- kname = g_string_new (NULL);
-
- while (1) {
- /* find all the entries.. they are in this format "`a`, `b`, `c`".
- * The list is terminated by a ) character */
- if ( ! ( start = strchr (pos, '`') ) )
- goto kname_out;
- start++;
- if ( ! ( stop = strchr (start, '`') ) )
- goto kname_out;
- if ( kname->len )
- g_string_append_c (kname, ',');
- g_string_append_len (kname, start, stop - start);
-
- pos = stop + 1;
-
- while ( *pos == ' ')
- pos++;
- if ( *pos == ',' )
- pos++;
- else /* if (*pos==')')*/
- break;
- }
- /* pass by the ) character.. but if we had an unexpected \0 character, don't crash */
- if (*pos)
- pos++;
-
- /* remove spaces again */
- while ( *pos == ' ' )
- pos++;
-
- /* we now expected the REFERENCES text */
- if ( strncmp (pos, "REFERENCES ", 11) )
- goto kname_out;
-
- pos += 11;
-
- /* and yeah... remove spaces */
- while ( *pos == ' ' )
- pos++;
-
- /* we should now hit the name of the foreign table. It is embedded inside ` characters */
- if ( ! ( start = strchr (pos, '`') ) )
- goto kname_out;
- start++;
-
- if ( ! ( stop = strchr (start, '`') ) )
- goto kname_out;
- /* store it in tname */
- tname = g_malloc ( stop - start + 1);
- g_strlcpy (tname, start, stop - start + 1);
-
- pos = stop + 1;
-
- /* we now should find a ( character */
- if ( ! ( start = strchr (pos, '(') ) )
- goto tname_out;
- pos = start + 1;
-
- fname = g_string_new (NULL);
-
- while (1) {
- /* and after this character we find a list like above with keys */
- if ( ! ( start = strchr (pos, '`') ) )
- goto kname_out;
- start++;
- if ( ! ( stop = strchr (start, '`') ) )
- goto kname_out;
- if (fname->len)
- g_string_append_c (fname, ',');
- g_string_append_len (fname, start, stop - start);
-
- pos = stop + 1;
- while ( *pos == ' ')
- pos++;
- if ( *pos == ',' )
- pos++;
- else /* if (*pos==')')*/
- break;
- }
- /* fill in the result into the result table */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), cname);
- value_list = g_list_append (NULL, tmpval);
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "FOREIGN_KEY");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), kname->str);
- value_list = g_list_append (value_list, tmpval);
+static GdaMysqlPStmt *
+prepare_stmt_simple (MysqlConnectionData *cdata,
+ const gchar *sql,
+ GError **error)
+{
+ GdaMysqlPStmt *ps = NULL;
+ g_return_val_if_fail (sql != NULL, NULL);
- temp = g_strdup_printf ("%s(%s)", tname, fname->str);
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), temp);
- value_list = g_list_append (value_list, tmpval);
+ if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
+ GdaConnectionEvent *event = _gda_mysql_make_error
+ (cdata->cnc, cdata->mysql, NULL);
+ ps = NULL;
+ } else {
+ ps = gda_mysql_pstmt_new (cdata->cnc, cdata->mysql, cdata->mysql_stmt);
+ _GDA_PSTMT(ps)->param_ids = NULL;
+ _GDA_PSTMT(ps)->sql = g_strdup (sql);
+ }
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
-
- g_string_free (fname, TRUE);
-tname_out:
- g_free (tname);
-kname_out:
- g_string_free (kname, TRUE);
-cname_out:
- g_free (cname);
+ return ps;
}
-static void
-mysql_get_constraints_from_create_table (GdaDataModelArray *recset, gchar *pos)
-{
- /* skip the first line. nothing of interrest there */
- if ((pos=strchr(pos, '\n')))
- pos++;
- else
- return;
- while (*pos)
- {
- gchar *next;
- if ((next = strchr (pos, '\n'))) {
- *next=0;
- next++;
- } else
- next = pos + strlen (pos);
- mysql_get_constraints_form_create_table_line (recset, pos);
- pos=next;
- }
-}
-static GdaDataModel *
-get_mysql_constraints (GdaConnection *cnc, GdaParameterList *params)
-{
- const gchar *table_name;
- GdaParameter *par;
- gchar *cmd_str;
- GdaDataModelArray *recset;
- gint rows, r;
- gint rc;
- MYSQL *mysql;
- MYSQL_RES *mysql_res;
- GString *pkey_fields = NULL;
- GValue *tmpval;
+/*
+ * Execute statement request
+ *
+ * Executes a statement. This method should do the following:
+ * - try to prepare the statement if not yet done
+ * - optionnally reset the prepared statement
+ * - bind the variables's values (which are in @params)
+ * - add a connection event to log the execution
+ * - execute the prepared statement
+ *
+ * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
+ * actual inserted row
+ */
+static GObject *
+gda_mysql_provider_statement_execute (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GdaStatement *stmt,
+ GdaSet *params,
+ GdaStatementModelUsage model_usage,
+ GType *col_types,
+ GdaSet **last_inserted_row,
+ guint *task_id,
+ GdaServerProviderAsyncCallback async_cb,
+ gpointer cb_data,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlPStmt *ps;
+ MysqlConnectionData *cdata;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (params != NULL, NULL);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return NULL;
- }
-
- /* get parameters sent by client */
- par = gda_parameter_list_find_param (params, "name");
- if (!par) {
- gda_connection_add_event_string (
- cnc,
- _("Table name is needed but none specified in parameter list"));
- return NULL;
- }
-
- table_name = g_value_get_string ((GValue *) gda_parameter_get_value (par));
- if (!table_name) {
- gda_connection_add_event_string (
- cnc,
- _("Table name is needed but none specified in parameter list"));
- return NULL;
- }
-
- /* create and initialize the recordset to be returned */
- recset = (GdaDataModelArray *) gda_data_model_array_new (gda_server_provider_get_schema_nb_columns (GDA_CONNECTION_SCHEMA_CONSTRAINTS));
- gda_server_provider_init_schema_model (GDA_DATA_MODEL (recset), GDA_CONNECTION_SCHEMA_CONSTRAINTS);
-
- /*
- * Obtaining list of columns
- */
- cmd_str = g_strdup_printf ("SHOW COLUMNS FROM %s", table_name);
- rc = gda_mysql_real_query_wrap (cnc, mysql, cmd_str, strlen (cmd_str));
- g_free (cmd_str);
- if (rc != 0) {
- gda_connection_add_event (cnc, gda_mysql_make_error (mysql));
- return NULL;
+ /* If asynchronous connection opening is not supported, then exit now */
+ if (async_cb) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+ _("Provider does not support asynchronous statement execution"));
+ return FALSE;
}
- mysql_res = mysql_store_result (mysql);
- rows = mysql_num_rows (mysql_res);
-
- for (r = 0; r < rows; r++) {
- GList *value_list = NULL;
- MYSQL_ROW mysql_row;
- gchar **arr;
-
- mysql_data_seek (mysql_res, r);
- mysql_row = mysql_fetch_row (mysql_res);
- if (!mysql_row) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
-
- /* treating ENUM and SET types into CHECK constraints */
- arr = g_strsplit ((const gchar *) mysql_row[1], "(", 0);
- if (arr) {
- gchar *str;
- if (!strcmp (arr[0], "enum")) {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "CHECK");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), mysql_row[0]);
- value_list = g_list_append (value_list, tmpval);
-
- str = g_strdup_printf ("IN %s", mysql_row[1]+4);
- g_value_take_string (tmpval = gda_value_new (G_TYPE_STRING), str);
- value_list = g_list_append (value_list, tmpval);
-
- value_list = g_list_append (value_list, gda_value_new_null());
- }
- else if (!strcmp (arr[0], "set")) {
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "CHECK");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), mysql_row[0]);
- value_list = g_list_append (value_list, tmpval);
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
- str = g_strdup_printf ("SETOF %s", mysql_row[1]+3);
- g_value_take_string (tmpval = gda_value_new (G_TYPE_STRING), str);
- value_list = g_list_append (value_list, tmpval);
- value_list = g_list_append (value_list, gda_value_new_null());
- }
- g_strfreev (arr);
- }
- if (value_list) {
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
+ /* get/create new prepared statement */
+ ps = gda_connection_get_prepared_statement (cnc, stmt);
+ if (!ps) {
+ if (!gda_mysql_provider_statement_prepare (provider, cnc, stmt, NULL)) {
+ /* this case can appear for example if some variables are used in places
+ * where the C API cannot allow them (for example if the variable is the table name
+ * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
+ * and use that SQL instead of @stmt to create another GdaMysqlPStmt object.
+ */
+ // TO_IMPLEMENT;
+
+ gchar *sql = gda_mysql_provider_statement_to_sql
+ (provider, cnc, stmt, params, 0, NULL, error);
+ if (!sql)
+ return NULL;
+ ps = prepare_stmt_simple (cdata, sql, error);
+ if (!ps)
+ return NULL;
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- value_list = NULL;
- }
-
- /* treating PRIMARY key constraints */
- if (!strcmp (mysql_row[3], "PRI")) {
- if (!pkey_fields)
- pkey_fields = g_string_new (mysql_row[0]);
- else {
- g_string_append_c (pkey_fields, ',');
- g_string_append (pkey_fields, mysql_row[0]);
- }
}
+ else
+ ps = gda_connection_get_prepared_statement (cnc, stmt);
}
+ g_assert (ps);
- /* creating the PKEY entry if necessary */
- if (pkey_fields) {
- GList *value_list = NULL;
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "PRIMARY_KEY");
- value_list = g_list_append (value_list, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), pkey_fields->str);
- value_list = g_list_append (value_list, tmpval);
-
- value_list = g_list_append (value_list, gda_value_new_null());
- value_list = g_list_append (value_list, gda_value_new_null());
- g_string_free (pkey_fields, TRUE);
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- }
-
- mysql_free_result (mysql_res);
+ /* optionnally reset the prepared statement if required by the API */
+ // TO_IMPLEMENT;
+
+ /* bind statement's parameters */
+ GSList *list;
+ GdaConnectionEvent *event = NULL;
+ int i;
+
+ gint nb_params = g_slist_length (_GDA_PSTMT (ps)->param_ids);
+ char **param_values = g_new0 (char *, nb_params + 1);
+ int *param_lengths = g_new0 (int, nb_params + 1);
+ int *param_formats = g_new0 (int, nb_params + 1);
+ g_print ("NB=%d\n", nb_params);
+
+ for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
+ const gchar *pname = (gchar *) list->data;
+ GdaHolder *h;
- /*
- * taking care of foreign keys if possible
- */
- if (atoi (mysql->server_version) >= 5) {
- gchar *current_cname = NULL;
- GString *ref_string = NULL;
- GString *src_string = NULL;
- GList *value_list = NULL;
- cmd_str = g_strdup_printf ("SELECT CONSTRAINT_NAME, COLUMN_NAME, ORDINAL_POSITION, REFERENCED_TABLE_SCHEMA, "
- "REFERENCED_TABLE_NAME, REFERENCED_COLUMN_NAME "
- "FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE "
- "WHERE TABLE_NAME = '%s' AND TABLE_SCHEMA = DATABASE() AND "
- "CONSTRAINT_NAME != 'PRIMARY' AND REFERENCED_TABLE_NAME IS NOT NULL "
- "ORDER BY CONSTRAINT_NAME, ORDINAL_POSITION",
- table_name);
- rc = gda_mysql_real_query_wrap (cnc, mysql, cmd_str, strlen (cmd_str));
- g_free (cmd_str);
- if (rc != 0) {
- gda_connection_add_event (cnc, gda_mysql_make_error (mysql));
- return NULL;
+ g_print ("PNAME=%s\n", pname);
+ //
+ /* find requested parameter */
+ if (!params) {
+ event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+ _("Missing parameter(s) to execute query"));
+ break;
}
- mysql_res = mysql_store_result (mysql);
- rows = mysql_num_rows (mysql_res);
-
- for (r = 0; r < rows; r++) {
- MYSQL_ROW mysql_row;
-
- mysql_data_seek (mysql_res, r);
- mysql_row = mysql_fetch_row (mysql_res);
- if (!mysql_row) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
-
- return NULL;
- }
-
-
- if ((! current_cname) || strcmp (current_cname, mysql_row[0])) {
- /* new constraint */
- if (value_list) {
- /* complete and store current row */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), src_string->str);
- value_list = g_list_append (value_list, tmpval);
- g_string_free (src_string, TRUE);
-
- g_string_append_c (ref_string, ')');
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), ref_string->str);
- value_list = g_list_append (value_list, tmpval);
- g_string_free (ref_string, TRUE);
-
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- }
- if (current_cname)
- g_free (current_cname);
-
- /* prepare new constraint */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), mysql_row[0]);
- value_list = g_list_append (NULL, tmpval);
-
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), "FOREIGN_KEY");
- value_list = g_list_append (value_list, tmpval);
-
- src_string = g_string_new (mysql_row[1]);
-
- ref_string = g_string_new (mysql_row[4]);
- g_string_append_c (ref_string, '(');
- g_string_append (ref_string, mysql_row[5]);
- current_cname = g_strdup (mysql_row[0]);
- }
- else {
- g_string_append_c (ref_string, ',');
- g_string_append (ref_string, mysql_row[5]);
- g_string_append_c (src_string, ',');
- g_string_append (src_string, mysql_row[1]);
+ h = gda_set_get_holder (params, pname);
+ if (!h) {
+ gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
+ if (tmp) {
+ h = gda_set_get_holder (params, tmp);
+ g_free (tmp);
}
}
-
- if (value_list) {
- /* complete and store current row */
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), src_string->str);
- value_list = g_list_append (value_list, tmpval);
- g_string_free (src_string, TRUE);
-
- g_string_append_c (ref_string, ')');
- g_value_set_string (tmpval = gda_value_new (G_TYPE_STRING), ref_string->str);
- value_list = g_list_append (value_list, tmpval);
- g_string_free (ref_string, TRUE);
-
- value_list = g_list_append (value_list, gda_value_new_null ());
-
- gda_data_model_append_values (GDA_DATA_MODEL (recset),
- (const GList *) value_list, NULL);
-
- g_list_foreach (value_list, (GFunc) gda_value_free, NULL);
- g_list_free (value_list);
- }
- if (current_cname)
- g_free(current_cname);
- mysql_free_result (mysql_res);
- } else {
- gchar *temp;
- MYSQL_ROW mysql_row;
- cmd_str = g_strdup_printf ("SHOW CREATE TABLE %s",
- table_name);
- rc = gda_mysql_real_query_wrap (cnc, mysql, cmd_str, strlen (cmd_str));
- g_free (cmd_str);
- if (rc != 0) {
- gda_connection_add_event (cnc, gda_mysql_make_error (mysql));
- return NULL;
+ if (!h) {
+ gchar *str;
+ str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
+ event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, str);
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, str);
+ g_free (str);
+ break;
}
- mysql_res = mysql_store_result (mysql);
-
- mysql_row = mysql_fetch_row (mysql_res);
- if (!mysql_row) {
- mysql_free_result (mysql_res);
- g_object_unref (G_OBJECT (recset));
- return NULL;
- }
- temp = g_strdup ( mysql_row[1] );
- mysql_get_constraints_from_create_table (recset, mysql_row[1]);
- g_free (temp);
- mysql_free_result (mysql_res);
+ /* actual binding using the C API, for parameter at position @i */
+ const GValue *value = gda_holder_get_value (h);
+ TO_IMPLEMENT;
}
-
- return GDA_DATA_MODEL (recset);
-}
-
-/* get_schema handler for the GdaMysqlProvider class */
-static GdaDataModel *
-gda_mysql_provider_get_schema (GdaServerProvider *provider,
- GdaConnection *cnc,
- GdaConnectionSchema schema,
- GdaParameterList *params)
-{
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- if (cnc)
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- else
+
+ if (event) {
+ gda_connection_add_event (cnc, event);
return NULL;
-
- switch (schema) {
- case GDA_CONNECTION_SCHEMA_AGGREGATES :
- return get_mysql_aggregates (cnc, params);
- case GDA_CONNECTION_SCHEMA_DATABASES :
- return get_mysql_databases (cnc, params);
- case GDA_CONNECTION_SCHEMA_FIELDS :
- return get_table_fields (cnc, params);
- case GDA_CONNECTION_SCHEMA_TABLES :
- return get_mysql_tables (cnc, params);
- case GDA_CONNECTION_SCHEMA_VIEWS:
- return get_mysql_views (cnc, params);
- case GDA_CONNECTION_SCHEMA_TYPES :
- return get_mysql_types (cnc, params);
- case GDA_CONNECTION_SCHEMA_PROCEDURES:
- return get_mysql_procedures (cnc, params);
- case GDA_CONNECTION_SCHEMA_CONSTRAINTS:
- return get_mysql_constraints (cnc, params);
- default : break;
}
+
+ /* add a connection event for the execution */
+ event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+ gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
+ gda_connection_add_event (cnc, event);
- return NULL;
-}
+
+ GObject *return_value = NULL;
+ if (mysql_stmt_execute (cdata->mysql_stmt)) {
+ event = _gda_mysql_make_error (cnc, cdata->mysql, error);
+ } else {
+ //
+ /* execute prepared statement using C API depending on its kind */
+ if (!g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SELECT", 6) ||
+ !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "SHOW", 4) ||
+ !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "DESCRIBE", 8) ||
+ !g_ascii_strncasecmp (_GDA_PSTMT (ps)->sql, "EXPLAIN", 7)) {
+
+ if (mysql_stmt_store_result (cdata->mysql_stmt)) {
+ _gda_mysql_make_error (cnc, cdata->mysql, error);
+ } else {
+ GdaDataModelAccessFlags flags;
-gchar *
-gda_mysql_provider_value_to_sql_string (GdaServerProvider *provider, /* we dont actually use this!*/
- GdaConnection *cnc,
- GValue *from)
-{
- gchar *val_str;
- gchar *ret;
- GType type;
+ if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
+ flags = GDA_DATA_MODEL_ACCESS_RANDOM;
+ else
+ flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- g_return_val_if_fail (from != NULL, FALSE);
-
- val_str = gda_value_stringify (from);
- if (!val_str)
- return NULL;
+ return_value = (GObject *) gda_mysql_recordset_new (cnc, ps, flags, col_types);
+ gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
+ }
+
+ } else {
+ my_ulonglong affected_rows = (my_ulonglong)~0;
- type = G_VALUE_TYPE (from);
- if ((type == G_TYPE_INT64) ||
- (type == G_TYPE_DOUBLE) ||
- (type == G_TYPE_INT) ||
- (type == GDA_TYPE_NUMERIC) ||
- (type == G_TYPE_FLOAT) ||
- (type == GDA_TYPE_SHORT) ||
- (type == G_TYPE_CHAR))
- ret = g_strdup (val_str);
- else if ((type == GDA_TYPE_TIMESTAMP) ||
- (type == G_TYPE_DATE) ||
- (type == GDA_TYPE_TIME))
- ret = g_strdup_printf ("\"%s\"", val_str);
- else {
- MYSQL *mysql;
- char *quoted;
- mysql = g_object_get_data (G_OBJECT (cnc), OBJECT_DATA_MYSQL_HANDLE);
-
- if (!mysql) {
- gda_connection_add_event_string (cnc, _("Invalid MySQL handle"));
- return NULL;
+ // TO_IMPLEMENT;
+ /* Create a #GdaSet containing "IMPACTED_ROWS" */
+ /* Create GdaConnectionEvent notice with the type of command and impacted rows */
+
+
+ affected_rows = mysql_stmt_affected_rows (cdata->mysql_stmt);
+ if (affected_rows >= 0) {
+ GdaConnectionEvent *event;
+ gchar *str;
+ event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+ str = g_strdup_printf ("%lu", affected_rows);
+ gda_connection_event_set_description (event, str);
+ g_free (str);
+
+ return_value = (GObject *) gda_set_new_inline
+ (1, "IMPACTED_ROWS", G_TYPE_INT, (int) affected_rows);
+
+ gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
+ } else {
+ return_value = (GObject *) gda_data_model_array_new (0);
+ }
+
}
- quoted = ret = g_malloc(strlen(val_str) * 2 + 3);
- *quoted++ = '\'';
- quoted += mysql_real_escape_string (
- mysql, quoted, val_str, strlen (val_str));
- *quoted++ = '\'';
- *quoted++ = '\0';
- ret = g_realloc(ret, quoted - ret + 1);
}
+ return return_value;
- g_free (val_str);
-
- return ret;
}
-static GdaDataHandler *
-gda_mysql_provider_get_data_handler (GdaServerProvider *provider,
- GdaConnection *cnc,
- GType type, const gchar *dbms_type)
+/*
+ * Free connection's specific data
+ */
+static void
+gda_mysql_free_cnc_data (MysqlConnectionData *cdata)
{
- GdaDataHandler *dh = NULL;
+ g_print ("*** %s\n", __func__);
+ if (!cdata)
+ return;
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), FALSE);
- if (cnc)
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ // TO_IMPLEMENT;
- if ((type == G_TYPE_INT64) ||
- (type == G_TYPE_UINT64) ||
- (type == G_TYPE_DOUBLE) ||
- (type == G_TYPE_INT) ||
- (type == GDA_TYPE_NUMERIC) ||
- (type == G_TYPE_FLOAT) ||
- (type == GDA_TYPE_SHORT) ||
- (type == GDA_TYPE_USHORT) ||
- (type == G_TYPE_CHAR) ||
- (type == G_TYPE_UCHAR) ||
- (type == G_TYPE_UINT)) {
- dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
- if (!dh) {
- dh = gda_handler_numerical_new ();
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT64, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT64, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DOUBLE, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_INT, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_NUMERIC, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_FLOAT, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_SHORT, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_USHORT, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_CHAR, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UCHAR, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_UINT, NULL);
- g_object_unref (dh);
- }
- }
- else if (type == GDA_TYPE_BINARY) {
- dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
- if (!dh) {
- dh = gda_handler_bin_new ();
- if (dh) {
- gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL);
- g_object_unref (dh);
- }
- }
+ if (cdata->mysql) {
+ mysql_close (cdata->mysql);
+ cdata->mysql = NULL;
}
- else if (type == G_TYPE_BOOLEAN) {
- dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
- if (!dh) {
- dh = gda_handler_boolean_new ();
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_BOOLEAN, NULL);
- g_object_unref (dh);
- }
- }
- else if ((type == G_TYPE_DATE) ||
- (type == GDA_TYPE_TIME) ||
- (type == GDA_TYPE_TIMESTAMP)) {
- dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
- if (!dh) {
- dh = gda_handler_time_new ();
- gda_handler_time_set_sql_spec (GDA_HANDLER_TIME (dh),
- G_DATE_YEAR, G_DATE_MONTH, G_DATE_DAY,
- '-', FALSE);
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
- gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
- g_object_unref (dh);
- }
- }
- else if (type == G_TYPE_STRING) {
- dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
- if (!dh) {
- dh = gda_handler_string_new ();
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_STRING, NULL);
- g_object_unref (dh);
- }
+ if (cdata->mysql_stmt) {
+ mysql_stmt_close (cdata->mysql_stmt);
+ cdata->mysql_stmt = NULL;
}
- else if (type == G_TYPE_ULONG) {
- dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
- if (!dh) {
- dh = gda_handler_type_new ();
- gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_ULONG, NULL);
- g_object_unref (dh);
- }
- }
- else {
- /* special case: we take into account the dbms_type argument */
- if (dbms_type)
- TO_IMPLEMENT;
- }
-
- return dh;
-}
-
-static const gchar*
-gda_mysql_provider_get_default_dbms_type (GdaServerProvider *provider,
- GdaConnection *cnc,
- GType type)
-{
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
-
- if (type == G_TYPE_INT64)
- return "bigint";
- if (type == G_TYPE_UINT64)
- return "bigint unsigned";
- if (type == GDA_TYPE_BINARY)
- return "longtext";
- if (type == G_TYPE_BOOLEAN)
- return "bool";
- if (type == G_TYPE_DATE)
- return "date";
- if (type == G_TYPE_DOUBLE)
- return "double";
- if (type == GDA_TYPE_GEOMETRIC_POINT)
- return "varchar";
- if (type == G_TYPE_OBJECT)
- return "text";
- if (type == G_TYPE_INT)
- return "int";
- if (type == GDA_TYPE_LIST)
- return "text";
- if (type == GDA_TYPE_NUMERIC)
- return "decimal";
- if (type == G_TYPE_FLOAT)
- return "float";
- if (type == GDA_TYPE_SHORT)
- return "smallint";
- if (type == GDA_TYPE_USHORT)
- return "smallint unsigned";
- if (type == G_TYPE_STRING)
- return "varchar";
- if (type == GDA_TYPE_TIME)
- return "time";
- if (type == GDA_TYPE_TIMESTAMP)
- return "timestamp";
- if (type == G_TYPE_CHAR)
- return "tinyint";
- if (type == G_TYPE_UCHAR)
- return "tinyint unsigned";
- if (type == G_TYPE_ULONG)
- return "bigint unsigned";
- if (type == G_TYPE_UINT)
- return "int unsigned";
- if (type == G_TYPE_INVALID)
- return "text";
- return "text";
-}
-
-static GdaSqlParser *
-gda_mysql_provider_create_parser (GdaServerProvider *provider, GdaConnection *cnc)
-{
- g_return_val_if_fail (GDA_IS_SERVER_PROVIDER (provider), NULL);
- return (GdaSqlParser*) g_object_new (GDA_TYPE_SQL_PARSER, "tokenizer-flavour",
- GDA_SQL_PARSER_FLAVOUR_MYSQL, NULL);
+ g_free (cdata->version);
+ cdata->version_long = -1;
+
+ g_free (cdata);
}
Modified: trunk/providers/mysql/gda-mysql-provider.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-provider.h (original)
+++ trunk/providers/mysql/gda-mysql-provider.h Sun Apr 6 17:06:43 2008
@@ -1,10 +1,8 @@
-/* GDA MySQL provider
- * Copyright (C) 1998-2005 The GNOME Foundation.
+/* GDA mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
+ * Carlos Savoretti <csavoretti gmail com>
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -22,37 +20,32 @@
* Boston, MA 02111-1307, USA.
*/
-#if !defined(__gda_mysql_provider_h__)
-# define __gda_mysql_provider_h__
+#ifndef __GDA_MYSQL_PROVIDER_H__
+#define __GDA_MYSQL_PROVIDER_H__
#include <libgda/gda-server-provider.h>
-G_BEGIN_DECLS
-
#define GDA_TYPE_MYSQL_PROVIDER (gda_mysql_provider_get_type())
#define GDA_MYSQL_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_MYSQL_PROVIDER, GdaMysqlProvider))
#define GDA_MYSQL_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_MYSQL_PROVIDER, GdaMysqlProviderClass))
#define GDA_IS_MYSQL_PROVIDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_MYSQL_PROVIDER))
#define GDA_IS_MYSQL_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_MYSQL_PROVIDER))
-#define OBJECT_DATA_MYSQL_HANDLE "GDA_Mysql_MysqlHandle"
-
typedef struct _GdaMysqlProvider GdaMysqlProvider;
typedef struct _GdaMysqlProviderClass GdaMysqlProviderClass;
struct _GdaMysqlProvider {
- GdaServerProvider provider;
+ GdaServerProvider provider;
};
struct _GdaMysqlProviderClass {
GdaServerProviderClass parent_class;
};
-GType gda_mysql_provider_get_type (void) G_GNUC_CONST;
-GdaServerProvider *gda_mysql_provider_new (void);
-gchar *gda_mysql_provider_value_to_sql_string (GdaServerProvider *provider,
- GdaConnection *cnc,
- GValue *from);
+G_BEGIN_DECLS
+
+GType gda_mysql_provider_get_type (void) G_GNUC_CONST;
+
G_END_DECLS
#endif
Added: trunk/providers/mysql/gda-mysql-pstmt.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-pstmt.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,116 @@
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * TO_ADD: your name and email
+ *
+ * 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 "gda-mysql-pstmt.h"
+
+static void
+gda_mysql_pstmt_class_init (GdaMysqlPStmtClass *klass);
+static void
+gda_mysql_pstmt_init (GdaMysqlPStmt *pstmt,
+ GdaMysqlPStmtClass *klass);
+static void
+gda_mysql_pstmt_finalize (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+/**
+ * gda_mysql_pstmt_get_type
+ *
+ * Returns: the #GType of GdaMysqlPStmt.
+ */
+GType
+gda_mysql_pstmt_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdaMysqlPStmtClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_mysql_pstmt_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaMysqlPStmt),
+ 0,
+ (GInstanceInitFunc) gda_mysql_pstmt_init
+ };
+
+ type = g_type_register_static (GDA_TYPE_PSTMT, "GdaMysqlPStmt", &info, 0);
+ }
+ return type;
+}
+
+static void
+gda_mysql_pstmt_class_init (GdaMysqlPStmtClass *klass)
+{
+ g_print ("*** %s\n", __func__);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ parent_class = g_type_class_peek_parent (klass);
+
+ /* virtual functions */
+ object_class->finalize = gda_mysql_pstmt_finalize;
+}
+
+static void
+gda_mysql_pstmt_init (GdaMysqlPStmt *pstmt,
+ GdaMysqlPStmtClass *klass)
+{
+ g_print ("*** %s\n", __func__);
+ g_return_if_fail (GDA_IS_PSTMT (pstmt));
+
+ /* initialize specific parts of @pstmt */
+ // TO_IMPLEMENT;
+}
+
+static void
+gda_mysql_pstmt_finalize (GObject *object)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlPStmt *pstmt = (GdaMysqlPStmt *) object;
+
+ g_return_if_fail (GDA_IS_PSTMT (pstmt));
+
+ /* free memory */
+ // TO_IMPLEMENT; /* free some specific parts of @pstmt */
+
+ /* chain to parent class */
+ parent_class->finalize (object);
+}
+
+
+GdaMysqlPStmt *
+gda_mysql_pstmt_new (GdaConnection *cnc,
+ MYSQL *mysql,
+ MYSQL_STMT *mysql_stmt)
+{
+ GdaMysqlPStmt *ps = (GdaMysqlPStmt *) g_object_new (GDA_TYPE_MYSQL_PSTMT,
+ NULL);
+ ps->cnc = cnc;
+ ps->mysql = mysql;
+ ps->mysql_stmt = mysql_stmt;
+
+ return ps;
+}
+
Added: trunk/providers/mysql/gda-mysql-pstmt.h
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-pstmt.h Sun Apr 6 17:06:43 2008
@@ -0,0 +1,65 @@
+/* GDA Mysql library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Carlos Savoretti <csavoretti gmail com>
+ *
+ * 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_MYSQL_PSTMT_H__
+#define __GDA_MYSQL_PSTMT_H__
+
+#include <providers-support/gda-pstmt.h>
+#include "gda-mysql.h"
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_MYSQL_PSTMT (gda_mysql_pstmt_get_type())
+#define GDA_MYSQL_PSTMT(obj) (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_MYSQL_PSTMT, GdaMysqlPStmt))
+#define GDA_MYSQL_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_MYSQL_PSTMT, GdaMysqlPStmtClass))
+#define GDA_IS_MYSQL_PSTMT(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_MYSQL_PSTMT))
+#define GDA_IS_MYSQL_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_MYSQL_PSTMT))
+
+typedef struct _GdaMysqlPStmt GdaMysqlPStmt;
+typedef struct _GdaMysqlPStmtClass GdaMysqlPStmtClass;
+
+struct _GdaMysqlPStmt {
+ GdaPStmt object;
+
+ GdaConnection *cnc;
+ MYSQL *mysql;
+ MYSQL_STMT *mysql_stmt;
+
+};
+
+struct _GdaMysqlPStmtClass {
+ GdaPStmtClass parent_class;
+};
+
+GType
+gda_mysql_pstmt_get_type (void) G_GNUC_CONST;
+/* TO_ADD: helper function to create a GdaMysqlPStmt such as gda_mysql_pstmt_new() with some specific arguments */
+
+GdaMysqlPStmt *
+gda_mysql_pstmt_new (GdaConnection *cnc,
+ MYSQL *mysql,
+ MYSQL_STMT *mysql_stmt);
+
+
+G_END_DECLS
+
+#endif
Modified: trunk/providers/mysql/gda-mysql-recordset.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.c (original)
+++ trunk/providers/mysql/gda-mysql-recordset.c Sun Apr 6 17:06:43 2008
@@ -1,11 +1,8 @@
-/* GDA MySQL provider
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
- * Bas Driessen <bas driessen xobas com>
+ * Carlos Savoretti <csavoretti gmail com>
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -23,911 +20,686 @@
* Boston, MA 02111-1307, USA.
*/
-#include <glib/gi18n-lib.h>
-#include <stdlib.h>
+#include <stdarg.h>
#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-util.h>
+#include <libgda/gda-connection-private.h>
#include "gda-mysql.h"
#include "gda-mysql-recordset.h"
-#include <libgda/gda-data-model-private.h>
+#include "gda-mysql-provider.h"
-#define PARENT_TYPE GDA_TYPE_DATA_MODEL_ARRAY
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#endif
-struct _GdaMysqlRecordsetPrivate {
- MYSQL_RES *mysql_res;
- gint mysql_res_rows;
- GdaConnection *cnc;
- gint ncolumns;
- gchar *table_name;
- gboolean row_sync;
-};
-static void gda_mysql_recordset_class_init (GdaMysqlRecordsetClass *klass);
-static void gda_mysql_recordset_init (GdaMysqlRecordset *recset,
- GdaMysqlRecordsetClass *klass);
-static void gda_mysql_recordset_finalize (GObject *object);
-
-static gint gda_mysql_recordset_get_n_rows (GdaDataModelRow *model);
-static GdaRow *gda_mysql_recordset_get_row (GdaDataModelRow *model,
- gint row, GError **error);
-static const GValue *gda_mysql_recordset_get_value_at (GdaDataModelRow *model, gint col, gint row);
-static gboolean gda_mysql_recordset_is_updatable (GdaDataModelRow *model);
-static gboolean gda_mysql_recordset_append_row (GdaDataModelRow *model, GdaRow *row, GError **error);
-static gboolean gda_mysql_recordset_remove_row (GdaDataModelRow *model, GdaRow *row, GError **error);
-static gboolean gda_mysql_recordset_update_row (GdaDataModelRow *model, GdaRow *row, GError **error);
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
-static GObjectClass *parent_class = NULL;
-/*
- * Private functions
- */
+enum
+{
+ PROP_0,
+ PROP_CHUNK_SIZE,
+ PROP_CHUNKS_READ
+};
+
-/*
- * Object init and finalize
- */
static void
-gda_mysql_recordset_class_init (GdaMysqlRecordsetClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
- GdaDataModelRowClass *model_class = GDA_DATA_MODEL_ROW_CLASS (klass);
+gda_mysql_recordset_class_init (GdaMysqlRecordsetClass *klass);
+static void
+gda_mysql_recordset_init (GdaMysqlRecordset *recset,
+ GdaMysqlRecordsetClass *klass);
+static void
+gda_mysql_recordset_dispose (GObject *object);
- parent_class = g_type_class_peek_parent (klass);
+/* virtual methods */
+static gint
+gda_mysql_recordset_fetch_nb_rows (GdaPModel *model);
+static gboolean
+gda_mysql_recordset_fetch_random (GdaPModel *model,
+ GdaPRow **prow,
+ gint rownum,
+ GError **error);
+static gboolean
+gda_mysql_recordset_fetch_next (GdaPModel *model,
+ GdaPRow **prow,
+ gint rownum,
+ GError **error);
+static gboolean
+gda_mysql_recordset_fetch_prev (GdaPModel *model,
+ GdaPRow **prow,
+ gint rownum,
+ GError **error);
+static gboolean
+gda_mysql_recordset_fetch_at (GdaPModel *model,
+ GdaPRow **prow,
+ gint rownum,
+ GError **error);
- object_class->finalize = gda_mysql_recordset_finalize;
- model_class->get_n_rows = gda_mysql_recordset_get_n_rows;
- model_class->get_row = gda_mysql_recordset_get_row;
- model_class->get_value_at = gda_mysql_recordset_get_value_at;
- model_class->is_updatable = gda_mysql_recordset_is_updatable;
- model_class->append_row = gda_mysql_recordset_append_row;
- model_class->remove_row = gda_mysql_recordset_remove_row;
- model_class->update_row = gda_mysql_recordset_update_row;
-}
+struct _GdaMysqlRecordsetPrivate {
+ GdaConnection *cnc;
+ /* TO_ADD: specific information */
+
+ MYSQL_STMT *mysql_stmt;
+ MYSQL_BIND *mysql_bind; /* Array to bind columns in the result set. */
+
+ gint chunk_size; /* Number of rows to fetch at a time when iterating forward/backward. */
+ gint chunks_read; /* Number of times that we've iterated forward/backward. */
+
+};
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and finalize
+ */
static void
-gda_mysql_recordset_init (GdaMysqlRecordset *recset, GdaMysqlRecordsetClass *klass)
+gda_mysql_recordset_init (GdaMysqlRecordset *recset,
+ GdaMysqlRecordsetClass *klass)
{
+ g_print ("*** %s\n", __func__);
g_return_if_fail (GDA_IS_MYSQL_RECORDSET (recset));
-
recset->priv = g_new0 (GdaMysqlRecordsetPrivate, 1);
+ recset->priv->cnc = NULL;
+
+ /* initialize specific information */
+ // TO_IMPLEMENT;
+
+ recset->priv->chunk_size = 10;
+ recset->priv->chunks_read = 0;
+
}
+
static void
-gda_mysql_recordset_finalize (GObject *object)
+gda_mysql_recordset_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) object;
-
- g_return_if_fail (GDA_IS_MYSQL_RECORDSET (recset));
+ GdaMysqlRecordset *record_set;
- if (recset->priv->mysql_res != NULL) {
- mysql_free_result (recset->priv->mysql_res);
- recset->priv->mysql_res = NULL;
- }
-
- g_free (recset->priv->table_name);
- recset->priv->table_name = NULL;
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDA_IS_MYSQL_RECORDSET(object));
+ g_return_if_fail (GDA_MYSQL_RECORDSET(object)->priv != NULL);
- g_free (recset->priv);
- recset->priv = NULL;
+ record_set = GDA_MYSQL_RECORDSET(object);
- parent_class->finalize (object);
+ switch (param_id) {
+ case PROP_CHUNK_SIZE:
+ record_set->priv->chunk_size = g_value_get_int (value);
+ break;
+ case PROP_CHUNKS_READ:
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ }
}
static void
-fill_gda_value (GValue *gda_value, enum enum_field_types type, gchar *value,
- unsigned long length, gboolean is_unsigned)
+gda_mysql_recordset_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
{
- if (!value) {
- gda_value_set_null (gda_value);
- return;
- }
+ GdaMysqlRecordset *record_set;
- switch (type) {
- case FIELD_TYPE_DECIMAL :
- case FIELD_TYPE_DOUBLE :
-#if NDB_VERSION_MAJOR >= 5
- case FIELD_TYPE_NEWDECIMAL :
-#endif
- gda_value_reset_with_type (gda_value, G_TYPE_DOUBLE);
- g_value_set_double (gda_value, atof (value));
- break;
- case FIELD_TYPE_FLOAT :
- gda_value_reset_with_type (gda_value, G_TYPE_FLOAT);
- g_value_set_float (gda_value, atof (value));
- break;
- case FIELD_TYPE_LONG :
- if (is_unsigned) {
- gda_value_reset_with_type (gda_value, G_TYPE_UINT);
- g_value_set_uint (gda_value, strtoul (value, NULL, 0));
- break;
- }
- case FIELD_TYPE_YEAR :
- gda_value_reset_with_type (gda_value, G_TYPE_INT);
- g_value_set_int (gda_value, atol (value));
- break;
- case FIELD_TYPE_LONGLONG :
- case FIELD_TYPE_INT24 :
- if (is_unsigned) {
- gda_value_reset_with_type (gda_value, G_TYPE_UINT64);
- g_value_set_uint64 (gda_value, strtoull (value, NULL, 0));
- } else {
- gda_value_reset_with_type (gda_value, G_TYPE_INT64);
- g_value_set_int64 (gda_value, atoll (value));
- }
- break;
- case FIELD_TYPE_SHORT :
- if (is_unsigned) {
- gda_value_reset_with_type (gda_value, GDA_TYPE_USHORT);
- gda_value_set_ushort (gda_value, atoi (value));
- } else {
- gda_value_reset_with_type (gda_value, GDA_TYPE_SHORT);
- gda_value_set_short (gda_value, atoi (value));
- }
- break;
- case FIELD_TYPE_TINY :
- if (is_unsigned) {
- gda_value_reset_with_type (gda_value, G_TYPE_UCHAR);
- g_value_set_uchar (gda_value, atoi (value));
- } else {
- gda_value_reset_with_type (gda_value, G_TYPE_CHAR);
- g_value_set_char (gda_value, atoi (value));
- }
- break;
- case FIELD_TYPE_TINY_BLOB :
- case FIELD_TYPE_MEDIUM_BLOB :
- case FIELD_TYPE_LONG_BLOB :
- case FIELD_TYPE_BLOB : {
- GdaBinary bin;
- bin.data = value;
- bin.binary_length = length;
- gda_value_reset_with_type (gda_value, GDA_TYPE_BINARY);
- gda_value_set_binary (gda_value, &bin);
- break;
- }
- case FIELD_TYPE_VAR_STRING :
- case FIELD_TYPE_STRING :
- /* FIXME: we might get "[VAR]CHAR(20) BINARY" type with \0 inside
- We should check for BINARY flag and treat it like a BLOB
- */
- gda_value_reset_with_type (gda_value, G_TYPE_STRING);
- g_value_set_string (gda_value, value);
- break;
- case FIELD_TYPE_DATE :
- gda_value_set_from_string (gda_value, value, G_TYPE_DATE);
- break;
- case FIELD_TYPE_TIME :
- gda_value_set_from_string (gda_value, value, GDA_TYPE_TIME);
- break;
- case FIELD_TYPE_TIMESTAMP :
- case FIELD_TYPE_DATETIME :
- gda_value_set_from_string (gda_value, value, GDA_TYPE_TIMESTAMP);
- break;
- case FIELD_TYPE_NULL :
- gda_value_set_null (gda_value);
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDA_IS_MYSQL_RECORDSET(object));
+ g_return_if_fail (GDA_MYSQL_RECORDSET(object)->priv != NULL);
+
+ record_set = GDA_MYSQL_RECORDSET(object);
+
+ switch (param_id) {
+ case PROP_CHUNK_SIZE:
+ g_value_set_int (value, record_set->priv->chunk_size);
break;
- case FIELD_TYPE_NEWDATE :
- case FIELD_TYPE_ENUM :
- case FIELD_TYPE_SET : /* FIXME */
- gda_value_reset_with_type (gda_value, G_TYPE_STRING);
- g_value_set_string (gda_value, value);
+ case PROP_CHUNKS_READ:
+ g_value_set_int (value, record_set->priv->chunks_read);
break;
- default :
- g_printerr ("Unknown MySQL datatype. This is fishy, but continuing anyway.\n");
- g_value_set_string (gda_value, value);
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
}
}
-static GdaRow *
-fetch_row (GdaMysqlRecordset *recset, gulong rownum)
+static void
+gda_mysql_recordset_class_init (GdaMysqlRecordsetClass *klass)
{
- GdaRow *row;
- gint field_count;
- gint row_count;
- gint i;
- MYSQL_FIELD *mysql_fields;
- MYSQL_ROW mysql_row;
- unsigned long *mysql_lengths;
-
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), NULL);
- g_return_val_if_fail (recset->priv != NULL, 0);
+ g_print ("*** %s\n", __func__);
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GdaPModelClass *pmodel_class = GDA_PMODEL_CLASS (klass);
- if (!recset->priv->mysql_res) {
- gda_connection_add_event_string (recset->priv->cnc, _("Invalid MySQL handle"));
- return NULL;
- }
+ parent_class = g_type_class_peek_parent (klass);
- /* move to the corresponding row */
- row_count = mysql_num_rows (recset->priv->mysql_res);
- if (row_count == 0)
- return NULL;
- field_count = mysql_num_fields (recset->priv->mysql_res);
+ object_class->dispose = gda_mysql_recordset_dispose;
+ pmodel_class->fetch_nb_rows = gda_mysql_recordset_fetch_nb_rows;
+ pmodel_class->fetch_random = gda_mysql_recordset_fetch_random;
+
+ pmodel_class->fetch_next = gda_mysql_recordset_fetch_next;
+ pmodel_class->fetch_prev = gda_mysql_recordset_fetch_prev;
+ pmodel_class->fetch_at = gda_mysql_recordset_fetch_at;
+
+ /* Properties. */
+ object_class->set_property = gda_mysql_recordset_set_property;
+ object_class->get_property = gda_mysql_recordset_get_property;
+
+ g_object_class_install_property
+ (object_class,
+ PROP_CHUNK_SIZE,
+ g_param_spec_int ("chunk-size", _("Number of rows fetched at a time"),
+ NULL,
+ 1, G_MAXINT - 1, 10,
+ (G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE)));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_CHUNKS_READ,
+ g_param_spec_int ("chunks-read", _("Number of row chunks read since the object creation"),
+ NULL,
+ 0, G_MAXINT - 1, 0,
+ (G_PARAM_CONSTRUCT | G_PARAM_WRITABLE | G_PARAM_READABLE)));
+
+}
- if (rownum < 0 || rownum >= row_count) {
- gda_connection_add_event_string (recset->priv->cnc, _("Row number out of range"));
- return NULL;
- }
+static void
+gda_mysql_recordset_dispose (GObject *object)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *recset = (GdaMysqlRecordset *) object;
- mysql_data_seek (recset->priv->mysql_res, rownum);
- mysql_fields = mysql_fetch_fields (recset->priv->mysql_res);
- mysql_row = mysql_fetch_row (recset->priv->mysql_res);
- mysql_lengths = mysql_fetch_lengths (recset->priv->mysql_res);
- if (!mysql_row || !mysql_lengths)
- return NULL;
-
- row = gda_row_new (GDA_DATA_MODEL (recset), field_count);
+ g_return_if_fail (GDA_IS_MYSQL_RECORDSET (recset));
- for (i = 0; i < field_count; i++) {
- fill_gda_value ((GValue*) gda_row_get_value (row, i),
- mysql_fields[i].type,
- mysql_row[i],
- mysql_lengths[i],
- mysql_fields[i].flags & UNSIGNED_FLAG);
+ if (recset->priv) {
+ if (recset->priv->cnc)
+ g_object_unref (recset->priv->cnc);
+
+ /* free specific information */
+ // TO_IMPLEMENT;
+
+ gint i;
+ for (i = 0; i < (((GdaPModel *)recset)->prep_stmt)->ncols; ++i) {
+ g_free (recset->priv->mysql_bind[i].buffer);
+ g_free (recset->priv->mysql_bind[i].is_null);
+ g_free (recset->priv->mysql_bind[i].length);
+ }
+ g_free (recset->priv->mysql_bind);
+ recset->priv->mysql_bind = NULL;
+
+
+ g_free (recset->priv);
+ recset->priv = NULL;
}
- return row;
+ parent_class->dispose (object);
}
/*
- * GdaMysqlRecordset class implementation
+ * Public functions
*/
-static gint
-gda_mysql_recordset_get_n_rows (GdaDataModelRow *model)
+GType
+gda_mysql_recordset_get_type (void)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
+ static GType type = 0;
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), -1);
- g_return_val_if_fail (recset->priv != NULL, -1);
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdaMysqlRecordsetClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_mysql_recordset_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaMysqlRecordset),
+ 0,
+ (GInstanceInitFunc) gda_mysql_recordset_init
+ };
+ type = g_type_register_static (GDA_TYPE_PMODEL, "GdaMysqlRecordset", &info, 0);
+ }
- if (recset->priv->row_sync == FALSE)
- return recset->priv->mysql_res_rows;
- else
- return GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model);
+ return type;
}
-static GdaRow *
-gda_mysql_recordset_get_row (GdaDataModelRow *model, gint row, GError **error)
+/*
+ * the @ps struct is modified and transfered to the new data model created in
+ * this function
+ */
+GdaDataModel *
+gda_mysql_recordset_new (GdaConnection *cnc,
+ GdaMysqlPStmt *ps,
+ GdaDataModelAccessFlags flags,
+ GType *col_types)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- GdaMysqlRecordsetPrivate *priv_data;
- gint fetched_rows;
- gint i;
- GdaRow *row_list;
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *model;
+ MysqlConnectionData *cdata;
+ gint i;
+ GdaDataModelAccessFlags rflags;
+
+ MYSQL_BIND *mysql_bind = NULL;
+
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), NULL);
- g_return_val_if_fail (recset->priv != NULL, 0);
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (ps != NULL, NULL);
- row_list = (GdaRow *) GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_row (model, row,
- error);
- if (row_list != NULL)
- return row_list;
-
- priv_data = recset->priv;
- if (!priv_data->mysql_res) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Invalid MySQL handle"));
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
return NULL;
- }
-
- if (row < 0 || row > priv_data->mysql_res_rows) {
- gchar *str;
- str = g_strdup_printf (_("Row number out of range 0 - %d"),
- priv_data->mysql_res_rows - 1);
- gda_connection_add_event_string (priv_data->cnc, str);
- g_set_error (error, 0, 0, str);
- g_free (str);
-
- return NULL;
- }
+ /* make sure @ps reports the correct number of columns using the API*/
+ if (_GDA_PSTMT (ps)->ncols < 0) {
+ /*_GDA_PSTMT (ps)->ncols = ...;*/
+ // TO_IMPLEMENT;
+
+ _GDA_PSTMT(ps)->ncols = mysql_stmt_field_count (cdata->mysql_stmt);
+
+ }
+
+ /* completing @ps if not yet done */
+ if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
+ /* create prepared statement's columns */
+ GSList *list;
+ for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
+ _GDA_PSTMT (ps)->tmpl_columns = g_slist_prepend (_GDA_PSTMT (ps)->tmpl_columns,
+ gda_column_new ());
+ _GDA_PSTMT (ps)->tmpl_columns = g_slist_reverse (_GDA_PSTMT (ps)->tmpl_columns);
+
+ /* create prepared statement's types */
+ _GDA_PSTMT (ps)->types = g_new0 (GType, _GDA_PSTMT (ps)->ncols); /* all types are initialized to GDA_TYPE_NULL */
+ if (col_types) {
+ for (i = 0; ; i++) {
+ if (col_types [i] > 0) {
+ if (col_types [i] == G_TYPE_NONE)
+ break;
+ if (i >= _GDA_PSTMT (ps)->ncols)
+ g_warning (_("Column %d is out of range (0-%d), ignoring its specified type"), i,
+ _GDA_PSTMT (ps)->ncols - 1);
+ else
+ _GDA_PSTMT (ps)->types [i] = col_types [i];
+ }
+ }
+ }
- fetched_rows = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model);
+
+ MYSQL_RES *mysql_res = mysql_stmt_result_metadata (cdata->mysql_stmt);
+ MYSQL_FIELD *mysql_fields = mysql_fetch_fields (mysql_res);
+
+ mysql_bind = g_new0 (MYSQL_BIND, GDA_PSTMT (ps)->ncols);
+ //
+ /* fill GdaColumn's data */
+ for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns;
+ i < GDA_PSTMT (ps)->ncols;
+ i++, list = list->next) {
+ GdaColumn *column;
+
+ column = GDA_COLUMN (list->data);
- gda_data_model_freeze (GDA_DATA_MODEL (recset));
+ /* use C API to set columns' information using gda_column_set_*() */
+ // TO_IMPLEMENT;
+
+ MYSQL_FIELD *field = &mysql_fields[i];
+ g_print ("*** %s , %d\n",
+ field->name, field->type);
+ GType gtype = _GDA_PSTMT(ps)->types[i];
+ if (gtype == 0) {
+ gtype = _gda_mysql_type_to_gda (cdata, field->type);
+ _GDA_PSTMT(ps)->types[i] = gtype;
+ }
+ gda_column_set_g_type (column, gtype);
+ gda_column_set_name (column, field->name);
+ gda_column_set_title (column, field->name);
+ gda_column_set_scale (column, (gtype == G_TYPE_DOUBLE) ? DBL_DIG :
+ (gtype == G_TYPE_FLOAT) ? FLT_DIG : 0);
+ gda_column_set_defined_size (column, field->length);
+ gda_column_set_references (column, "");
+
+ /* Use @cnc's associate GdaMetaStore to get the following information:
+ gda_column_set_references (column, ...);
+ gda_column_set_table (column, ...);
+ gda_column_set_primary_key (column, ...);
+ gda_column_set_unique_key (column, ...);
+ gda_column_set_allow_null (column, ...);
+ gda_column_set_auto_increment (column, ...);
+ */
+
+
+ mysql_bind[i].buffer_type = field->type;
+ switch (mysql_bind[i].buffer_type) {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ mysql_bind[i].buffer = g_malloc0 (sizeof(int));
+ mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+ break;
+ case MYSQL_TYPE_NULL:
+ break;
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ mysql_bind[i].buffer = g_malloc0 (sizeof(MYSQL_TIME));
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ mysql_bind[i].buffer = g_malloc0 (sizeof(double));
+ mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ mysql_bind[i].buffer = g_malloc0 (field->max_length + 1);
+ mysql_bind[i].buffer_length = field->max_length + 1;
+ mysql_bind[i].length = g_malloc0 (sizeof(unsigned long));
+ break;
+ default:
+ g_warning (_("Invalid column bind data type.\n"),
+ mysql_bind[i].buffer_type);
+ }
+
+ }
+
+ if (mysql_stmt_bind_result (cdata->mysql_stmt, mysql_bind)) {
+ g_warning ("mysql_stmt_bind_result failed: %s\n", mysql_stmt_error (cdata->mysql_stmt));
+ }
+
+ mysql_free_result (mysql_res);
+
+ }
+
+ /* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
+ if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
+ rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
+ else
+ rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
- for (i = fetched_rows; i <= row; i++) {
- row_list = fetch_row (recset, i);
- if (!row_list)
- return NULL;
+ /* create data model */
+ model = g_object_new (GDA_TYPE_MYSQL_RECORDSET,
+ "prepared-stmt", ps,
+ "model-usage", rflags,
+ NULL);
+ model->priv->cnc = cnc;
+ g_object_ref (G_OBJECT(cnc));
- if (! GDA_DATA_MODEL_ROW_CLASS (parent_class)->append_row (model, row_list, NULL))
- return NULL;
- }
+ /* post init specific code */
+ // TO_IMPLEMENT;
+
+ if (mysql_bind != NULL)
+ model->priv->mysql_bind = mysql_bind;
+
+ model->priv->mysql_stmt = cdata->mysql_stmt;
- gda_data_model_thaw (GDA_DATA_MODEL (recset));
+ ((GdaPModel *) model)->advertized_nrows = mysql_stmt_affected_rows (cdata->mysql_stmt);
+
- return row_list;
+ return GDA_DATA_MODEL (model);
}
-static const GValue *
-gda_mysql_recordset_get_value_at (GdaDataModelRow *model, gint col, gint row)
-{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- GdaMysqlRecordsetPrivate *priv_data;
- const GValue *value;
- const GdaRow *fields;
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), NULL);
- g_return_val_if_fail (recset->priv != NULL, 0);
-
- if (row < GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model)) {
- value = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_value_at (model, col, row);
- if (value != NULL)
- return value;
- }
-
- priv_data = recset->priv;
- if (!priv_data->mysql_res) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Invalid MySQL handle"));
- return NULL;
- }
+/*
+ * Get the number of rows in @model, if possible
+ */
+static gint
+gda_mysql_recordset_fetch_nb_rows (GdaPModel *model)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel;
- if (row < 0 || row > priv_data->mysql_res_rows) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Row number out of range"));
- return NULL;
- }
+ imodel = GDA_MYSQL_RECORDSET (model);
+ if (model->advertized_nrows >= 0)
+ return model->advertized_nrows;
- if (col >= priv_data->ncolumns) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Column number out of range"));
- return NULL;
- }
+ /* use C API to determine number of rows,if possible */
+ // TO_IMPLEMENT;
+
+ model->advertized_nrows = mysql_stmt_affected_rows (imodel->priv->mysql_stmt);
+
- fields = gda_mysql_recordset_get_row (model, row, NULL);
- return fields != NULL ? gda_row_get_value ((GdaRow *) fields, col) : NULL;
+ return model->advertized_nrows;
}
-static gboolean
-gda_mysql_recordset_is_updatable (GdaDataModelRow *model)
-{
- GdaCommandType cmd_type;
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), FALSE);
-
- g_object_get (G_OBJECT (model), "command_type", &cmd_type, NULL);
- return cmd_type == GDA_COMMAND_TYPE_TABLE ? TRUE : FALSE;
-}
-
-static gboolean
-gda_mysql_recordset_append_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+static GdaPRow *
+new_row_from_mysql_stmt (GdaMysqlRecordset *imodel,
+ gint rownum)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- GdaMysqlRecordsetPrivate *priv_data;
- GdaRow *row_list;
- MYSQL *mysql;
- MYSQL_FIELD *mysql_field;
- gint i, fetched_rows, rc;
- GString *sql, *sql_value;
- const gchar *column_name;
-
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), FALSE);
- g_return_val_if_fail (row != NULL, FALSE);
- g_return_val_if_fail (gda_data_model_is_updatable (GDA_DATA_MODEL (model)), FALSE);
- g_return_val_if_fail (recset->priv != NULL, FALSE);
-
- priv_data = recset->priv;
-
- /* checks for valid MySQL handle */
- if (!priv_data->mysql_res) {
- gda_connection_add_event_string (priv_data->cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- /* get the mysql handle */
- mysql = g_object_get_data (G_OBJECT (priv_data->cnc), OBJECT_DATA_MYSQL_HANDLE);
+ g_print ("*** %s -- %d -- %d\n", __func__,
+ ((GdaPModel *) imodel)->prep_stmt->ncols, rownum);
- /* checks if the table name has been guessed */
- if (priv_data->table_name == NULL) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Table name could not be guessed"));
- return FALSE;
- }
-
- /* checks for correct number of columns */
- if (priv_data->ncolumns != gda_row_get_length (row)) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Attempt to insert a row with an invalid number of columns"));
- return FALSE;
- }
-
- /* check if all results are loaded in array, if not do so */
- if (priv_data->row_sync == FALSE)
- {
- fetched_rows = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model);
-
- gda_data_model_freeze (GDA_DATA_MODEL (recset));
-
- for (i = fetched_rows; i < priv_data->mysql_res_rows; i++) {
- row_list = fetch_row (recset, i);
- if (!row_list) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not synchronize array with MySQL result set"));
- return FALSE;
+ MYSQL_BIND *mysql_bind = imodel->priv->mysql_bind;
+ g_assert (mysql_bind);
+
+ GdaPRow *prow = gda_prow_new (((GdaPModel *) imodel)->prep_stmt->ncols);
+ gint col;
+ for (col = 0; col < ((GdaPModel *) imodel)->prep_stmt->ncols; ++col) {
+
+ GValue *value = gda_prow_get_value (prow, col);
+ GType type = ((GdaPModel *) imodel)->prep_stmt->types[col];
+ gda_value_reset_with_type (value, type);
+
+ gint i = col;
+
+ int intvalue = 0;
+ double doublevalue = 0.0;
+ MYSQL_TIME timevalue = { 0 };
+ char *strvalue = NULL;
+ my_bool is_null;
+ unsigned long length;
+
+ switch (mysql_bind[i].buffer_type) {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_LONGLONG:
+ g_memmove (&intvalue, mysql_bind[i].buffer, sizeof(int));
+ g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+
+ if (type == G_TYPE_INT)
+ g_value_set_int (value, intvalue);
+ else if (type == G_TYPE_LONG)
+ g_value_set_long (value, (long) intvalue);
+ else {
+ g_warning (_("Type %s not mapped for value %d"),
+ g_type_name (type), intvalue);
}
-
- if (!GDA_DATA_MODEL_ROW_CLASS (parent_class)->append_row (model, row_list, NULL)) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not synchronize array with MySQL result set"));
- return FALSE;
+
+ break;
+ case MYSQL_TYPE_NULL:
+ break;
+ case MYSQL_TYPE_TIME:
+ case MYSQL_TYPE_DATE:
+ case MYSQL_TYPE_DATETIME:
+ case MYSQL_TYPE_TIMESTAMP:
+ g_memmove (&timevalue, mysql_bind[i].buffer, sizeof(MYSQL_TIME));
+ break;
+ case MYSQL_TYPE_FLOAT:
+ case MYSQL_TYPE_DOUBLE:
+ g_memmove (&doublevalue, mysql_bind[i].buffer, sizeof(double));
+ g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+
+ setlocale (LC_NUMERIC, "C");
+ if (type == G_TYPE_FLOAT)
+ g_value_set_float (value, (float) doublevalue);
+ else if (type == G_TYPE_DOUBLE)
+ g_value_set_long (value, doublevalue);
+ else {
+ g_warning (_("Type %s not mapped for value %f"),
+ g_type_name (type), intvalue);
}
+ setlocale (LC_NUMERIC, "");
+
+ break;
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_BLOB:
+ case MYSQL_TYPE_TINY_BLOB:
+ case MYSQL_TYPE_MEDIUM_BLOB:
+ case MYSQL_TYPE_LONG_BLOB:
+ g_memmove (&length, mysql_bind[i].length, sizeof(unsigned long));
+ strvalue = g_memdup (mysql_bind[i].buffer, length + 1);
+
+ if (type == G_TYPE_STRING)
+ g_value_set_string (value, strvalue);
+ else {
+ g_warning (_("Type %s not mapped for value %p"),
+ g_type_name (type), strvalue);
+ }
+
+ break;
+ default:
+ g_warning (_("Invalid column bind data type.\n"),
+ mysql_bind[i].buffer_type);
}
+
+ }
+ return prow;
+}
- gda_data_model_thaw (GDA_DATA_MODEL (recset));
-
- /* set flag that all mysql result records are in array */
- priv_data->row_sync = TRUE;
- }
-
- /* prepare the SQL statement */
- sql = g_string_new ("INSERT INTO ");
- g_string_append_printf (sql, "%s (", priv_data->table_name);
- sql_value = g_string_new ("VALUES (");
+/*
+ * Create a new filled #GdaPRow object for the row at position @rownum, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ * - If *prow is NULL then a new #GdaPRow object has to be created,
+ * - and otherwise *prow contains a #GdaPRow object which has already been created
+ * (through a call to this very function), and in this case it should not be modified
+ * but the function may return FALSE if an error occurred.
+ *
+ * Memory management for that new GdaPRow object is left to the implementation, which
+ * can use gda_pmodel_take_row(). If new row objects are "given" to the GdaPModel implemantation
+ * using that method, then this method should detect when all the data model rows have been analysed
+ * (when model->nb_stored_rows == model->advertized_nrows) and then possibly discard the API handle
+ * as it won't be used anymore to fetch rows.
+ */
+static gboolean
+gda_mysql_recordset_fetch_random (GdaPModel *model,
+ GdaPRow **prow,
+ gint rownum,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel;
- for (i = 0; i < priv_data->ncolumns; i++) {
+ imodel = GDA_MYSQL_RECORDSET (model);
- if (i != 0) {
- sql = g_string_append (sql, ", ");
- sql_value = g_string_append (sql_value, ", ");
- }
- /* get column name */
- mysql_field = mysql_fetch_field_direct (priv_data->mysql_res, i);
- if (mysql_field)
- column_name = mysql_field->name;
- else
- column_name = gda_data_model_get_column_title (GDA_DATA_MODEL (model), i);
-
- sql = g_string_append (sql, "`");
- sql = g_string_append (sql, column_name);
- sql = g_string_append (sql, "`");
-
- sql_value = g_string_append (sql_value,
- gda_mysql_provider_value_to_sql_string (
- NULL,
- priv_data->cnc,
- gda_row_get_value ((GdaRow *) row, i))
- );
- }
+ // TO_IMPLEMENT;
+
+ if (*prow)
+ return TRUE;
- /* concatenate SQL statement */
- sql = g_string_append (sql, ") ");
- sql = g_string_append (sql, sql_value->str);
- sql = g_string_append (sql, ")");
-
- /* execute append command */
- rc = gda_mysql_real_query_wrap (priv_data->cnc, mysql, sql->str, strlen (sql->str));
- if (rc != 0) {
- gda_connection_add_event (
- priv_data->cnc, gda_mysql_make_error (mysql));
+ if (imodel->priv->mysql_stmt == NULL) {
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_INTERNAL_ERROR,
+ _("Internal error"));
return FALSE;
}
-
- g_string_free (sql, TRUE);
- g_string_free (sql_value, TRUE);
-
- /* append row in the array */
- if (! GDA_DATA_MODEL_ROW_CLASS (parent_class)->append_row (model, row, NULL)) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not append row to data model"));
+
+ if (mysql_stmt_fetch (imodel->priv->mysql_stmt))
return FALSE;
+
+ *prow = new_row_from_mysql_stmt (imodel, rownum);
+ gda_pmodel_take_row (model, *prow, rownum);
+
+ if (model->nb_stored_rows == model->advertized_nrows) {
+ g_print ("*** All the row have been converted...");
}
+
return TRUE;
}
+/*
+ * Create and "give" filled #GdaPRow object for all the rows in the model
+ */
static gboolean
-gda_mysql_recordset_remove_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+gda_mysql_recordset_store_all (GdaPModel *model, GError **error)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- GdaMysqlRecordsetPrivate *priv_data;
- GdaRow *row_list;
- GdaColumn *attrs;
- MYSQL *mysql;
- MYSQL_FIELD *mysql_field;
- gint i, fetched_rows, rc, colnum, uk;
- gchar *query, *query_where, *tmp;
- const gchar *column_name;
-
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), FALSE);
- g_return_val_if_fail (row != NULL, FALSE);
- g_return_val_if_fail (gda_data_model_is_updatable (GDA_DATA_MODEL (model)), FALSE);
- g_return_val_if_fail (recset->priv != NULL, FALSE);
-
- priv_data = recset->priv;
-
- /* checks for valid MySQL handle */
- if (!priv_data->mysql_res) {
- gda_connection_add_event_string (priv_data->cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- /* get the mysql handle */
- mysql = g_object_get_data (G_OBJECT (priv_data->cnc), OBJECT_DATA_MYSQL_HANDLE);
-
- /* checks if the given row belongs to the given model */
- if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
- g_set_error (error, 0, 0,
- _("Given row doesn't belong to the model."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Given row doesn't belong to the model."));
- return FALSE;
- }
-
- /* checks if the table name has been guessed */
- if (priv_data->table_name == NULL) {
- g_set_error (error, 0, 0,
- _("Table name could not be guessed"));
- gda_connection_add_event_string (priv_data->cnc,
- _("Table name could not be guessed"));
- return FALSE;
- }
-
- /* check if all results are loaded in array, if not do so */
- if (priv_data->row_sync == FALSE)
- {
- fetched_rows = GDA_DATA_MODEL_ROW_CLASS (parent_class)->get_n_rows (model);
-
- gda_data_model_freeze (GDA_DATA_MODEL (recset));
-
- for (i = fetched_rows; i < priv_data->mysql_res_rows; i++) {
- row_list = fetch_row (recset, i);
- if (!row_list) {
- g_set_error (error, 0, 0,
- _("Can not synchronize array with MySQL result set"));
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not synchronize array with MySQL result set"));
- return FALSE;
- }
-
- if (! GDA_DATA_MODEL_ROW_CLASS (parent_class)->append_row (model, row_list, error)) {
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not synchronize array with MySQL result set"));
- return FALSE;
- }
- }
-
- gda_data_model_thaw (GDA_DATA_MODEL (recset));
-
- /* set flag that all mysql result records are in array */
- priv_data->row_sync = TRUE;
- }
-
- query_where = g_strdup ("WHERE ");
-
- for (colnum = uk = 0;
- colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL(model));
- colnum++)
- {
- attrs = gda_data_model_describe_column (GDA_DATA_MODEL(model), colnum);
-
- mysql_field = mysql_fetch_field_direct (priv_data->mysql_res, colnum);
- if (mysql_field)
- column_name = mysql_field->name;
- else
- column_name = gda_data_model_get_column_title (GDA_DATA_MODEL (model), colnum);
-
- gchar *curval = gda_mysql_provider_value_to_sql_string (
- NULL,
- priv_data->cnc,
- gda_row_get_value ((GdaRow *) row, colnum)
- );
-
- /* unique column: we will use it as an index */
- if (gda_column_get_primary_key (attrs) ||
- gda_column_get_unique_key (attrs)) {
- /* fills the 'where' part of the update command */
- if (colnum != 0)
- query_where = g_strconcat (query_where, "AND ", NULL);
-
- /* fills the 'where' part of the remove command */
- tmp = g_strdup_printf ("`%s` = %s ",
- column_name,
- curval);
- query_where = g_strconcat (query_where, tmp, NULL);
- g_free (tmp);
- uk++;
- }
-
- g_free (curval);
- }
-
- if (uk == 0) {
- g_set_error (error, 0, 0,
- _("Model doesn't have at least one unique key."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Model doesn't have at least one unique key."));
- g_free (query_where);
-
- return FALSE;
- }
-
- /* build the delete command */
- query = g_strdup_printf ("DELETE FROM %s %s",
- priv_data->table_name,
- query_where);
-
- /* execute append command */
- rc = gda_mysql_real_query_wrap (priv_data->cnc, mysql, query, strlen (query));
- if (rc != 0) {
- gda_connection_add_event (
- priv_data->cnc, gda_mysql_make_error (mysql));
- g_free (query);
- g_free (query_where);
-
- return FALSE;
- }
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel;
+ gint i;
- g_free (query);
- g_free (query_where);
+ imodel = GDA_MYSQL_RECORDSET (model);
- /* remove row from the array */
- if (! GDA_DATA_MODEL_ROW_CLASS (parent_class)->remove_row (model, row, NULL)) {
- g_set_error (error, 0, 0,
- _("Can not remove row from data model"));
- gda_connection_add_event_string (priv_data->cnc,
- _("Can not remove row from data model"));
- return FALSE;
+ /* default implementation */
+ for (i = 0; i < model->advertized_nrows; i++) {
+ GdaPRow *prow;
+ if (! gda_mysql_recordset_fetch_random (model, &prow, i, error))
+ return FALSE;
}
-
return TRUE;
}
-static gboolean
-gda_mysql_recordset_update_row (GdaDataModelRow *model, GdaRow *row, GError **error)
+/*
+ * Create a new filled #GdaPRow object for the next cursor row, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ * - If *prow is NULL then a new #GdaPRow object has to be created,
+ * - and otherwise *prow contains a #GdaPRow object which has already been created
+ * (through a call to this very function), and in this case it should not be modified
+ * but the function may return FALSE if an error occurred.
+ *
+ * Memory management for that new GdaPRow object is left to the implementation, which
+ * can use gda_pmodel_take_row().
+ */
+static gboolean
+gda_mysql_recordset_fetch_next (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
{
- GdaMysqlRecordset *recset = (GdaMysqlRecordset *) model;
- GdaMysqlRecordsetPrivate *priv_data;
- gint colnum, uk, nuk, rc, rownum;
- gchar *query, *query_where, *query_set, *tmp;
- gchar *oldval, *newval;
- const gchar *column_name;
- MYSQL *mysql;
- MYSQL_FIELD *mysql_field;
- MYSQL_ROW mysql_row;
- GdaColumn *attrs;
-
- g_return_val_if_fail (GDA_IS_MYSQL_RECORDSET (recset), FALSE);
- g_return_val_if_fail (row != NULL, FALSE);
- g_return_val_if_fail (gda_data_model_is_updatable (GDA_DATA_MODEL (model)), FALSE);
- g_return_val_if_fail (recset->priv != NULL, FALSE);
-
- priv_data = recset->priv;
-
- /* checks for valid MySQL handle */
- if (!priv_data->mysql_res) {
- g_set_error (error, 0, 0,
- _("Invalid MySQL handle"));
- gda_connection_add_event_string (priv_data->cnc, _("Invalid MySQL handle"));
- return FALSE;
- }
-
- /* get the mysql handle */
- mysql = g_object_get_data (G_OBJECT (priv_data->cnc), OBJECT_DATA_MYSQL_HANDLE);
-
- /* checks if the given row belongs to the given model */
- if (gda_row_get_model ((GdaRow *) row) != GDA_DATA_MODEL (model)) {
- g_set_error (error, 0, 0,
- _("Given row doesn't belong to the model."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Given row doesn't belong to the model."));
- return FALSE;
- }
-
- /* checks if the table name has been guessed */
- if (priv_data->table_name == NULL) {
- g_set_error (error, 0, 0,
- _("Table name could not be guessed."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Table name could not be guessed."));
- return FALSE;
- }
-
- /* init query */
- query_where = g_strdup ("WHERE ");
- query_set = g_strdup ("SET ");
-
- /* get original data if from mysql result set */
- rownum = gda_row_get_number ((GdaRow *) row);
- if (rownum < priv_data->mysql_res_rows) {
- mysql_data_seek (recset->priv->mysql_res, rownum);
- mysql_row = mysql_fetch_row (recset->priv->mysql_res);
- }
-
- /* process columns */
- for (colnum = uk = nuk = 0;
- colnum != gda_data_model_get_n_columns (GDA_DATA_MODEL (model));
- colnum++)
- {
- attrs = gda_data_model_describe_column (GDA_DATA_MODEL (model), colnum);
- mysql_field = mysql_fetch_field_direct (priv_data->mysql_res, colnum);
- if (mysql_field)
- column_name = mysql_field->name;
- else
- column_name = gda_data_model_get_column_title (GDA_DATA_MODEL (model), colnum);
- newval = gda_value_stringify (gda_row_get_value ((GdaRow *) row, colnum));
-
- /* for data from mysql result we can retrieve original values to avoid
- unique columns to be updated */
- if (rownum < priv_data->mysql_res_rows)
- oldval = mysql_row[colnum];
- else
- oldval = newval;
-
- /* unique column: we won't update it, but we will use it as
- an index */
- if (gda_column_get_primary_key (attrs) ||
- gda_column_get_unique_key (attrs))
- {
- /* checks if it hasn't be modified anyway */
- if (oldval == NULL ||
- newval == NULL ||
- strcmp (oldval, newval) != 0)
- continue;
-
- /* fills the 'where' part of the update command */
- if (colnum != 0)
- query_where = g_strconcat (query_where, "AND ", NULL);
-
- tmp = g_strdup_printf ("`%s` = '%s' ",
- column_name,
- newval);
- query_where = g_strconcat (query_where, tmp, NULL);
- g_free (tmp);
- uk++;
- }
- /* non-unique column: update it */
- else {
- /* fills the 'set' part of the update command */
- tmp = g_strdup_printf ("`%s` = '%s', ",
- column_name,
- newval);
- query_set = g_strconcat (query_set, tmp, NULL);
- g_free (tmp);
- nuk++;
- }
-
- g_free (newval);
- }
-
- if (uk == 0) {
- g_set_error (error, 0, 0,
- _("Model does not have at least one non-modified unique key."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Model does not have at least one non-modified unique key."));
- g_free (query_set);
- g_free (query_where);
-
- return FALSE;
- }
-
- if (nuk == 0) {
- g_set_error (error, 0, 0,
- _("Model does not have any non-unique values to update."));
- gda_connection_add_event_string (priv_data->cnc,
- _("Model does not have any non-unique values to update."));
- g_free (query_set);
- g_free (query_where);
-
- return FALSE;
- }
-
- /* remove the last ',' in the SET part */
- tmp = strrchr (query_set, ',');
- if (tmp != NULL)
- *tmp = ' ';
-
- /* build the update command */
- query = g_strdup_printf ("UPDATE %s %s %s",
- priv_data->table_name,
- query_set,
- query_where);
-
- /* execute update command */
- rc = gda_mysql_real_query_wrap (priv_data->cnc, mysql, query, strlen (query));
- if (rc != 0) {
- GdaConnectionEvent *event = gda_mysql_make_error (mysql);
- gda_connection_add_event (priv_data->cnc, event);
- g_set_error (error, 0, 0,
- gda_connection_event_get_description (event));
- return FALSE;
- }
-
- /* emit update signals */
- gda_data_model_row_updated (GDA_DATA_MODEL (model), gda_row_get_number ((GdaRow *) row));
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
- /* clean up */
- g_free (query);
- g_free (query_set);
- g_free (query_where);
+ TO_IMPLEMENT;
return TRUE;
}
-GType
-gda_mysql_recordset_get_type (void)
+/*
+ * Create a new filled #GdaPRow object for the previous cursor row, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ * - If *prow is NULL then a new #GdaPRow object has to be created,
+ * - and otherwise *prow contains a #GdaPRow object which has already been created
+ * (through a call to this very function), and in this case it should not be modified
+ * but the function may return FALSE if an error occurred.
+ *
+ * Memory management for that new GdaPRow object is left to the implementation, which
+ * can use gda_pmodel_take_row().
+ */
+static gboolean
+gda_mysql_recordset_fetch_prev (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
{
- static GType type = 0;
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
- if (G_UNLIKELY (type == 0)) {
- static const GTypeInfo info = {
- sizeof (GdaMysqlRecordsetClass),
- (GBaseInitFunc) NULL,
- (GBaseFinalizeFunc) NULL,
- (GClassInitFunc) gda_mysql_recordset_class_init,
- NULL,
- NULL,
- sizeof (GdaMysqlRecordset),
- 0,
- (GInstanceInitFunc) gda_mysql_recordset_init
- };
- type = g_type_register_static (PARENT_TYPE, "GdaMysqlRecordset", &info, 0);
- }
+ TO_IMPLEMENT;
- return type;
+ return TRUE;
}
-GdaMysqlRecordset *
-gda_mysql_recordset_new (GdaConnection *cnc, MYSQL_RES *mysql_res, MYSQL *mysql)
+/*
+ * Create a new filled #GdaPRow object for the cursor row at position @rownum, and put it into *prow.
+ *
+ * WARNING: @prow will NOT be NULL, but *prow may or may not be NULL:
+ * - If *prow is NULL then a new #GdaPRow object has to be created,
+ * - and otherwise *prow contains a #GdaPRow object which has already been created
+ * (through a call to this very function), and in this case it should not be modified
+ * but the function may return FALSE if an error occurred.
+ *
+ * Memory management for that new GdaPRow object is left to the implementation, which
+ * can use gda_pmodel_take_row().
+ */
+static gboolean
+gda_mysql_recordset_fetch_at (GdaPModel *model, GdaPRow **prow, gint rownum, GError **error)
{
- GdaMysqlRecordset *model;
- MYSQL_FIELD *mysql_fields;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
- g_return_val_if_fail (mysql_res != NULL || mysql != NULL, NULL);
-
- model = g_object_new (GDA_TYPE_MYSQL_RECORDSET, NULL);
- model->priv->mysql_res = mysql_res;
- model->priv->cnc = cnc;
- model->priv->row_sync = FALSE;
- model->priv->ncolumns = 0;
- if (mysql_res == NULL) {
- model->priv->mysql_res_rows = mysql_affected_rows (mysql);
- return model;
- }
- else
- model->priv->mysql_res_rows = mysql_num_rows (model->priv->mysql_res);
-
- mysql_fields = mysql_fetch_fields (model->priv->mysql_res);
- if (mysql_fields != NULL) {
- gint i;
-
- model->priv->ncolumns = mysql_num_fields (model->priv->mysql_res);
- gda_data_model_array_set_n_columns (GDA_DATA_MODEL_ARRAY (model),
- model->priv->ncolumns);
- for (i = 0; i < model->priv->ncolumns; i++) {
- GdaColumn *column;
- MYSQL_FIELD *mysql_field;
-
- /* determine table name */
- gboolean multi_table = FALSE;
- if (strcmp(mysql_fields[i].table, mysql_fields[0].table) != 0)
- multi_table = TRUE;
-
- if (multi_table == FALSE)
- model->priv->table_name = g_strdup (mysql_fields[0].table);
- else
- model->priv->table_name = NULL;
-
- /* set GdaColumn attributes */
- column = gda_data_model_describe_column (GDA_DATA_MODEL (model), i);
- mysql_field = &(mysql_fields[i]);
- gda_column_set_title (column, mysql_field->name);
- if (mysql_field->name)
- gda_column_set_name (column, mysql_field->name);
- gda_column_set_defined_size (column, mysql_field->length);
- gda_column_set_table (column, mysql_field->table);
- gda_column_set_scale (column, mysql_field->decimals);
- gda_column_set_g_type (column, gda_mysql_type_to_gda (mysql_field->type,
- mysql_field->flags & UNSIGNED_FLAG));
- gda_column_set_allow_null (column, !IS_NOT_NULL (mysql_field->flags));
- gda_column_set_primary_key (column, IS_PRI_KEY (mysql_field->flags));
- gda_column_set_unique_key (column, mysql_field->flags & UNIQUE_KEY_FLAG);
- gda_column_set_auto_increment (column, mysql_field->flags & AUTO_INCREMENT_FLAG);
- }
- }
+ g_print ("*** %s\n", __func__);
+ GdaMysqlRecordset *imodel = (GdaMysqlRecordset*) model;
+
+ TO_IMPLEMENT;
- return model;
+ return TRUE;
}
Modified: trunk/providers/mysql/gda-mysql-recordset.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.h (original)
+++ trunk/providers/mysql/gda-mysql-recordset.h Sun Apr 6 17:06:43 2008
@@ -1,11 +1,8 @@
-/* GDA MySQL provider
- * Copyright (C) 1998 - 2005 The GNOME Foundation.
+/* GDA Mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
- * Bas Driessen <bas driessen xobas com>
+ * Carlos Savoretti <csavoretti gmail com>
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -23,10 +20,12 @@
* Boston, MA 02111-1307, USA.
*/
-#if !defined(__gda_mysql_recordset_h__)
-# define __gda_mysql_recordset_h__
+#ifndef __GDA_MYSQL_RECORDSET_H__
+#define __GDA_MYSQL_RECORDSET_H__
-#include <libgda/gda-data-model-array.h>
+#include <libgda/libgda.h>
+#include <providers-support/gda-pmodel.h>
+#include "gda-mysql-pstmt.h"
G_BEGIN_DECLS
@@ -36,21 +35,22 @@
#define GDA_IS_MYSQL_RECORDSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_MYSQL_RECORDSET))
#define GDA_IS_MYSQL_RECORDSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_MYSQL_RECORDSET))
-typedef struct _GdaMysqlRecordset GdaMysqlRecordset;
-typedef struct _GdaMysqlRecordsetClass GdaMysqlRecordsetClass;
+typedef struct _GdaMysqlRecordset GdaMysqlRecordset;
+typedef struct _GdaMysqlRecordsetClass GdaMysqlRecordsetClass;
typedef struct _GdaMysqlRecordsetPrivate GdaMysqlRecordsetPrivate;
struct _GdaMysqlRecordset {
- GdaDataModelArray model;
+ GdaPModel model;
GdaMysqlRecordsetPrivate *priv;
};
struct _GdaMysqlRecordsetClass {
- GdaDataModelArrayClass parent_class;
+ GdaPModelClass parent_class;
};
-GType gda_mysql_recordset_get_type (void) G_GNUC_CONST;
-GdaMysqlRecordset *gda_mysql_recordset_new (GdaConnection *cnc, MYSQL_RES *mysql_res, MYSQL *mysql);
+GType gda_mysql_recordset_get_type (void) G_GNUC_CONST;
+GdaDataModel *gda_mysql_recordset_new (GdaConnection *cnc, GdaMysqlPStmt *ps, GdaDataModelAccessFlags flags,
+ GType *col_types);
G_END_DECLS
Added: trunk/providers/mysql/gda-mysql-util.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-util.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,213 @@
+/* GDA mysql provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * 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 <glib/gi18n-lib.h>
+#include "gda-mysql-util.h"
+
+/* static GdaConnectionEventCode */
+/* gda_mysql_sqlsate_to_gda_code (const gchar *sqlstate) */
+/* { */
+/* guint64 gda_code = g_ascii_strtoull (sqlstate, NULL, 0); */
+
+/* switch (gda_code) { */
+/* case 42501: */
+/* return GDA_CONNECTION_EVENT_CODE_INSUFFICIENT_PRIVILEGES; */
+/* case 23505: */
+/* return GDA_CONNECTION_EVENT_CODE_UNIQUE_VIOLATION; */
+/* case 23502: */
+/* return GDA_CONNECTION_EVENT_CODE_NOT_NULL_VIOLATION; */
+/* default: */
+/* return GDA_CONNECTION_EVENT_CODE_UNKNOWN; */
+/* } */
+/* } */
+
+/*
+ * Create a new #GdaConnectionEvent object and "adds" it to @cnc
+ *
+ * Returns: a new GdaConnectionEvent which must not be unrefed()
+ */
+GdaConnectionEvent *
+_gda_mysql_make_error (GdaConnection *cnc,
+ MYSQL *mysql, /* PGresult *pg_res, */
+ GError **error)
+{
+ /* GdaConnectionEvent *error_ev; */
+ /* GdaConnectionEventCode gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN; */
+ /* GdaTransactionStatus *trans; */
+
+ /* error_ev = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR); */
+ /* if (mysql != NULL) { */
+ /* gchar *message; */
+
+ /* if (pg_res != NULL) { */
+ /* gchar *sqlstate; */
+
+ /* message = g_strdup (PQresultErrorMessage (pg_res)); */
+ /* // sqlstate = PQresultErrorField (pg_res, PG_DIAG_SQLSTATE); */
+ /* gda_connection_event_set_sqlstate (error_ev, sqlstate); */
+ /* gda_code = gda_mysql_sqlsate_to_gda_code (sqlstate); */
+ /* } */
+ /* else { */
+ /* message = g_strdup (PQerrorMessage (mysql)); */
+ /* gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN; */
+ /* } */
+
+
+ /* gchar *ptr = message; */
+ /* if (g_str_has_prefix (message, "ERROR:")) */
+ /* ptr += 6; */
+ /* g_strstrip (ptr); */
+
+ /* gda_connection_event_set_description (error_ev, ptr); */
+ /* gda_connection_event_set_gda_code (error_ev, gda_code); */
+ /* g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, ptr); */
+ /* g_free (message); */
+ /* } */
+ /* else { */
+ /* gda_connection_event_set_description (error_ev, _("No detail")); */
+ /* gda_connection_event_set_gda_code (error_ev, gda_code); */
+ /* g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR, */
+ /* _("No detail")); */
+ /* } */
+
+ /* gda_connection_event_set_code (error_ev, -1); */
+ /* gda_connection_event_set_source (error_ev, "gda-mysql"); */
+ /* gda_connection_add_event (cnc, error_ev); */
+
+ /* /\* change the transaction status if there is a problem *\/ */
+ /* trans = gda_connection_get_transaction_status (cnc); */
+ /* if (trans) { */
+ /* if ((PQtransactionStatus (mysql) == PQTRANS_INERROR) && */
+ /* (trans->state != GDA_TRANSACTION_STATUS_STATE_FAILED)) */
+ /* gda_connection_internal_change_transaction_state (cnc, */
+ /* GDA_TRANSACTION_STATUS_STATE_FAILED); */
+ /* } */
+ /* return error_ev; */
+
+ GdaConnectionEvent *event_error =
+ gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+ if (mysql) {
+ gda_connection_event_set_description
+ (event_error, mysql_error (mysql));
+ gda_connection_event_set_code
+ (event_error, mysql_errno (mysql));
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
+ mysql_sqlstate (mysql));
+ } else {
+ gda_connection_event_set_description
+ (event_error, _("No description"));
+ gda_connection_event_set_code
+ (event_error, -1);
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
+ _("No detail"));
+ }
+ gda_connection_event_set_code (event_error, -1);
+ gda_connection_event_set_source (event_error, "gda-mysql");
+
+ gda_connection_add_event (cnc, event_error);
+
+ return event_error;
+}
+
+/* /\* to be used only while initializing a connection *\/ */
+/* int */
+/* _gda_mysql_real_query_wrap (GdaConnection *cnc, */
+/* MYSQL *mysql, */
+/* const char *query, */
+/* unsigned long length) */
+/* { */
+/* GdaConnectionEvent *event; */
+
+/* if (cnc) { */
+/* event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND); */
+/* gda_connection_event_set_description (event, query); */
+/* gda_connection_add_event (cnc, event); */
+/* } */
+
+/* return mysql_real_query (mysql, query, length); */
+/* } */
+
+GType
+_gda_mysql_type_to_gda (MysqlConnectionData *cdata,
+ enum enum_field_types mysql_type)
+{
+ /* gint i; */
+
+ /* for (i = 0; i < cdata->ntypes; i++) */
+ /* if (cdata->type_data[i].oid == mysql_type) */
+ /* break; */
+
+ /* if (cdata->type_data[i].oid != mysql_type) */
+ /* return G_TYPE_STRING; */
+
+ /* return cdata->type_data[i].type; */
+
+ GType gtype = 0;
+ switch (mysql_type) {
+ case MYSQL_TYPE_TINY:
+ case MYSQL_TYPE_SHORT:
+ case MYSQL_TYPE_LONG:
+ case MYSQL_TYPE_INT24:
+ case MYSQL_TYPE_YEAR:
+ gtype = G_TYPE_INT;
+ break;
+ case MYSQL_TYPE_LONGLONG:
+ gtype = G_TYPE_LONG;
+ break;
+ case MYSQL_TYPE_FLOAT:
+ gtype = G_TYPE_FLOAT;
+ break;
+ case MYSQL_TYPE_DECIMAL:
+ case MYSQL_TYPE_NEWDECIMAL:
+ case MYSQL_TYPE_DOUBLE:
+ gtype = G_TYPE_DOUBLE;
+ break;
+ case MYSQL_TYPE_BIT:
+ case MYSQL_TYPE_BLOB:
+ gtype = GDA_TYPE_BLOB;
+ break;
+ case MYSQL_TYPE_TIMESTAMP:
+ case MYSQL_TYPE_DATETIME:
+ gtype = GDA_TYPE_TIMESTAMP;
+ break;
+ case MYSQL_TYPE_DATE:
+ gtype = G_TYPE_DATE;
+ break;
+ case MYSQL_TYPE_TIME:
+ gtype = GDA_TYPE_TIME;
+ break;
+ case MYSQL_TYPE_NULL:
+ gtype = GDA_TYPE_NULL;
+ break;
+ case MYSQL_TYPE_STRING:
+ case MYSQL_TYPE_VAR_STRING:
+ case MYSQL_TYPE_SET:
+ case MYSQL_TYPE_ENUM:
+ case MYSQL_TYPE_GEOMETRY:
+ default:
+ gtype = G_TYPE_STRING;
+ }
+ return gtype;
+
+}
Added: trunk/providers/mysql/gda-mysql-util.h
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gda-mysql-util.h Sun Apr 6 17:06:43 2008
@@ -0,0 +1,50 @@
+/* GDA mysql provider
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ * Rodrigo Moya <rodrigo gnome-db org>
+ * Gonzalo Paniagua Javier <gonzalo gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as 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; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_MYSQL_UTIL_H__
+#define __GDA_MYSQL_UTIL_H__
+
+#include "gda-mysql.h"
+
+G_BEGIN_DECLS
+
+GdaConnectionEvent *
+_gda_mysql_make_error (GdaConnection *cnc,
+ MYSQL *mysql,
+ GError **error);
+/* int */
+/* _gda_mysql_real_query_wrap (GdaConnection *cnc, */
+/* MYSQL *mysql, */
+/* const char *query, */
+/* unsigned long length); */
+/* int */
+/* _gda_mysql_get_connection_type_list (GdaConnection *cnc, */
+/* MysqlConnectionData *cdata); */
+/* GType */
+/* _gda_mysql_type_oid_to_gda (MysqlConnectionData *cdata, */
+/* enum enum_field_types mysql_type); */
+
+G_END_DECLS
+
+#endif
+
Modified: trunk/providers/mysql/gda-mysql.h
==============================================================================
--- trunk/providers/mysql/gda-mysql.h (original)
+++ trunk/providers/mysql/gda-mysql.h Sun Apr 6 17:06:43 2008
@@ -1,10 +1,8 @@
-/* GDA MySQL provider
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+/* GDA mysql provider
+ * Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
+ * Carlos Savoretti <csavoretti gmail com>
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -25,40 +23,30 @@
#ifndef __GDA_MYSQL_H__
#define __GDA_MYSQL_H__
-#include <glib/gmacros.h>
-#include <libgda/gda-connection.h>
-#include <libgda/gda-server-provider.h>
-#include <glib/gi18n-lib.h>
-#include <libgda/gda-value.h>
-#include "gda-mysql-provider.h"
-
-#ifdef G_OS_WIN32
-#include <windows.h>
-#endif
+/*
+ * Provider name
+ */
+#define MYSQL_PROVIDER_NAME "Mysql"
+#include <libgda/libgda.h>
#include <mysql.h>
-#include <mysql_com.h>
-
-/* undefine the macros defined by Libgda because MySQL exports them */
-#undef PACKAGE_BUGREPORT
-#undef PACKAGE_NAME
-#undef PACKAGE_STRING
-#undef PACKAGE_TARNAME
-#undef PACKAGE_VERSION
-#include <my_config.h>
-
-#define GDA_MYSQL_PROVIDER_ID "GDA MySQL provider"
-
-G_BEGIN_DECLS
/*
- * Utility functions
+ * Provider's specific connection data
*/
-
-GdaConnectionEvent *gda_mysql_make_error (MYSQL *handle);
-GType gda_mysql_type_to_gda (enum enum_field_types mysql_type, gboolean is_unsigned);
-int gda_mysql_real_query_wrap (GdaConnection *cnc, MYSQL *mysql,
- const char *stmt_str, unsigned long length);
-G_END_DECLS
+typedef struct {
+ /* TO_ADD: this structure holds any information necessary to specialize the GdaConnection, usually a connection
+ * handle from the C or C++ API
+ */
+
+ GdaConnection *cnc;
+ MYSQL *mysql;
+ MYSQL_STMT *mysql_stmt;
+
+ /* Backend version (to which we're connected). */
+ gchar *version;
+ unsigned long version_long;
+
+} MysqlConnectionData;
#endif
Added: trunk/providers/mysql/gen_def.c
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/gen_def.c Sun Apr 6 17:06:43 2008
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/*
+ * This program generates tokens'ID transformation because the GdaSqlParser object uses 2 Lemon generated
+ * parsers at once, but with only one tokenizer (because each Lemon generated parser generates it own IDs for
+ * tokens).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#define MAX_SYMBOLS 500
+#define PARSER_HEADER "parser.h"
+#define FALSE 0
+#define TRUE (!FALSE)
+
+typedef struct {
+ char *key;
+ int parser_value;
+} HashEntry;
+
+HashEntry entries[MAX_SYMBOLS];
+int nb_entries; /* must remain < MAX_SYMBOLS */
+
+typedef enum {
+ TYPE_IMPOSED,
+ TYPE_PARSER
+} SourceType;
+
+static void parse_contents (FILE *stream, SourceType type);
+static HashEntry *find_entry_for_token (char *token);
+int
+main (int argc,char** argv)
+{
+ int i;
+ FILE *fd_imposed;
+ FILE *fd_parser;
+ HashEntry *illegal_entry;
+ HashEntry *rawstring_entry;
+
+ memset (entries, 0, sizeof (entries));
+ fd_imposed = fopen (IMPOSED_HEADER, "r");
+ if (!fd_imposed) {
+ printf ("Can't open '%s':%s\n", IMPOSED_HEADER, strerror (errno));
+ return 1;
+ }
+ fd_parser = fopen (PARSER_HEADER, "r");
+ if (!fd_parser) {
+ printf ("Can't open '%s':%s\n", PARSER_HEADER, strerror (errno));
+ return 1;
+ }
+
+ nb_entries = 0;
+ parse_contents (fd_imposed, TYPE_IMPOSED);
+ parse_contents (fd_parser, TYPE_PARSER);
+
+ fclose (fd_imposed);
+ fclose (fd_parser);
+
+ /* output notice */
+ printf ("/*\n * This file is generated by the gen_def program (see the gen_def.c file \n"
+ " * for some explanations)\n"
+ " * DO NOT EDIT MANUALLY\n */\n\n\n");
+
+ /* output */
+ for (i = 0; i < nb_entries; i++) {
+ HashEntry *entry = &(entries[i]);
+ printf ("#define L_%s \t\t %d\n", entry->key, i);
+ }
+ illegal_entry = find_entry_for_token ("ILLEGAL");
+ rawstring_entry = find_entry_for_token ("RAWSTRING");
+ printf ("gint mysql_parser_tokens[] = {\n");
+ for (i = 0; i < nb_entries; i++) {
+ HashEntry *entry = &(entries[i]);
+ if (i!= 0)
+ printf (",");
+ if (entry->parser_value >= 0)
+ printf ("%d", entry->parser_value);
+ else
+ printf ("%d", illegal_entry->parser_value);
+ }
+ printf ("};\n");
+
+ return 0;
+}
+
+static HashEntry *
+find_entry_for_token (char *token)
+{
+ int i;
+
+ for (i = 0; i < nb_entries; i++) {
+ HashEntry *e = &(entries[i]);
+ if (!strcmp (e->key, token))
+ return e;
+ }
+ return NULL;
+}
+
+
+
+static void
+parse_line (char *line, SourceType type)
+{
+ char *z, *token;
+ int value;
+ HashEntry *entry;
+
+ z = line;
+ if (strncmp (z, "#define ", 8)) {
+ printf ("Expected '#define', not found");
+ exit (1);
+ }
+ z += 8;
+ token = z + 2;
+ for (; *z && *z != ' '; z++);
+ *z = 0;
+ z++;
+ for (; *z == ' '; z++);
+ value = atoi (z);
+ /*printf ("%d Token: /%s/, value=%d\n", type, token, value);*/
+
+ entry = find_entry_for_token (token);
+ if (!entry) {
+ nb_entries++;
+ entry = &(entries[nb_entries - 1]);
+ entry->key = malloc (sizeof (char) * (strlen (token) + 1));
+ memcpy (entry->key, token, strlen (token) + 1);
+ entry->parser_value = -1;
+ }
+ if (type == TYPE_PARSER)
+ entry->parser_value = value;
+}
+
+static void
+parse_contents (FILE *stream, SourceType type)
+{
+#define BUFSIZE 500
+ char buffer[BUFSIZE];
+ int read;
+ char *end;
+
+ read = fread (buffer, 1, BUFSIZE, stream);
+ end = buffer + read;
+ while (read > 0) {
+ char *ptr;
+
+ /* read all complete lines in buffer */
+ while (end > buffer) {
+ char *hold = NULL;
+ for (ptr = buffer; (ptr < end) && *ptr && (*ptr != '\n'); ptr++);
+ if (ptr == end)
+ break;
+ if (*ptr)
+ hold = ptr+1;
+ *ptr = 0;
+
+ /* treat the line */
+ parse_line (buffer, type);
+
+ if (hold) {
+ int l = end - hold;
+ end -= hold - buffer;
+ memmove (buffer, hold, l);
+ }
+ else
+ break;
+ }
+
+ read = fread (end, 1, BUFSIZE - (end - buffer), stream);
+ end += read;
+ }
+}
+
Modified: trunk/providers/mysql/libgda-mysql-4.0.pc.in
==============================================================================
--- trunk/providers/mysql/libgda-mysql-4.0.pc.in (original)
+++ trunk/providers/mysql/libgda-mysql-4.0.pc.in Sun Apr 6 17:06:43 2008
@@ -3,7 +3,7 @@
libdir= libdir@
includedir= includedir@
-Name: libgda-mysql- GDA_ABI_MAJOR_VERSION@ GDA_ABI_MINOR_VERSION@
-Description: GDA (GNOME Data Access) MySQL provider
+Name: libgda-postgres- GDA_ABI_MAJOR_VERSION@ GDA_ABI_MINOR_VERSION@
+Description: GDA (GNOME Data Access) Mysql provider
Requires: libgda- GDA_ABI_MAJOR_VERSION@ GDA_ABI_MINOR_VERSION@
Version: @VERSION@
Modified: trunk/providers/mysql/libmain.c
==============================================================================
--- trunk/providers/mysql/libmain.c (original)
+++ trunk/providers/mysql/libmain.c Sun Apr 6 17:06:43 2008
@@ -1,10 +1,8 @@
-/* GDA MySQL Provider
- * Copyright (C) 1998 - 2007 The GNOME Foundation
+/* GDA Mysql Provider
+ * Copyright (C) 2008 The GNOME Foundation
*
* AUTHORS:
- * Michael Lausch <michael lausch at>
- * Rodrigo Moya <rodrigo gnome-db org>
- * Vivien Malerba <malerba gnome-db org>
+ * TO_ADD: your name and email
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -22,10 +20,10 @@
*/
#include <glib/gi18n-lib.h>
-#include <libgda/gda-config.h>
-#include "gda-mysql-provider.h"
#include <libgda/gda-server-provider-extra.h>
#include <libgda/binreloc/gda-binreloc.h>
+#include "gda-mysql.h"
+#include "gda-mysql-provider.h"
static gchar *module_path = NULL;
const gchar *plugin_get_name (void);
@@ -36,20 +34,20 @@
void
plugin_init (const gchar *real_path)
{
- if (real_path)
- module_path = g_strdup (real_path);
+ if (real_path)
+ module_path = g_strdup (real_path);
}
const gchar *
plugin_get_name (void)
{
- return "MySQL";
+ return MYSQL_PROVIDER_NAME;
}
const gchar *
plugin_get_description (void)
{
- return _("Provider for MySQL databases");
+ return _("Example provider for C API databases");
}
gchar *
@@ -68,7 +66,7 @@
{
GdaServerProvider *prov;
- prov = gda_mysql_provider_new ();
- g_object_set_data ((GObject* ) prov, "GDA_PROVIDER_DIR", module_path);
- return prov;
+ prov = (GdaServerProvider*) g_object_new (GDA_TYPE_MYSQL_PROVIDER, NULL);
+ g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
+ return prov;
}
Added: trunk/providers/mysql/parser.y
==============================================================================
--- (empty file)
+++ trunk/providers/mysql/parser.y Sun Apr 6 17:06:43 2008
@@ -0,0 +1,1025 @@
+// All token codes are small integers with #defines that begin with "TK_"
+%token_prefix T_
+
+// The type of the data attached to each token is GValue. This is also the
+// default type for non-terminals.
+//
+%token_type {GValue *}
+%default_type {GValue *}
+%token_destructor {if ($$) {
+ gchar *str = gda_sql_value_stringify ($$);
+ DEBUG ("token destructor /%s/", str);
+ g_free (str);
+ g_value_unset ($$); g_free ($$);}}
+
+// The generated parser function takes a 4th argument as follows:
+%extra_argument {GdaSqlParserIface *pdata}
+
+// This code runs whenever there is a syntax error
+//
+%syntax_error {
+ gda_sql_parser_set_syntax_error (pdata->parser);
+}
+%stack_overflow {
+ gda_sql_parser_set_overflow_error (pdata->parser);
+}
+
+// The name of the generated procedure that implements the parser
+// is as follows:
+%name gda_lemon_mysql_parser
+
+// The following text is included near the beginning of the C source
+// code file that implements the parser.
+//
+%include {
+#include <string.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/sql-parser/gda-sql-parser-private.h>
+#include <libgda/sql-parser/gda-statement-struct-util.h>
+#include <libgda/sql-parser/gda-statement-struct-trans.h>
+#include <libgda/sql-parser/gda-statement-struct-insert.h>
+#include <libgda/sql-parser/gda-statement-struct-update.h>
+#include <libgda/sql-parser/gda-statement-struct-delete.h>
+#include <libgda/sql-parser/gda-statement-struct-select.h>
+#include <libgda/sql-parser/gda-statement-struct-compound.h>
+#include <libgda/sql-parser/gda-statement-struct-parts.h>
+#include <assert.h>
+
+#ifdef GDA_DEBUG_NO
+#define DEBUG(format, ...) g_print ("___" format "\n", __VA_ARGS__)
+#else
+#define DEBUG(format, ...)
+#endif
+
+typedef struct {
+ GValue *fname;
+ GdaSqlExpr *expr;
+} UpdateSet;
+
+typedef struct {
+ gboolean distinct;
+ GdaSqlExpr *expr;
+} Distinct;
+
+typedef struct {
+ GdaSqlExpr *count;
+ GdaSqlExpr *offset;
+} Limit;
+
+typedef struct {
+ GSList *when_list;
+ GSList *then_list;
+} CaseBody;
+
+static GdaSqlOperator
+sql_operation_string_to_operator (const gchar *op)
+{
+ switch (g_ascii_toupper (*op)) {
+ case 'A':
+ return GDA_SQL_OPERATOR_AND;
+ case 'O':
+ return GDA_SQL_OPERATOR_OR;
+ case 'N':
+ return GDA_SQL_OPERATOR_NOT;
+ case '=':
+ return GDA_SQL_OPERATOR_EQ;
+ case 'I':
+ if (op[1] == 'S')
+ return GDA_SQL_OPERATOR_IS;
+ else if (op[1] == 'N')
+ return GDA_SQL_OPERATOR_IN;
+ break;
+ case 'L':
+ return GDA_SQL_OPERATOR_LIKE;
+ case 'B':
+ return GDA_SQL_OPERATOR_BETWEEN;
+ case '>':
+ if (op[1] == '=')
+ return GDA_SQL_OPERATOR_GEQ;
+ else if (op[1] == 0)
+ return GDA_SQL_OPERATOR_GT;
+ break;
+ case '<':
+ if (op[1] == '=')
+ return GDA_SQL_OPERATOR_LEQ;
+ else if (op[1] == 0)
+ return GDA_SQL_OPERATOR_LT;
+ break;
+ case '!':
+ if (op[1] == '=')
+ return GDA_SQL_OPERATOR_DIFF;
+ else if (op[1] == '~') {
+ if (op[2] == 0)
+ return GDA_SQL_OPERATOR_NOT_REGEXP;
+ else if (op[2] == '*')
+ return GDA_SQL_OPERATOR_NOT_REGEXP_CI;
+ }
+ break;
+ case '~':
+ if (op[1] == '*')
+ return GDA_SQL_OPERATOR_REGEXP_CI;
+ else if (op[1] == 0)
+ return GDA_SQL_OPERATOR_REGEXP;
+ break;
+ case 'S':
+ return GDA_SQL_OPERATOR_SIMILAR;
+ case '|':
+ if (op[1] == '|')
+ return GDA_SQL_OPERATOR_CONCAT;
+ else
+ return GDA_SQL_OPERATOR_BITOR;
+ case '+':
+ return GDA_SQL_OPERATOR_PLUS;
+ case '-':
+ return GDA_SQL_OPERATOR_MINUS;
+ case '*':
+ return GDA_SQL_OPERATOR_STAR;
+ case '/':
+ return GDA_SQL_OPERATOR_DIV;
+ case '%':
+ return GDA_SQL_OPERATOR_REM;
+ case '&':
+ return GDA_SQL_OPERATOR_BITAND;
+ }
+ g_error ("Unhandled operator named '%s'\n", op);
+ return 0;
+}
+
+static GdaSqlOperator
+string_to_op_type (GValue *value)
+{
+ GdaSqlOperator op;
+ op = sql_operation_string_to_operator (g_value_get_string (value));
+ g_value_reset (value);
+ g_free (value);
+ return op;
+}
+
+static GdaSqlExpr *
+compose_multiple_expr (GdaSqlOperator op, GdaSqlExpr *left, GdaSqlExpr *right) {
+ GdaSqlExpr *ret;
+ if (left->cond && (left->cond->operator == op)) {
+ ret = left;
+ ret->cond->operands = g_slist_append (ret->cond->operands, right);
+ }
+ else {
+ GdaSqlOperation *cond;
+ ret = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret));
+ ret->cond = cond;
+ cond->operator = op;
+ cond->operands = g_slist_prepend (NULL, right);
+ GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_prepend (cond->operands, left);
+ GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond);
+ }
+ return ret;
+}
+
+static GdaSqlExpr *
+create_two_expr (GdaSqlOperator op, GdaSqlExpr *left, GdaSqlExpr *right) {
+ GdaSqlExpr *ret;
+ GdaSqlOperation *cond;
+ ret = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret));
+ ret->cond = cond;
+ cond->operator = op;
+ cond->operands = g_slist_prepend (NULL, right);
+ GDA_SQL_ANY_PART (right)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_prepend (cond->operands, left);
+ GDA_SQL_ANY_PART (left)->parent = GDA_SQL_ANY_PART (cond);
+ return ret;
+}
+
+static GdaSqlExpr *
+create_uni_expr (GdaSqlOperator op, GdaSqlExpr *expr) {
+ GdaSqlExpr *ret;
+ GdaSqlOperation *cond;
+ ret = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (ret));
+ ret->cond = cond;
+ cond->operator = op;
+ cond->operands = g_slist_prepend (NULL, expr);
+ GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond);
+ return ret;
+}
+
+static GdaSqlStatement *
+compose_multiple_compounds (GdaSqlStatementCompoundType ctype, GdaSqlStatement *left, GdaSqlStatement *right) {
+ GdaSqlStatement *ret;
+ GdaSqlStatementCompound *lc = (GdaSqlStatementCompound*) left->contents;
+ if (lc->compound_type == ctype) {
+ GdaSqlStatementCompound *rc = (GdaSqlStatementCompound*) right->contents;
+ if (!rc->stmt_list->next || rc->compound_type == ctype) {
+ GSList *list;
+ for (list = rc->stmt_list; list; list = list->next)
+ GDA_SQL_ANY_PART (((GdaSqlStatement*)list->data)->contents)->parent = GDA_SQL_ANY_PART (lc);
+
+ ret = left;
+ lc->stmt_list = g_slist_concat (lc->stmt_list, rc->stmt_list);
+ rc->stmt_list = NULL;
+ gda_sql_statement_free (right);
+ }
+ }
+ else {
+ ret = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND);
+ gda_sql_statement_compound_set_type (ret, ctype);
+ gda_sql_statement_compound_take_stmt (ret, left);
+ gda_sql_statement_compound_take_stmt (ret, right);
+ }
+ return ret;
+}
+
+}
+
+// The following directive causes tokens ABORT, AFTER, ASC, etc. to
+// fallback to ID if they will not parse as their original value.
+%fallback ID
+ ABORT AFTER ANALYZE ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
+ DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
+ IGNORE IMMEDIATE INITIALLY INSTEAD LIKE MATCH PLAN
+ QUERY KEY OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW
+ TEMP TRIGGER VACUUM VIEW VIRTUAL
+ REINDEX RENAME CTIME_KW IF
+ DELIMITER COMMIT ROLLBACK ISOLATION LEVEL SERIALIZABLE READ COMMITTED
+ UNCOMMITTED REPEATABLE WRITE ONLY SAVEPOINT RELEASE COMMENT FORCE WAIT NOWAIT BATCH.
+
+// Define operator precedence early so that this is the first occurance
+// of the operator tokens in the grammer. Keeping the operators together
+// causes them to be assigned integer values that are close together,
+// which keeps parser tables smaller.
+%left OR.
+%left AND.
+%right NOT.
+%left IS MATCH LIKE IN ISNULL NOTNULL DIFF EQ.
+%left BETWEEN.
+%left GT LEQ LT GEQ.
+%left REGEXP REGEXP_CI NOT_REGEXP NOT_REGEXP_CI.
+%left SIMILAR.
+%right ESCAPE.
+%left BITAND BITOR LSHIFT RSHIFT.
+%left PLUS MINUS.
+%left STAR SLASH REM.
+%left CONCAT.
+%left COLLATE.
+%right UMINUS UPLUS BITNOT.
+%left LP RP.
+%left JOIN INNER NATURAL LEFT RIGHT FULL CROSS.
+%left UNION EXCEPT.
+%left INTERSECT.
+%left PGCAST.
+
+// force the declaration of the ILLEGAL and SQLCOMMENT tokens
+%nonassoc ILLEGAL.
+%nonassoc SQLCOMMENT.
+
+// Input is a single SQL command
+%type stmt {GdaSqlStatement *}
+%destructor stmt {g_print ("Statement destroyed by parser: %p\n", $$); gda_sql_statement_free ($$);}
+stmt ::= cmd(C) eos. {pdata->parsed_statement = C;}
+stmt ::= compound(C) eos. {
+ GdaSqlStatementCompound *scompound = (GdaSqlStatementCompound *) C->contents;
+ if (scompound->stmt_list->next)
+ /* real compound (multiple statements) */
+ pdata->parsed_statement = C;
+ else {
+ /* false compound (only 1 select) */
+ pdata->parsed_statement = (GdaSqlStatement*) scompound->stmt_list->data;
+ GDA_SQL_ANY_PART (pdata->parsed_statement->contents)->parent = NULL;
+ g_slist_free (scompound->stmt_list);
+ scompound->stmt_list = NULL;
+ gda_sql_statement_free (C);
+ }
+}
+cmd(C) ::= LP cmd(E) RP. {C = E;}
+compound(C) ::= LP compound(E) RP. {C = E;}
+
+eos ::= SEMI.
+eos ::= END_OF_FILE.
+
+%type cmd {GdaSqlStatement *}
+%destructor cmd {gda_sql_statement_free ($$);}
+
+//
+// Transactions
+//
+cmd(C) ::= BEGIN. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);}
+cmd(C) ::= BEGIN TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= BEGIN transtype(Y) TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= BEGIN transtype(Y) nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= BEGIN transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= BEGIN TRANSACTION transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= BEGIN TRANSACTION transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+}
+
+cmd(C) ::= BEGIN TRANSACTION transtype(Y) opt_comma transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= BEGIN TRANSACTION transilev(L) opt_comma transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= BEGIN transtype(Y) opt_comma transilev(L). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= BEGIN transilev(L) opt_comma transtype(Y). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_BEGIN);
+ gda_sql_statement_trans_take_mode (C, Y);
+ gda_sql_statement_trans_set_isol_level (C, L);
+}
+
+cmd(C) ::= END trans_opt_kw nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= COMMIT nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= COMMIT TRANSACTION nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= COMMIT FORCE STRING. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);}
+cmd(C) ::= COMMIT FORCE STRING COMMA INTEGER. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);}
+cmd(C) ::= COMMIT COMMENT STRING. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);}
+cmd(C) ::= COMMIT COMMENT STRING ora_commit_write. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);}
+cmd(C) ::= COMMIT ora_commit_write. {C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMMIT);}
+
+cmd(C) ::= ROLLBACK trans_opt_kw nm_opt(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+ora_commit_write ::= WRITE IMMEDIATE.
+ora_commit_write ::= WRITE BATCH.
+ora_commit_write ::= WRITE WAIT.
+ora_commit_write ::= WRITE NOWAIT.
+ora_commit_write ::= WRITE IMMEDIATE WAIT.
+ora_commit_write ::= WRITE IMMEDIATE NOWAIT.
+ora_commit_write ::= WRITE BATCH WAIT.
+ora_commit_write ::= WRITE BATCH NOWAIT.
+
+trans_opt_kw ::= .
+trans_opt_kw ::= TRANSACTION.
+
+opt_comma ::= .
+opt_comma ::= COMMA.
+
+%type transilev {GdaTransactionIsolation}
+transilev(L) ::= ISOLATION LEVEL SERIALIZABLE. {L = GDA_TRANSACTION_ISOLATION_SERIALIZABLE;}
+transilev(L) ::= ISOLATION LEVEL REPEATABLE READ. {L = GDA_TRANSACTION_ISOLATION_REPEATABLE_READ;}
+transilev(L) ::= ISOLATION LEVEL READ COMMITTED. {L = GDA_TRANSACTION_ISOLATION_READ_COMMITTED;}
+transilev(L) ::= ISOLATION LEVEL READ UNCOMMITTED. {L = GDA_TRANSACTION_ISOLATION_READ_UNCOMMITTED;}
+
+nm_opt(R) ::= . {R = NULL;}
+nm_opt(R) ::= nm(N). {R = N;}
+
+transtype(A) ::= DEFERRED(X). {A = X;}
+transtype(A) ::= IMMEDIATE(X). {A = X;}
+transtype(A) ::= EXCLUSIVE(X). {A = X;}
+transtype(A) ::= READ WRITE. {A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_set_string (A, "READ_WRITE");
+}
+transtype(A) ::= READ ONLY. {A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_set_string (A, "READ_ONLY");
+}
+
+//
+// Savepoints
+//
+cmd(C) ::= SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_SAVEPOINT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= RELEASE SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= RELEASE nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE_SAVEPOINT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= ROLLBACK trans_opt_kw TO nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+cmd(C) ::= ROLLBACK trans_opt_kw TO SAVEPOINT nm(R). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_ROLLBACK_SAVEPOINT);
+ gda_sql_statement_trans_take_name (C, R);
+}
+
+//
+// INSERT
+//
+cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) VALUES LP exprlist(Y) RP. {
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
+ gda_sql_statement_insert_take_table_name (C, X);
+ gda_sql_statement_insert_take_fields_list (C, F);
+ gda_sql_statement_insert_take_1_values_list (C, Y);
+ gda_sql_statement_insert_take_on_conflict (C, O);
+}
+
+cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) VALUES LP exprlist(Y) RP ins_extra_values(E). {
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
+ gda_sql_statement_insert_take_table_name (C, X);
+ gda_sql_statement_insert_take_fields_list (C, F);
+ gda_sql_statement_insert_take_1_values_list (C, Y);
+ gda_sql_statement_insert_take_extra_values_list (C, E);
+ gda_sql_statement_insert_take_on_conflict (C, O);
+}
+
+cmd(C) ::= INSERT opt_on_conflict(O) INTO fullname(X) inscollist_opt(F) compound(S). {
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
+ gda_sql_statement_insert_take_table_name (C, X);
+ gda_sql_statement_insert_take_fields_list (C, F);
+ gda_sql_statement_insert_take_select (C, S);
+ gda_sql_statement_insert_take_on_conflict (C, O);
+}
+
+
+opt_on_conflict(O) ::= . {O = NULL;}
+opt_on_conflict(O) ::= OR ID(V). {O = V;}
+
+%type ins_extra_values {GSList*}
+%destructor ins_extra_values {GSList *list;
+ for (list = $$; list; list = list->next) {
+ g_slist_foreach ((GSList*) list->data, (GFunc) gda_sql_field_free, NULL);
+ g_slist_free ((GSList*) list->data);
+ }
+ g_slist_free ($$);
+}
+ins_extra_values(E) ::= ins_extra_values(A) COMMA LP exprlist(L) RP. {E = g_slist_append (A, L);}
+ins_extra_values(E) ::= COMMA LP exprlist(L) RP. {E = g_slist_append (NULL, L);}
+
+%type inscollist_opt {GSList*}
+%destructor inscollist_opt {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_field_free, NULL); g_slist_free ($$);}}
+inscollist_opt(A) ::= . {A = NULL;}
+inscollist_opt(A) ::= LP inscollist(X) RP. {A = X;}
+
+%type inscollist {GSList*}
+%destructor inscollist {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_field_free, NULL); g_slist_free ($$);}}
+inscollist(A) ::= inscollist(X) COMMA fullname(Y). {GdaSqlField *field;
+ field = gda_sql_field_new (NULL);
+ gda_sql_field_take_name (field, Y);
+ A = g_slist_append (X, field);
+}
+inscollist(A) ::= fullname(Y). {GdaSqlField *field = gda_sql_field_new (NULL);
+ gda_sql_field_take_name (field, Y);
+ A = g_slist_prepend (NULL, field);
+}
+
+// DELETE
+cmd(C) ::= DELETE FROM fullname(T) where_opt(X). {C = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE);
+ gda_sql_statement_delete_take_table_name (C, T);
+ gda_sql_statement_delete_take_condition (C, X);}
+
+%type where_opt {GdaSqlExpr *}
+%destructor where_opt {gda_sql_expr_free ($$);}
+where_opt(A) ::= . {A = NULL;}
+where_opt(A) ::= WHERE expr(X). {A = X;}
+
+// UPDATE
+cmd(C) ::= UPDATE opt_on_conflict(O) fullname(T) SET setlist(S) where_opt(X). {
+ GSList *list;
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE);
+ gda_sql_statement_update_take_table_name (C, T);
+ gda_sql_statement_update_take_on_conflict (C, O);
+ gda_sql_statement_update_take_condition (C, X);
+ for (list = S; list; list = list->next) {
+ UpdateSet *set = (UpdateSet*) list->data;
+ gda_sql_statement_update_take_set_value (C, set->fname, set->expr);
+ g_free (set);
+ }
+ g_slist_free (S);
+}
+
+%type setlist {GSList*}
+%destructor setlist {GSList *list;
+ for (list = $$; list; list = list->next) {
+ UpdateSet *set = (UpdateSet*) list->data;
+ g_value_reset (set->fname); g_free (set->fname);
+ gda_sql_expr_free (set->expr);
+ g_free (set);
+ }
+ g_slist_free ($$);
+}
+setlist(A) ::= setlist(Z) COMMA fullname(X) EQ expr(Y). {UpdateSet *set;
+ set = g_new (UpdateSet, 1);
+ set->fname = X;
+ set->expr = Y;
+ A = g_slist_append (Z, set);
+}
+setlist(A) ::= fullname(X) EQ expr(Y). {UpdateSet *set;
+ set = g_new (UpdateSet, 1);
+ set->fname = X;
+ set->expr = Y;
+ A = g_slist_append (NULL, set);
+}
+
+// COMPOUND SELECT
+%type compound {GdaSqlStatement *}
+%destructor compound {gda_sql_statement_free ($$);}
+//compound(C) ::= LP compound(E) RP. {C = E;}
+compound(C) ::= selectcmd(S). {
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_COMPOUND);
+ gda_sql_statement_compound_take_stmt (C, S);
+}
+compound(C) ::= compound(L) UNION opt_compound_all(A) compound(R). {
+ C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_UNION_ALL : GDA_SQL_STATEMENT_COMPOUND_UNION,
+ L, R);
+}
+
+compound(C) ::= compound(L) EXCEPT opt_compound_all(A) compound(R). {
+ C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_EXCEPT_ALL : GDA_SQL_STATEMENT_COMPOUND_EXCEPT,
+ L, R);
+}
+
+compound(C) ::= compound(L) INTERSECT opt_compound_all(A) compound(R). {
+ C = compose_multiple_compounds (A ? GDA_SQL_STATEMENT_COMPOUND_INTERSECT_ALL : GDA_SQL_STATEMENT_COMPOUND_INTERSECT,
+ L, R);
+}
+
+%type opt_compound_all {gboolean}
+opt_compound_all(A) ::= . {A = FALSE;}
+opt_compound_all(A) ::= ALL. {A = TRUE;}
+
+
+// SELECT
+%type selectcmd {GdaSqlStatement *}
+%destructor selectcmd {gda_sql_statement_free ($$);}
+selectcmd(C) ::= SELECT distinct(D) selcollist(W) from(F) where_opt(Y)
+ groupby_opt(P) having_opt(Q) orderby_opt(Z) limit_opt(L). {
+ C = gda_sql_statement_new (GDA_SQL_STATEMENT_SELECT);
+ if (D) {
+ gda_sql_statement_select_take_distinct (C, D->distinct, D->expr);
+ g_free (D);
+ }
+ gda_sql_statement_select_take_expr_list (C, W);
+ gda_sql_statement_select_take_from (C, F);
+ gda_sql_statement_select_take_where_cond (C, Y);
+ gda_sql_statement_select_take_group_by (C, P);
+ gda_sql_statement_select_take_having_cond (C, Q);
+ gda_sql_statement_select_take_order_by (C, Z);
+ gda_sql_statement_select_take_limits (C, L.count, L.offset);
+}
+
+%type limit_opt {Limit}
+%destructor limit_opt {gda_sql_expr_free ($$.count); gda_sql_expr_free ($$.offset);}
+limit_opt(A) ::= . {A.count = NULL; A.offset = NULL;}
+limit_opt(A) ::= LIMIT expr(X). {A.count = X; A.offset = NULL;}
+limit_opt(A) ::= LIMIT expr(X) OFFSET expr(Y). {A.count = X; A.offset = Y;}
+limit_opt(A) ::= LIMIT expr(X) COMMA expr(Y). {A.count = X; A.offset = Y;}
+
+%type orderby_opt {GSList *}
+%destructor orderby_opt {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_select_order_free, NULL); g_slist_free ($$);}}
+orderby_opt(A) ::= . {A = 0;}
+orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
+
+%type sortlist {GSList *}
+%destructor sortlist {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_select_order_free, NULL); g_slist_free ($$);}}
+sortlist(A) ::= sortlist(X) COMMA expr(Y) sortorder(Z). {GdaSqlSelectOrder *order;
+ order = gda_sql_select_order_new (NULL);
+ order->expr = Y;
+ order->asc = Z;
+ A = g_slist_append (X, order);
+}
+sortlist(A) ::= expr(Y) sortorder(Z). {GdaSqlSelectOrder *order;
+ order = gda_sql_select_order_new (NULL);
+ order->expr = Y;
+ order->asc = Z;
+ A = g_slist_prepend (NULL, order);
+}
+
+%type sortorder {gboolean}
+sortorder(A) ::= ASC. {A = TRUE;}
+sortorder(A) ::= DESC. {A = FALSE;}
+sortorder(A) ::= . {A = TRUE;}
+
+
+%type having_opt {GdaSqlExpr *}
+%destructor having_opt {gda_sql_expr_free ($$);}
+having_opt(A) ::= . {A = NULL;}
+having_opt(A) ::= HAVING expr(X). {A = X;}
+
+%type groupby_opt {GSList*}
+%destructor groupby_opt {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_expr_free, NULL); g_slist_free ($$);}}
+groupby_opt(A) ::= . {A = 0;}
+groupby_opt(A) ::= GROUP BY nexprlist(X). {A = X;}
+
+%type from {GdaSqlSelectFrom *}
+%destructor from {gda_sql_select_from_free ($$);}
+from(F) ::= . {F = NULL;}
+from(F) ::= FROM seltablist(X). {F = X;}
+
+%type seltablist {GdaSqlSelectFrom *}
+%destructor seltablist {gda_sql_select_from_free ($$);}
+%type stl_prefix {GdaSqlSelectFrom *}
+%destructor stl_prefix {gda_sql_select_from_free ($$);}
+
+seltablist(L) ::= stl_prefix(P) seltarget(T) on_cond(C) using_opt(U). {
+ GSList *last;
+ if (P)
+ L = P;
+ else
+ L = gda_sql_select_from_new (NULL);
+ gda_sql_select_from_take_new_target (L, T);
+ last = g_slist_last (L->joins);
+ if (last) {
+ GdaSqlSelectJoin *join = (GdaSqlSelectJoin *) (last->data);
+ join->expr = C;
+ join->position = g_slist_length (L->targets) - 1;
+ join->using = U;
+ }
+}
+
+%type using_opt {GSList*}
+%destructor using_opt {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_field_free, NULL); g_slist_free ($$);}}
+using_opt(U) ::= USING LP inscollist(L) RP. {U = L;}
+using_opt(U) ::= . {U = NULL;}
+
+stl_prefix(P) ::= . {P = NULL;}
+stl_prefix(P) ::= seltablist(L) jointype(J). {GdaSqlSelectJoin *join;
+ P = L;
+ join = gda_sql_select_join_new (GDA_SQL_ANY_PART (P));
+ join->type = J;
+ gda_sql_select_from_take_new_join (P, join);
+}
+
+
+%type on_cond {GdaSqlExpr *}
+%destructor on_cond {gda_sql_expr_free ($$);}
+on_cond(N) ::= ON expr(E). {N = E;}
+on_cond(N) ::= . {N = NULL;}
+
+%type jointype {GdaSqlSelectJoinType}
+jointype(J) ::= COMMA. {J = GDA_SQL_SELECT_JOIN_CROSS;}
+jointype(J) ::= JOIN. {J = GDA_SQL_SELECT_JOIN_INNER;}
+jointype(J) ::= CROSS JOIN. {J = GDA_SQL_SELECT_JOIN_CROSS;}
+jointype(J) ::= INNER JOIN. {J = GDA_SQL_SELECT_JOIN_INNER;}
+jointype(J) ::= NATURAL JOIN. {J = GDA_SQL_SELECT_JOIN_NATURAL;}
+jointype(J) ::= LEFT JOIN. {J = GDA_SQL_SELECT_JOIN_LEFT;}
+jointype(J) ::= LEFT OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_LEFT;}
+jointype(J) ::= RIGHT JOIN. {J = GDA_SQL_SELECT_JOIN_RIGHT;}
+jointype(J) ::= RIGHT OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_RIGHT;}
+jointype(J) ::= FULL JOIN. {J = GDA_SQL_SELECT_JOIN_FULL;}
+jointype(J) ::= FULL OUTER JOIN. {J = GDA_SQL_SELECT_JOIN_FULL;}
+
+
+%type seltarget {GdaSqlSelectTarget *}
+%destructor seltarget {gda_sql_select_target_free ($$);}
+seltarget(T) ::= fullname(F) as(A). {T = gda_sql_select_target_new (NULL);
+ gda_sql_select_target_take_alias (T, A);
+ gda_sql_select_target_take_table_name (T, F);
+}
+seltarget(T) ::= fullname(F) ID(A). {T = gda_sql_select_target_new (NULL);
+ gda_sql_select_target_take_alias (T, A);
+ gda_sql_select_target_take_table_name (T, F);
+}
+seltarget(T) ::= LP compound(S) RP as(A). {T = gda_sql_select_target_new (NULL);
+ gda_sql_select_target_take_alias (T, A);
+ gda_sql_select_target_take_select (T, S);
+}
+
+%type selcollist {GSList *}
+%destructor selcollist {g_slist_foreach ($$, (GFunc) gda_sql_select_field_free, NULL); g_slist_free ($$);}
+
+%type sclp {GSList *}
+%destructor sclp {g_slist_foreach ($$, (GFunc) gda_sql_select_field_free, NULL); g_slist_free ($$);}
+sclp(A) ::= selcollist(X) COMMA. {A = X;}
+sclp(A) ::= . {A = NULL;}
+
+selcollist(L) ::= sclp(E) expr(X) as(A). {GdaSqlSelectField *field;
+ field = gda_sql_select_field_new (NULL);
+ gda_sql_select_field_take_expr (field, X);
+ gda_sql_select_field_take_alias (field, A);
+ L = g_slist_append (E, field);}
+selcollist(L) ::= sclp(E) starname(X). {GdaSqlSelectField *field;
+ field = gda_sql_select_field_new (NULL);
+ gda_sql_select_field_take_star_value (field, X);
+ L = g_slist_append (E, field);}
+
+starname(S) ::= STAR(X). {S = X;}
+starname(A) ::= nm(S) DOT STAR(X). {gchar *str;
+ str = g_strdup_printf ("%s.%s", g_value_get_string (S), g_value_get_string (X));
+ A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_take_string (A, str);
+ g_value_reset (S); g_free (S);
+ g_value_reset (X); g_free (X);
+}
+
+starname(A) ::= nm(C) DOT nm(S) DOT STAR(X). {gchar *str;
+ str = g_strdup_printf ("%s.%s.%s", g_value_get_string (C),
+ g_value_get_string (S), g_value_get_string (X));
+ A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_take_string (A, str);
+ g_value_reset (C); g_free (C);
+ g_value_reset (S); g_free (S);
+ g_value_reset (X); g_free (X);
+}
+
+as(A) ::= AS fullname(F). {A = F;}
+as(A) ::= AS value(F). {A = F;}
+as(A) ::= . {A = NULL;}
+
+%type distinct {Distinct *}
+%destructor distinct {if ($$) {if ($$->expr) gda_sql_expr_free ($$->expr); g_free ($$);}}
+distinct(E) ::= . {E = NULL;}
+distinct(E) ::= ALL. {E = NULL;}
+distinct(E) ::= DISTINCT. {E = g_new0 (Distinct, 1); E->distinct = TRUE;}
+distinct(E) ::= DISTINCT ON expr(X). [OR] {E = g_new0 (Distinct, 1); E->distinct = TRUE; E->expr = X;}
+
+// Non empty list of expressions
+%type nexprlist {GSList *}
+%destructor nexprlist {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_expr_free, NULL); g_slist_free ($$);}}
+nexprlist(L) ::= nexprlist(E) COMMA expr(X). {L = g_slist_append (E, X);}
+nexprlist(L) ::= expr(E). {L = g_slist_append (NULL, E);}
+
+// List of expressions
+%type exprlist {GSList *}
+%destructor exprlist {if ($$) {g_slist_foreach ($$, (GFunc) gda_sql_expr_free, NULL); g_slist_free ($$);}}
+exprlist(L) ::= . {L = NULL;}
+exprlist(L) ::= exprlist(E) COMMA expr(X). {L = g_slist_append (E, X);}
+exprlist(L) ::= expr(E). {L = g_slist_append (NULL, E);}
+
+// A single expression
+%type expr {GdaSqlExpr *}
+%destructor expr {gda_sql_expr_free ($$);}
+expr(E) ::= pvalue(V). {E = V;}
+expr(E) ::= value(V). {E = gda_sql_expr_new (NULL); E->value = V;}
+expr(E) ::= LP expr(X) RP. {E = X;}
+expr(E) ::= fullname(V). {E = gda_sql_expr_new (NULL); E->value = V;}
+expr(E) ::= fullname(V) LP exprlist(A) RP. {GdaSqlFunction *func;
+ E = gda_sql_expr_new (NULL);
+ func = gda_sql_function_new (GDA_SQL_ANY_PART (E));
+ gda_sql_function_take_name (func, V);
+ gda_sql_function_take_args_list (func, A);
+ E->func = func;}
+expr(E) ::= fullname(V) LP compound(S) RP. {GdaSqlFunction *func;
+ GdaSqlExpr *expr;
+ E = gda_sql_expr_new (NULL);
+ func = gda_sql_function_new (GDA_SQL_ANY_PART (E));
+ gda_sql_function_take_name (func, V);
+ expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func));
+ gda_sql_expr_take_select (expr, S);
+ gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr));
+ E->func = func;}
+expr(E) ::= fullname(V) LP starname(A) RP. {GdaSqlFunction *func;
+ GdaSqlExpr *expr;
+ E = gda_sql_expr_new (NULL);
+ func = gda_sql_function_new (GDA_SQL_ANY_PART (E));
+ gda_sql_function_take_name (func, V);
+ expr = gda_sql_expr_new (GDA_SQL_ANY_PART (func));
+ expr->value = A;
+ gda_sql_function_take_args_list (func, g_slist_prepend (NULL, expr));
+ E->func = func;}
+expr(E) ::= CAST LP expr(A) AS fullname(T) RP. {E = A;
+ A->cast_as = g_value_dup_string (T);
+ g_value_reset (T);
+ g_free (T);}
+expr(E) ::= expr(A) PGCAST fullname(T). {E = A;
+ A->cast_as = g_value_dup_string (T);
+ g_value_reset (T);
+ g_free (T);}
+
+expr(C) ::= expr(L) PLUS|MINUS(O) expr(R). {C = compose_multiple_expr (string_to_op_type (O), L, R);}
+expr(C) ::= expr(L) STAR expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_STAR, L, R);}
+expr(C) ::= expr(L) SLASH|REM(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);}
+expr(C) ::= expr(L) BITAND|BITOR(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);}
+
+expr(C) ::= MINUS expr(X). [UMINUS] {C = create_uni_expr (GDA_SQL_OPERATOR_MINUS, X);}
+expr(C) ::= PLUS expr(X). [UPLUS] {C = create_uni_expr (GDA_SQL_OPERATOR_PLUS, X);}
+
+expr(C) ::= expr(L) AND expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_AND, L, R);}
+expr(C) ::= expr(L) OR expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_OR, L, R);}
+expr(C) ::= expr(L) CONCAT expr(R). {C = compose_multiple_expr (GDA_SQL_OPERATOR_CONCAT, L, R);}
+
+expr(C) ::= expr(L) GT|LEQ|GEQ|LT(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);}
+expr(C) ::= expr(L) DIFF|EQ(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);}
+expr(C) ::= expr(L) LIKE expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_LIKE, L, R);}
+expr(C) ::= expr(L) REGEXP|REGEXP_CI|NOT_REGEXP|NOT_REGEXP_CI|SIMILAR(O) expr(R). {C = create_two_expr (string_to_op_type (O), L, R);}
+expr(C) ::= expr(L) BETWEEN expr(R) AND expr(E). {GdaSqlOperation *cond;
+ C = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (C));
+ C->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_BETWEEN;
+ cond->operands = g_slist_append (NULL, L);
+ GDA_SQL_ANY_PART (L)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_append (cond->operands, R);
+ GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_append (cond->operands, E);
+ GDA_SQL_ANY_PART (E)->parent = GDA_SQL_ANY_PART (cond);
+}
+
+expr(C) ::= expr(L) NOT BETWEEN expr(R) AND expr(E). {GdaSqlOperation *cond;
+ GdaSqlExpr *expr;
+ expr = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
+ expr->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_BETWEEN;
+ cond->operands = g_slist_append (NULL, L);
+ GDA_SQL_ANY_PART (L)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_append (cond->operands, R);
+ GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_append (cond->operands, E);
+ GDA_SQL_ANY_PART (E)->parent = GDA_SQL_ANY_PART (cond);
+
+ C = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (C));
+ C->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_NOT;
+ cond->operands = g_slist_prepend (NULL, expr);
+ GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond);
+}
+
+expr(C) ::= NOT expr(R). {C = create_uni_expr (GDA_SQL_OPERATOR_NOT, R);}
+expr(C) ::= BITNOT expr(R). {C = create_uni_expr (GDA_SQL_OPERATOR_BITNOT, R);}
+expr(C) ::= expr(R) uni_op(O) . {C = create_uni_expr (O, R);}
+
+expr(C) ::= expr(L) IS expr(R). {C = create_two_expr (GDA_SQL_OPERATOR_IS, L, R);}
+expr(E) ::= LP compound(S) RP. {E = gda_sql_expr_new (NULL); gda_sql_expr_take_select (E, S);}
+expr(E) ::= expr(R) IN LP exprlist(L) RP. {GdaSqlOperation *cond;
+ GSList *list;
+ E = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E));
+ E->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_IN;
+ cond->operands = g_slist_prepend (L, R);
+ for (list = cond->operands; list; list = list->next)
+ GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond);
+}
+expr(E) ::= expr(R) IN LP compound(S) RP. {GdaSqlOperation *cond;
+ GdaSqlExpr *expr;
+ E = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E));
+ E->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_IN;
+
+ expr = gda_sql_expr_new (GDA_SQL_ANY_PART (cond));
+ gda_sql_expr_take_select (expr, S);
+ cond->operands = g_slist_prepend (NULL, expr);
+ cond->operands = g_slist_prepend (cond->operands, R);
+ GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond);
+}
+expr(E) ::= expr(R) NOT IN LP exprlist(L) RP. {GdaSqlOperation *cond;
+ GdaSqlExpr *expr;
+ GSList *list;
+ expr = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr));
+ expr->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_IN;
+ cond->operands = g_slist_prepend (L, R);
+ for (list = cond->operands; list; list = list->next)
+ GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (cond);
+
+ E = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E));
+ E->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_NOT;
+ cond->operands = g_slist_prepend (NULL, expr);
+ GDA_SQL_ANY_PART (expr)->parent = GDA_SQL_ANY_PART (cond);
+}
+expr(E) ::= expr(R) NOT IN LP compound(S) RP. {GdaSqlOperation *cond;
+ GdaSqlExpr *expr1, *expr2;
+ expr1 = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (expr1));
+ expr1->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_IN;
+
+ expr2 = gda_sql_expr_new (NULL);
+ gda_sql_expr_take_select (expr2, S);
+ cond->operands = g_slist_prepend (NULL, expr2);
+ GDA_SQL_ANY_PART (expr2)->parent = GDA_SQL_ANY_PART (cond);
+ cond->operands = g_slist_prepend (cond->operands, R);
+ GDA_SQL_ANY_PART (R)->parent = GDA_SQL_ANY_PART (cond);
+
+ E = gda_sql_expr_new (NULL);
+ cond = gda_sql_operation_new (GDA_SQL_ANY_PART (E));
+ E->cond = cond;
+ cond->operator = GDA_SQL_OPERATOR_NOT;
+ cond->operands = g_slist_prepend (NULL, expr1);
+ GDA_SQL_ANY_PART (expr1)->parent = GDA_SQL_ANY_PART (cond);
+}
+expr(A) ::= CASE case_operand(X) case_exprlist(Y) case_else(Z) END. {
+ GdaSqlCase *sc;
+ GSList *list;
+ A = gda_sql_expr_new (NULL);
+ sc = gda_sql_case_new (GDA_SQL_ANY_PART (A));
+ sc->base_expr = X;
+ sc->else_expr = Z;
+ sc->when_expr_list = Y.when_list;
+ sc->then_expr_list = Y.then_list;
+ A->case_s = sc;
+ for (list = sc->when_expr_list; list; list = list->next)
+ GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc);
+ for (list = sc->then_expr_list; list; list = list->next)
+ GDA_SQL_ANY_PART (list->data)->parent = GDA_SQL_ANY_PART (sc);
+}
+
+%type case_operand {GdaSqlExpr*}
+%destructor case_operand {gda_sql_expr_free ($$);}
+case_operand(A) ::= expr(X). {A = X;}
+case_operand(A) ::= . {A = NULL;}
+
+%type case_exprlist {CaseBody}
+%destructor case_exprlist {g_slist_foreach ($$.when_list, (GFunc) gda_sql_expr_free, NULL); g_slist_free ($$.when_list);
+ g_slist_foreach ($$.then_list, (GFunc) gda_sql_expr_free, NULL); g_slist_free ($$.then_list);}
+
+case_exprlist(A) ::= case_exprlist(X) WHEN expr(Y) THEN expr(Z). {
+ A.when_list = g_slist_append (X.when_list, Y);
+ A.then_list = g_slist_append (X.then_list, Z);
+}
+case_exprlist(A) ::= WHEN expr(Y) THEN expr(Z). {
+ A.when_list = g_slist_prepend (NULL, Y);
+ A.then_list = g_slist_prepend (NULL, Z);
+}
+
+%type case_else {GdaSqlExpr*}
+%destructor case_else {gda_sql_expr_free ($$);}
+case_else(A) ::= ELSE expr(X). {A = X;}
+case_else(A) ::= . {A = NULL;}
+
+%type uni_op {GdaSqlOperator}
+uni_op(O) ::= ISNULL. {O = GDA_SQL_OPERATOR_ISNULL;}
+uni_op(O) ::= IS NOTNULL. {O = GDA_SQL_OPERATOR_ISNOTNULL;}
+
+
+// Values: for all constants (G_TYPE_STRING GValue)
+value(V) ::= NULL. {V = NULL;}
+value(V) ::= STRING(S). {V = S;}
+value(V) ::= TEXTUAL(T). {V = T;}
+value(V) ::= INTEGER(I). {V = I;}
+value(V) ::= FLOAT(F). {V = F;}
+
+// pvalue: values which are parameters (GdaSqlExpr)
+%type pvalue {GdaSqlExpr *}
+%destructor pvalue {gda_sql_expr_free ($$);}
+ pvalue(E) ::= UNSPECVAL LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->param_spec = P;}
+pvalue(E) ::= value(V) LSBRACKET paramspec(P) RSBRACKET. {E = gda_sql_expr_new (NULL); E->value = V; E->param_spec = P;}
+pvalue(E) ::= SIMPLEPARAM(S). {E = gda_sql_expr_new (NULL); E->param_spec = gda_sql_param_spec_new (S);}
+
+// paramspec: parameter's specifications
+%type paramspec {GdaSqlParamSpec *}
+%destructor paramspec {gda_sql_param_spec_free ($$);}
+paramspec(P) ::= . {P = NULL;}
+paramspec(P) ::= paramspec(E) PNAME(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E;
+ gda_sql_param_spec_take_name (P, N);}
+paramspec(P) ::= paramspec(E) PDESCR(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E;
+ gda_sql_param_spec_take_descr (P, N);}
+paramspec(P) ::= paramspec(E) PTYPE(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E;
+ gda_sql_param_spec_take_type (P, N);}
+paramspec(P) ::= paramspec(E) PNULLOK(N). {if (!E) P = gda_sql_param_spec_new (NULL); else P = E;
+ gda_sql_param_spec_take_nullok (P, N);}
+
+// The name of a column or table can be any of the following:
+//
+nm(A) ::= JOIN(X). {A = X;}
+nm(A) ::= ID(X). {A = X;}
+
+// Fully qualified name
+fullname(A) ::= nm(X). {A = X;}
+fullname(A) ::= nm(S) DOT nm(X). {gchar *str;
+ str = g_strdup_printf ("%s.%s", g_value_get_string (S), g_value_get_string (X));
+ A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_take_string (A, str);
+ g_value_reset (S); g_free (S);
+ g_value_reset (X); g_free (X);
+}
+
+fullname(A) ::= nm(C) DOT nm(S) DOT nm(X). {gchar *str;
+ str = g_strdup_printf ("%s.%s.%s", g_value_get_string (C),
+ g_value_get_string (S), g_value_get_string (X));
+ A = g_new0 (GValue, 1);
+ g_value_init (A, G_TYPE_STRING);
+ g_value_take_string (A, str);
+ g_value_reset (C); g_free (C);
+ g_value_reset (S); g_free (S);
+ g_value_reset (X); g_free (X);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]