libgda r3159 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser po providers/mysql providers/postgres testing
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3159 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser po providers/mysql providers/postgres testing
- Date: Wed, 4 Jun 2008 20:35:49 +0000 (UTC)
Author: vivien
Date: Wed Jun 4 20:35:49 2008
New Revision: 3159
URL: http://svn.gnome.org/viewvc/libgda?rev=3159&view=rev
Log:
2008-06-04 Vivien Malerba <malerba gnome-db org>
* po/POTFILES.in:
* po/POTFILES.skip: updated lists of files
* libgda/gda-connection.h: added GDA_CONNECTION_FEATURE_XA_TRANSACTIONS
* testing/html.[ch]:
* testing/Makefile.am:
* testing/gda-provider-status.c: new program to report about the
implementation of database providers (generates an HTML report)
this program is not installed by 'make install'
* providers/mysql: more work on the MySQL provider (thanks to Carlos
Savoretti)
2008-06-04 Johannes Schmid <jhs gnome org>
* libgda/sql-parser/Makefile.am:
Added rules to generate gda-sql-parser-enum-types.[ch]
Added:
trunk/testing/gda-provider-status.c
trunk/testing/html.c
trunk/testing/html.h
Modified:
trunk/ChangeLog
trunk/doc/C/ (props changed)
trunk/doc/C/tmpl/ (props changed)
trunk/doc/C/tmpl/gda-connection.sgml
trunk/libgda/gda-config.c
trunk/libgda/gda-connection.h
trunk/libgda/sql-parser/ (props changed)
trunk/libgda/sql-parser/Makefile.am
trunk/po/POTFILES.in
trunk/po/POTFILES.skip
trunk/providers/mysql/gda-mysql-meta.c
trunk/providers/mysql/gda-mysql-provider.c
trunk/providers/mysql/gda-mysql-pstmt.c
trunk/providers/mysql/gda-mysql-pstmt.h
trunk/providers/mysql/gda-mysql-recordset.c
trunk/providers/mysql/gda-mysql-recordset.h
trunk/providers/mysql/gda-mysql-util.c
trunk/providers/mysql/gda-mysql-util.h
trunk/providers/mysql/libmain.c
trunk/providers/postgres/gda-postgres-provider.c
trunk/testing/ (props changed)
trunk/testing/Makefile.am
Modified: trunk/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection.sgml (original)
+++ trunk/doc/C/tmpl/gda-connection.sgml Wed Jun 4 20:35:49 2008
@@ -492,6 +492,7 @@
@GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR:
@GDA_CONNECTION_FEATURE_USERS:
@GDA_CONNECTION_FEATURE_VIEWS:
+ GDA_CONNECTION_FEATURE_XA_TRANSACTIONS:
@GDA_CONNECTION_FEATURE_LAST:
<!-- ##### FUNCTION gda_connection_supports_feature ##### -->
Modified: trunk/libgda/gda-config.c
==============================================================================
--- trunk/libgda/gda-config.c (original)
+++ trunk/libgda/gda-config.c Wed Jun 4 20:35:49 2008
@@ -1063,7 +1063,8 @@
* @error: a place to store errors, or %NULL
*
* Get a pointer to the session-wide #GdaServerProvider for the
- * provider named @provider_name
+ * provider named @provider_name. The caller must not call g_object_unref() on the
+ * returned object.
*
* Returns: a pointer to the #GdaServerProvider, or %NULL if an error occurred
*/
Modified: trunk/libgda/gda-connection.h
==============================================================================
--- trunk/libgda/gda-connection.h (original)
+++ trunk/libgda/gda-connection.h Wed Jun 4 20:35:49 2008
@@ -98,6 +98,7 @@
GDA_CONNECTION_FEATURE_UPDATABLE_CURSOR,
GDA_CONNECTION_FEATURE_USERS,
GDA_CONNECTION_FEATURE_VIEWS,
+ GDA_CONNECTION_FEATURE_XA_TRANSACTIONS,
GDA_CONNECTION_FEATURE_LAST
} GdaConnectionFeature;
Modified: trunk/libgda/sql-parser/Makefile.am
==============================================================================
--- trunk/libgda/sql-parser/Makefile.am (original)
+++ trunk/libgda/sql-parser/Makefile.am Wed Jun 4 20:35:49 2008
@@ -37,13 +37,50 @@
gda-statement-struct-unknown.h \
gda-statement-struct-util.h
+gda-sql-parser-enum-types.h: s-enum-types-h
+ @true
+
+s-enum-types-h: @REBUILD@ $(libgda_sql_parser_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#ifndef __LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n#define __LIBGDA_SQL_PARSER_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \
+ --fprod "/* enumerations from \"@filename \" */\n" \
+ --vhead "GType @enum_name _get_type (void);\n#define GDA_SQL_PARSER_TYPE_ ENUMSHORT@ (@enum_name _get_type())\n" \
+ --ftail "G_END_DECLS\n\n#endif /* __LIBGDA_ENUM_TYPES_H__ */" \
+ $(libgda_sql_parser_headers)) > tmp-gda-enum-types.h \
+ && (cmp -s tmp-gda-enum-types.h gda-sql-parser-enum-types.h || cp tmp-gda-enum-types.h gda-sql-parser-enum-types.h ) \
+ && rm -f tmp-gda-enum-types.h \
+ && echo timestamp > $(@F)
+
+gda-sql-parser-enum-types.c: s-enum-types-c
+ @true
+
+s-enum-types-c: @REBUILD@ $(libgda_sql_parser_headers) Makefile
+ ( cd $(srcdir) && glib-mkenums \
+ --fhead "#include <sql-parser/gda-sql-parser.h>\n" \
+ --fhead "#include <sql-parser/gda-sql-statement.h>\n" \
+ --fhead "#include <glib-object.h>" \
+ --fprod "\n/* enumerations from \"@filename \" */" \
+ --vhead "GType\n enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G Type@Value values[] = {" \
+ --vprod " { @VALUENAME@, \"@VALUENAME \", \"@valuenick \" }," \
+ --vtail " { 0, NULL, NULL }\n };\n etype = g_ type@_register_static (\"@EnumName \", values);\n }\n return etype;\n}\n" \
+ $(libgda_sql_parser_headers)) > tmp-gda-enum-types.c \
+ && (cmp -s tmp-gda-enum-types.c gda-sql-parser-enum-types.c || cp tmp-gda-enum-types.c gda-sql-parser-enum-types.c ) \
+ && rm -f tmp-gda-enum-types.c \
+ && echo timestamp > $(@F)
+
+# Generate the enums source code, with glib-mkenums:
+# This is based on the same Makefile.am stuff in pango:
+libgda_sql_parser_built_headers = gda-sql-parser-enum-types.h
+libgda_sql_parser_built_cfiles = gda-sql-parser-enum-types.c
$(OBJECTS) $(libgda_sql_parser_4_0_la_OBJECTS): token_types.h
libgda_sql_parserincludedir=$(includedir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/sql-parser
-libgda_sql_parserinclude_HEADERS=$(libgda_sql_parser_headers)
+libgda_sql_parserinclude_HEADERS=$(libgda_sql_parser_headers) $(libgda_sql_parser_built_headers)
libgda_sql_parser_4_0_la_SOURCES = \
$(libgda_sql_parser_headers) \
+ $(libgda_sql_parser_built_headers) \
+ $(libgda_sql_parser_built_cfiles) \
gda-sql-parser-private.h \
parser.c \
parser.h \
@@ -66,4 +103,9 @@
EXTRA_DIST= parser.y delimiter.y lemon.c lempar.c gen_def.c parser_tokens.h
CLEANFILES = parser.h parser.c parser.out delimiter.h delimiter.c delimiter.out token_types.h \
- lemon$(EXEEXT_FOR_BUILD) gen_def$(EXEEXT_FOR_BUILD)
+ lemon$(EXEEXT_FOR_BUILD) gen_def$(EXEEXT_FOR_BUILD) \
+ $(libgda_sql_parser_built_headers) $(libgda_sql_parser_built_cfiles) \
+ gda-enum-types.h \
+ s-enum-types-h \
+ gda-enum-types.c \
+ s-enum-types-c
Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in (original)
+++ trunk/po/POTFILES.in Wed Jun 4 20:35:49 2008
@@ -26,6 +26,7 @@
libgda/gda-statement.c
libgda/gda-util.c
libgda/gda-value.c
+libgda/gda-xa-transaction.c
libgda/handlers/gda-handler-bin.c
libgda/handlers/gda-handler-boolean.c
libgda/handlers/gda-handler-numerical.c
Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip (original)
+++ trunk/po/POTFILES.skip Wed Jun 4 20:35:49 2008
@@ -2,6 +2,39 @@
libgda/sqlite/sql-parser.c/lemon.c
libgda/sqlite/sql-parser.c/lempar.c
libgda/sqlite/sqlite-src/sqlite3.c
+providers/firebird/firebird_specs_dsn.xml.in
+providers/firebird/gda-firebird-blob-op.c
+providers/firebird/gda-firebird-provider.c
+providers/firebird/gda-firebird-recordset.c
+providers/firebird/libmain.c
+providers/freetds/freetds_specs_dsn.xml.in
+providers/freetds/gda-freetds-provider.c
+providers/freetds/gda-freetds-recordset.c
+providers/freetds/libmain.c
+providers/freetds/utils.c
+providers/ibmdb2/gda-ibmdb2-provider.c
+providers/ibmdb2/gda-ibmdb2-types.c
+providers/ibmdb2/ibmdb2_specs_dsn.xml.in
+providers/ibmdb2/libmain.c
+providers/ldap/gda-ldap-provider.c
+providers/ldap/gda-ldap-recordset.c
+providers/ldap/ldap_specs_dsn.xml.in
+providers/ldap/libmain.c
+providers/msql/gda-msql-provider.c
+providers/msql/gda-msql-recordset.c
+providers/msql/libmain.c
+providers/msql/msql_specs_dsn.xml.in
+providers/odbc/gda-odbc-provider.c
+providers/odbc/libmain.c
+providers/odbc/odbc_specs_dsn.xml.in
+providers/oracle/gda-oracle-blob-op.c
+providers/oracle/gda-oracle-provider.c
+providers/oracle/gda-oracle-recordset.c
+providers/oracle/libmain.c
+providers/oracle/oracle_specs_drop_index.xml.in
+providers/oracle/oracle_specs_drop_table.xml.in
+providers/oracle/oracle_specs_dsn.xml.in
+providers/oracle/utils.c
providers/skel-implementation/capi/capi_specs_create_table.xml.in
providers/skel-implementation/capi/capi_specs_dsn.xml.in
providers/skel-implementation/capi/gda-capi-blob-op.c
@@ -14,4 +47,13 @@
providers/skel-implementation/models/gda-models-provider.c
providers/skel-implementation/models/libmain.c
providers/skel-implementation/models/models_specs_dsn.xml.in
+providers/sybase/gda-sybase-provider.c
+providers/sybase/gda-sybase-recordset.c
+providers/sybase/gda-sybase-types.c
+providers/sybase/libmain.c
providers/sybase/main.c
+providers/sybase/sybase_specs_dsn.xml.in
+providers/sybase/utils.c
+providers/xbase/gda-xbase-provider.c
+providers/xbase/libmain.c
+providers/xbase/xbase_specs_dsn.xml.in
Modified: trunk/providers/mysql/gda-mysql-meta.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-meta.c (original)
+++ trunk/providers/mysql/gda-mysql-meta.c Wed Jun 4 20:35:49 2008
@@ -44,6 +44,7 @@
typedef enum {
I_STMT_CATALOG,
I_STMT_BTYPES,
+ I_STMT_SCHEMAS_ALL,
} InternalStatementItem;
@@ -60,6 +61,7 @@
/* I_STMT_SCHEMAS */
/* I_STMT_SCHEMAS_ALL */
+ "SELECT catalog_name, schema_name, 'mysql', CASE schema_name WHEN 'information_schema' THEN TRUE WHEN 'mysql' THEN TRUE ELSE FALSE END FROM information_schema.schemata",
/* I_STMT_SCHEMA_NAMED */
@@ -170,15 +172,16 @@
GdaMetaContext *context,
GError **error)
{
+ g_print ("*** %s\n", __func__);
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);
+ if (model == NULL)
+ retval = FALSE;
+ else {
+ retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
+ g_object_unref (G_OBJECT(model));
+ }
return retval;
}
@@ -191,20 +194,20 @@
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
};
+ GdaDataModel *model;
+ gboolean retval;
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)
+ if (model == NULL)
+ retval = FALSE;
+ else {
retval = gda_meta_store_modify (store, context->table_name, model, NULL, error, NULL);
- g_object_unref (G_OBJECT(model));
+ g_object_unref (G_OBJECT(model));
+ }
return retval;
}
@@ -229,23 +232,26 @@
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;
+ /* /\* 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); */
+ /* GdaDataModel *model; */
+ /* gboolean retval; */
+ /* /\* fill in @model, with something like: */
+ /* * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error); */
+ /* *\/ */
+ /* if (model == NULL) */
+ /* retval = FALSE; */
+ /* else { */
+ /* retval = gda_meta_store_modify_with_context (store, context, model, error); */
+ /* g_object_unref (G_OBJECT(model)); */
+ /* } */
+
+ /* return retval; */
+ return TRUE;
}
@@ -361,16 +367,6 @@
}
gboolean
-_gda_mysql_meta_el_types (GdaServerProvider *prov, GdaConnection *cnc,
- GdaMetaStore *store, GdaMetaContext *context, GError **error,
- const GValue *specific_name)
-{
- TO_IMPLEMENT;
- return TRUE;
-}
-
-
-gboolean
_gda_mysql_meta__collations (GdaServerProvider *prov,
GdaConnection *cnc,
GdaMetaStore *store,
@@ -427,8 +423,20 @@
GdaMetaContext *context,
GError **error)
{
- TO_IMPLEMENT;
- return TRUE;
+ g_print ("*** %s\n", __func__);
+ // TO_IMPLEMENT;
+
+ GdaDataModel *model;
+ gboolean retval;
+ model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_SCHEMAS_ALL], i_set, error);
+ if (model == NULL)
+ retval = FALSE;
+ else {
+ retval = gda_meta_store_modify_with_context (store, context, model, error);
+ g_object_unref (G_OBJECT(model));
+ }
+
+ return retval;
}
gboolean
Modified: trunk/providers/mysql/gda-mysql-provider.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-provider.c (original)
+++ trunk/providers/mysql/gda-mysql-provider.c Wed Jun 4 20:35:49 2008
@@ -158,6 +158,36 @@
GdaServerProviderAsyncCallback async_cb,
gpointer cb_data,
GError **error);
+//
+
+/* distributed transactions */
+static gboolean gda_mysql_provider_xa_start (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error);
+
+static gboolean gda_mysql_provider_xa_end (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error);
+static gboolean gda_mysql_provider_xa_prepare (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error);
+
+static gboolean gda_mysql_provider_xa_commit (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error);
+static gboolean gda_mysql_provider_xa_rollback (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error);
+
+static GList *gda_mysql_provider_xa_recover (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GError **error);
+//
/*
* private connection data destroy
@@ -238,7 +268,6 @@
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.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;
@@ -267,6 +296,17 @@
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;
+ //
+
+ /* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
+ provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
+ provider_class->xa_funcs->xa_start = gda_mysql_provider_xa_start;
+ provider_class->xa_funcs->xa_end = gda_mysql_provider_xa_end;
+ provider_class->xa_funcs->xa_prepare = gda_mysql_provider_xa_prepare;
+ provider_class->xa_funcs->xa_commit = gda_mysql_provider_xa_commit;
+ provider_class->xa_funcs->xa_rollback = gda_mysql_provider_xa_rollback;
+ provider_class->xa_funcs->xa_recover = gda_mysql_provider_xa_recover;
+ //
}
static void
@@ -489,19 +529,19 @@
(use_ssl != NULL) ? TRUE : FALSE,
&error);
if (!mysql) {
- _gda_mysql_make_error (cnc, mysql, NULL);
+ _gda_mysql_make_error (cnc, mysql, NULL, NULL);
return FALSE;
}
MYSQL_STMT *mysql_stmt = mysql_stmt_init (mysql);
if (!mysql_stmt) {
- _gda_mysql_make_error (cnc, mysql, NULL);
+ _gda_mysql_make_error (cnc, NULL, mysql_stmt, 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);
+ _gda_mysql_make_error (cnc, NULL, mysql_stmt, NULL);
return FALSE;
}
@@ -1155,7 +1195,7 @@
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);
+ GDA_STATEMENT_SQL_PARAMS_AS_UQMARK, &used_set, error);
if (!sql)
@@ -1163,7 +1203,7 @@
if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
GdaConnectionEvent *event = _gda_mysql_make_error
- (cdata->cnc, cdata->mysql, NULL);
+ (cdata->cnc, NULL, cdata->mysql_stmt, NULL);
goto cleanup;
}
@@ -1224,7 +1264,7 @@
if (mysql_stmt_prepare (cdata->mysql_stmt, sql, strlen (sql))) {
GdaConnectionEvent *event = _gda_mysql_make_error
- (cdata->cnc, cdata->mysql, NULL);
+ (cdata->cnc, NULL, cdata->mysql_stmt, NULL);
ps = NULL;
} else {
ps = gda_mysql_pstmt_new (cdata->cnc, cdata->mysql, cdata->mysql_stmt);
@@ -1310,6 +1350,9 @@
/* optionnally reset the prepared statement if required by the API */
// TO_IMPLEMENT;
+ //
+ g_print (" %s: SQL=%s\n", __func__, _GDA_PSTMT(ps)->sql);
+ //
/* bind statement's parameters */
GSList *list;
GdaConnectionEvent *event = NULL;
@@ -1319,15 +1362,13 @@
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);
+ g_print ("NB=%d, SQL=%s\n", nb_params, _GDA_PSTMT(ps)->sql);
+
+ MYSQL_BIND *mysql_bind_param = g_new0 (MYSQL_BIND, nb_params);
- for (i = 1, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
+ for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
const gchar *pname = (gchar *) list->data;
- GdaHolder *h;
-
- g_print ("PNAME=%s\n", pname);
- //
/* find requested parameter */
if (!params) {
event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
@@ -1338,7 +1379,7 @@
break;
}
- h = gda_set_get_holder (params, pname);
+ GdaHolder *h = gda_set_get_holder (params, pname);
if (!h) {
gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
if (tmp) {
@@ -1359,11 +1400,58 @@
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
- TO_IMPLEMENT;
+ // TO_IMPLEMENT;
+
+ if (value == NULL || gda_value_is_null (value)) {
+ param_values[i] = NULL;
+ } else if ((G_VALUE_TYPE(value) == G_TYPE_DATE) ||
+ (G_VALUE_TYPE(value) == GDA_TYPE_TIME) ||
+ (G_VALUE_TYPE(value) == GDA_TYPE_TIMESTAMP)) {
+ //
+ GdaHandlerTime *handler_time = (GdaHandlerTime *) gda_server_provider_get_data_handler_gtype
+ (provider, cnc, G_VALUE_TYPE(value));
+ g_assert (handler_time);
+ param_values[i] = gda_handler_time_get_no_locale_str_from_value (handler_time,
+ value);
+ //
+ g_print ("--- TIME=%s\n", param_values[i]);
+ } else {
+ GdaDataHandler *data_handler = gda_server_provider_get_data_handler_gtype
+ (provider, cnc, G_VALUE_TYPE(value));
+ if (data_handler == NULL)
+ param_values[i] = NULL;
+ else
+ param_values[i] = gda_data_handler_get_str_from_value (data_handler,
+ value);
+ g_print ("--- PV=%s\n", param_values[i]);
+
+ mysql_bind_param[i].buffer_type = MYSQL_TYPE_STRING;
+ mysql_bind_param[i].buffer = g_strdup (param_values[i]);
+ mysql_bind_param[i].buffer_length = strlen (param_values[i]);
+ mysql_bind_param[i].length = g_malloc0 (sizeof(unsigned long));
+
+ }
+ //
+ gchar *str = gda_value_stringify (value);
+ g_print (" %s: %s=%s\n", __func__, pname, str);
+ g_free (str);
+ //
+
}
+ if (mysql_stmt_bind_param (cdata->mysql_stmt, mysql_bind_param)) {
+ g_warning ("mysql_stmt_bind_param failed: %s\n", mysql_stmt_error (cdata->mysql_stmt));
+ }
+
+ ps->mysql_bind_param = mysql_bind_param;
+
if (event) {
gda_connection_add_event (cnc, event);
+
+ g_strfreev (param_values);
+ g_free (param_lengths);
+ g_free (param_formats);
+
return NULL;
}
@@ -1375,7 +1463,7 @@
GObject *return_value = NULL;
if (mysql_stmt_execute (cdata->mysql_stmt)) {
- event = _gda_mysql_make_error (cnc, cdata->mysql, error);
+ event = _gda_mysql_make_error (cnc, NULL, cdata->mysql_stmt, error);
} else {
//
/* execute prepared statement using C API depending on its kind */
@@ -1385,7 +1473,7 @@
!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);
+ _gda_mysql_make_error (cnc, NULL, cdata->mysql_stmt, error);
} else {
GdaDataModelAccessFlags flags;
@@ -1431,6 +1519,152 @@
}
/*
+ * starts a distributed transaction: put the XA transaction in the ACTIVE state
+ */
+static gboolean
+gda_mysql_provider_xa_start (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ 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 (xid, FALSE);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
+ * This state is required by some database providers before actually going to the PREPARED state
+ */
+static gboolean
+gda_mysql_provider_xa_end (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ 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 (xid, FALSE);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * prepares the distributed transaction: put the XA transaction in the PREPARED state
+ */
+static gboolean
+gda_mysql_provider_xa_prepare (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ 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 (xid, FALSE);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * commits the distributed transaction: actually write the prepared data to the database and
+ * terminates the XA transaction
+ */
+static gboolean
+gda_mysql_provider_xa_commit (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ 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 (xid, FALSE);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
+ */
+static gboolean
+gda_mysql_provider_xa_rollback (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ const GdaXaTransactionId *xid,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ 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 (xid, FALSE);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return FALSE;
+
+ TO_IMPLEMENT;
+ return FALSE;
+}
+
+/*
+ * Lists all XA transactions that are in the PREPARED state
+ *
+ * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
+ */
+static GList *
+gda_mysql_provider_xa_recover (GdaServerProvider *provider,
+ GdaConnection *cnc,
+ GError **error)
+{
+ g_print ("*** %s\n", __func__);
+ MysqlConnectionData *cdata;
+
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider_obj (cnc) == provider, NULL);
+
+ cdata = (MysqlConnectionData*) gda_connection_internal_get_provider_data (cnc);
+ if (!cdata)
+ return NULL;
+
+ TO_IMPLEMENT;
+ return NULL;
+}
+
+/*
* Free connection's specific data
*/
static void
Modified: trunk/providers/mysql/gda-mysql-pstmt.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-pstmt.c (original)
+++ trunk/providers/mysql/gda-mysql-pstmt.c Wed Jun 4 20:35:49 2008
@@ -2,7 +2,7 @@
* Copyright (C) 2008 The GNOME Foundation.
*
* AUTHORS:
- * TO_ADD: your name and email
+ * 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
@@ -82,6 +82,10 @@
/* initialize specific parts of @pstmt */
// TO_IMPLEMENT;
+ //
+ pstmt->mysql_bind_param = NULL;
+ pstmt->mysql_bind_result = NULL;
+ //
}
static void
@@ -94,6 +98,23 @@
/* free memory */
// TO_IMPLEMENT; /* free some specific parts of @pstmt */
+ //
+ gint i;
+ for (i = 0; i < g_slist_length (((GdaPStmt *) pstmt)->param_ids); ++i) {
+ g_free (pstmt->mysql_bind_param[i].buffer);
+ g_free (pstmt->mysql_bind_param[i].length);
+ }
+ g_free (pstmt->mysql_bind_param);
+ pstmt->mysql_bind_param = NULL;
+
+ for (i = 0; i < ((GdaPStmt *) pstmt)->ncols; ++i) {
+ g_free (pstmt->mysql_bind_result[i].buffer);
+ g_free (pstmt->mysql_bind_result[i].is_null);
+ g_free (pstmt->mysql_bind_result[i].length);
+ }
+ g_free (pstmt->mysql_bind_result);
+ pstmt->mysql_bind_result = NULL;
+ //
/* chain to parent class */
parent_class->finalize (object);
Modified: trunk/providers/mysql/gda-mysql-pstmt.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-pstmt.h (original)
+++ trunk/providers/mysql/gda-mysql-pstmt.h Wed Jun 4 20:35:49 2008
@@ -43,6 +43,8 @@
GdaConnection *cnc;
MYSQL *mysql;
MYSQL_STMT *mysql_stmt;
+ MYSQL_BIND *mysql_bind_param;
+ MYSQL_BIND *mysql_bind_result;
};
Modified: trunk/providers/mysql/gda-mysql-recordset.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.c (original)
+++ trunk/providers/mysql/gda-mysql-recordset.c Wed Jun 4 20:35:49 2008
@@ -83,7 +83,6 @@
/* 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. */
@@ -218,16 +217,6 @@
/* 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;
}
@@ -277,9 +266,6 @@
MysqlConnectionData *cdata;
gint i;
GdaDataModelAccessFlags rflags;
-
- MYSQL_BIND *mysql_bind = NULL;
-
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (ps != NULL, NULL);
@@ -326,7 +312,7 @@
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);
+ MYSQL_BIND *mysql_bind_result = g_new0 (MYSQL_BIND, GDA_PSTMT (ps)->ncols);
//
/* fill GdaColumn's data */
for (i=0, list = _GDA_PSTMT (ps)->tmpl_columns;
@@ -365,19 +351,19 @@
*/
- mysql_bind[i].buffer_type = field->type;
- switch (mysql_bind[i].buffer_type) {
+ mysql_bind_result[i].buffer_type = field->type;
+ switch (mysql_bind_result[i].buffer_type) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_YEAR:
- mysql_bind[i].buffer = g_malloc0 (sizeof(int));
- mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+ mysql_bind_result[i].buffer = g_malloc0 (sizeof(int));
+ mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
break;
case MYSQL_TYPE_LONGLONG:
- mysql_bind[i].buffer = g_malloc0 (sizeof(long long));
- mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+ mysql_bind_result[i].buffer = g_malloc0 (sizeof(long long));
+ mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
break;
case MYSQL_TYPE_NULL:
break;
@@ -385,13 +371,13 @@
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- mysql_bind[i].buffer = g_malloc0 (sizeof(MYSQL_TIME));
- mysql_bind[i].is_null = g_malloc0 (sizeof(my_bool));
+ mysql_bind_result[i].buffer = g_malloc0 (sizeof(MYSQL_TIME));
+ mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
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));
+ mysql_bind_result[i].buffer = g_malloc0 (sizeof(double));
+ mysql_bind_result[i].is_null = g_malloc0 (sizeof(my_bool));
break;
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
@@ -401,23 +387,25 @@
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_BIT:
- 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));
+ mysql_bind_result[i].buffer = g_malloc0 (field->max_length + 1);
+ mysql_bind_result[i].buffer_length = field->max_length + 1;
+ mysql_bind_result[i].length = g_malloc0 (sizeof(unsigned long));
break;
default:
- g_warning (_("Invalid column bind data type.\n"),
- mysql_bind[i].buffer_type);
+ g_warning (_("Invalid column bind data type. %d\n"),
+ mysql_bind_result[i].buffer_type);
}
}
- if (mysql_stmt_bind_result (cdata->mysql_stmt, mysql_bind)) {
+ if (mysql_stmt_bind_result (cdata->mysql_stmt, mysql_bind_result)) {
g_warning ("mysql_stmt_bind_result failed: %s\n", mysql_stmt_error (cdata->mysql_stmt));
}
mysql_free_result (mysql_res);
-
+
+ ps->mysql_bind_result = mysql_bind_result;
+
}
/* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
@@ -437,9 +425,6 @@
/* post init specific code */
// TO_IMPLEMENT;
- if (mysql_bind != NULL)
- model->priv->mysql_bind = mysql_bind;
-
model->priv->mysql_stmt = cdata->mysql_stmt;
((GdaPModel *) model)->advertized_nrows = mysql_stmt_affected_rows (cdata->mysql_stmt);
@@ -479,19 +464,19 @@
g_print ("*** %s -- %d -- %d\n", __func__,
((GdaPModel *) imodel)->prep_stmt->ncols, rownum);
- MYSQL_BIND *mysql_bind = imodel->priv->mysql_bind;
- g_assert (mysql_bind);
+ MYSQL_BIND *mysql_bind_result = ((GdaMysqlPStmt *) ((GdaPModel *) imodel)->prep_stmt)->mysql_bind_result;
+ g_assert (mysql_bind_result);
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;
+ GValue *value = gda_prow_get_value (prow, i);
+ GType type = ((GdaPModel *) imodel)->prep_stmt->types[i];
+ gda_value_reset_with_type (value, type);
+
int intvalue = 0;
long long longlongvalue = 0;
double doublevalue = 0.0;
@@ -500,14 +485,14 @@
my_bool is_null;
unsigned long length;
- switch (mysql_bind[i].buffer_type) {
+ switch (mysql_bind_result[i].buffer_type) {
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_SHORT:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_YEAR:
- g_memmove (&intvalue, mysql_bind[i].buffer, sizeof(int));
- g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+ g_memmove (&intvalue, mysql_bind_result[i].buffer, sizeof(int));
+ g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
if (type == G_TYPE_INT)
g_value_set_int (value, intvalue);
@@ -521,8 +506,8 @@
}
break;
case MYSQL_TYPE_LONGLONG:
- g_memmove (&longlongvalue, mysql_bind[i].buffer, sizeof(long long));
- g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+ g_memmove (&longlongvalue, mysql_bind_result[i].buffer, sizeof(long long));
+ g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
break;
case MYSQL_TYPE_NULL:
g_value_unset (value);
@@ -531,8 +516,8 @@
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_TIMESTAMP:
- g_memmove (&timevalue, mysql_bind[i].buffer, sizeof(MYSQL_TIME));
- g_memmove (&is_null, mysql_bind[i].is_null, sizeof(my_bool));
+ g_memmove (&timevalue, mysql_bind_result[i].buffer, sizeof(MYSQL_TIME));
+ g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
if (type == GDA_TYPE_TIME) {
GdaTime time = {
@@ -566,8 +551,8 @@
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));
+ g_memmove (&doublevalue, mysql_bind_result[i].buffer, sizeof(double));
+ g_memmove (&is_null, mysql_bind_result[i].is_null, sizeof(my_bool));
setlocale (LC_NUMERIC, "C");
if (type == G_TYPE_FLOAT)
@@ -589,8 +574,8 @@
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_NEWDECIMAL:
case MYSQL_TYPE_BIT:
- g_memmove (&length, mysql_bind[i].length, sizeof(unsigned long));
- strvalue = g_memdup (mysql_bind[i].buffer, length + 1);
+ g_memmove (&length, mysql_bind_result[i].length, sizeof(unsigned long));
+ strvalue = g_memdup (mysql_bind_result[i].buffer, length + 1);
if (type == G_TYPE_STRING)
g_value_set_string (value, strvalue);
@@ -604,7 +589,7 @@
GdaBlob *blob = (GdaBlob *) gda_value_new_blob
((const guchar *) strvalue, (gulong) length);
gda_value_take_blob (value, blob);
- gda_value_free (blob);
+ gda_value_free ((GValue *) blob);
} else if (type == G_TYPE_DOUBLE) {
setlocale (LC_NUMERIC, "C");
g_value_set_double (value, atof (strvalue));
@@ -617,9 +602,13 @@
break;
default:
g_warning (_("Invalid column bind data type. %d\n"),
- mysql_bind[i].buffer_type);
+ mysql_bind_result[i].buffer_type);
}
-
+ //
+ gchar *str = gda_value_stringify (value);
+ g_print (" V=%s, %d\n", str, is_null);
+ g_free (str);
+ //
}
return prow;
}
@@ -670,7 +659,7 @@
gda_pmodel_take_row (model, *prow, rownum);
/* if (model->nb_stored_rows == model->advertized_nrows) { */
- /* g_print ("*** All the row have been converted..."); */
+ /* g_print (" All the row have been converted..."); */
/* } */
Modified: trunk/providers/mysql/gda-mysql-recordset.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-recordset.h (original)
+++ trunk/providers/mysql/gda-mysql-recordset.h Wed Jun 4 20:35:49 2008
@@ -48,9 +48,13 @@
GdaPModelClass parent_class;
};
-GType gda_mysql_recordset_get_type (void) G_GNUC_CONST;
-GdaDataModel *gda_mysql_recordset_new (GdaConnection *cnc, GdaMysqlPStmt *ps, GdaDataModelAccessFlags flags,
- GType *col_types);
+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
Modified: trunk/providers/mysql/gda-mysql-util.c
==============================================================================
--- trunk/providers/mysql/gda-mysql-util.c (original)
+++ trunk/providers/mysql/gda-mysql-util.c Wed Jun 4 20:35:49 2008
@@ -49,7 +49,8 @@
*/
GdaConnectionEvent *
_gda_mysql_make_error (GdaConnection *cnc,
- MYSQL *mysql, /* PGresult *pg_res, */
+ MYSQL *mysql,
+ MYSQL_STMT *mysql_stmt,
GError **error)
{
/* GdaConnectionEvent *error_ev; */
@@ -114,6 +115,19 @@
(event_error, mysql_errno (mysql));
g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
mysql_sqlstate (mysql));
+ //
+ g_print ("%s: %s\n", __func__, mysql_error (mysql));
+ //
+ } else if (mysql_stmt) {
+ gda_connection_event_set_description
+ (event_error, mysql_stmt_error (mysql_stmt));
+ gda_connection_event_set_code
+ (event_error, mysql_stmt_errno (mysql_stmt));
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_STATEMENT_EXEC_ERROR,
+ mysql_stmt_sqlstate (mysql_stmt));
+ //
+ g_print ("%s: %s\n", __func__, mysql_stmt_error (mysql_stmt));
+ //
} else {
gda_connection_event_set_description
(event_error, _("No description"));
Modified: trunk/providers/mysql/gda-mysql-util.h
==============================================================================
--- trunk/providers/mysql/gda-mysql-util.h (original)
+++ trunk/providers/mysql/gda-mysql-util.h Wed Jun 4 20:35:49 2008
@@ -31,6 +31,7 @@
GdaConnectionEvent *
_gda_mysql_make_error (GdaConnection *cnc,
MYSQL *mysql,
+ MYSQL_STMT *mysql_stmt,
GError **error);
/* int */
/* _gda_mysql_real_query_wrap (GdaConnection *cnc, */
Modified: trunk/providers/mysql/libmain.c
==============================================================================
--- trunk/providers/mysql/libmain.c (original)
+++ trunk/providers/mysql/libmain.c Wed Jun 4 20:35:49 2008
@@ -47,7 +47,7 @@
const gchar *
plugin_get_description (void)
{
- return _("Example provider for C API databases");
+ return _("Provider for MySQL databases");
}
gchar *
Modified: trunk/providers/postgres/gda-postgres-provider.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-provider.c (original)
+++ trunk/providers/postgres/gda-postgres-provider.c Wed Jun 4 20:35:49 2008
@@ -1416,6 +1416,7 @@
case GDA_CONNECTION_FEATURE_USERS:
case GDA_CONNECTION_FEATURE_VIEWS:
case GDA_CONNECTION_FEATURE_BLOBS:
+ case GDA_CONNECTION_FEATURE_XA_TRANSACTIONS:
return TRUE;
case GDA_CONNECTION_FEATURE_NAMESPACES:
if (cnc) {
Modified: trunk/testing/Makefile.am
==============================================================================
--- trunk/testing/Makefile.am (original)
+++ trunk/testing/Makefile.am Wed Jun 4 20:35:49 2008
@@ -5,7 +5,7 @@
$(LIBGDA_CFLAGS)
bin_PROGRAMS = gda-test-connection-4.0
-noinst_PROGRAMS = gda-test-blob
+noinst_PROGRAMS = gda-test-blob gda-provider-status
gda_test_connection_4_0_SOURCES = \
gda-test-connection.c
@@ -22,4 +22,13 @@
$(LIBGDA_LIBS)
+gda_provider_status_SOURCES = \
+ html.h \
+ html.c \
+ gda-provider-status.c
+
+gda_provider_status_LDADD = \
+ $(top_builddir)/libgda/libgda-4.0.la \
+ $(LIBGDA_LIBS)
+
EXTRA_DIST =
Added: trunk/testing/gda-provider-status.c
==============================================================================
--- (empty file)
+++ trunk/testing/gda-provider-status.c Wed Jun 4 20:35:49 2008
@@ -0,0 +1,475 @@
+/* GDA - provider status report
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ * Vivien Malerba <malerba gnome-db org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include "html.h"
+#include <libgda/gda-enum-types.h>
+
+/* options */
+gboolean ask_pass = FALSE;
+gchar *outfile = NULL;
+gchar *raw_prov = NULL;
+
+static GOptionEntry entries[] = {
+ { "no-password-ask", 'p', 0, G_OPTION_ARG_NONE, &ask_pass, "Don't ast for a password when it is empty", NULL },
+ { "prov", 'P', 0, G_OPTION_ARG_STRING, &raw_prov, "Provider to be used", NULL },
+ { "output-file", 'o', 0, G_OPTION_ARG_STRING, &outfile, "Output file", "output file"},
+ { NULL }
+};
+
+HtmlConfig *config;
+
+static GdaConnection *open_connection (const gchar *cnc_string, GError **error);
+static gboolean report_provider_status (GdaServerProvider *prov, GdaConnection *cnc);
+
+int
+main (int argc, char *argv[])
+{
+ GOptionContext *context;
+ GError *error = NULL;
+ int exit_status = EXIT_SUCCESS;
+ GSList *list, *cnc_list = NULL;
+ GdaServerProvider *prov = NULL;
+
+ context = g_option_context_new ("[DSN|connection string]...");
+ g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
+ if (!g_option_context_parse (context, &argc, &argv, &error)) {
+ g_print ("Can't parse arguments: %s\n", error->message);
+ exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+ g_option_context_free (context);
+ gda_init ();
+ ask_pass = !ask_pass;
+
+ config = g_new0 (HtmlConfig, 1);
+ html_init_config (HTML_CONFIG (config));
+ config->index = html_file_new (HTML_CONFIG (config),
+ "index.html", "Providers status");
+ config->dir = g_strdup (".");
+
+ if (raw_prov) {
+ prov = gda_config_get_provider_object (raw_prov, &error);
+ if (!prov) {
+ g_print ("Can't load the '%s' provider: %s\n", raw_prov,
+ error && error->message ? error->message : "No detail");
+ return EXIT_FAILURE;
+ }
+ if (!report_provider_status (prov, NULL)) {
+ exit_status = EXIT_FAILURE;
+ goto cleanup;
+
+ }
+ }
+
+ /* use connections if specified */
+ gint i;
+ for (i = 1; i < argc; i++) {
+ /* open connection */
+ GdaConnection *cnc;
+ cnc = open_connection (argv[i], &error);
+ if (!cnc) {
+ g_print ("Can't open connection to '%s': %s\n", argv[i],
+ error && error->message ? error->message : "No detail");
+ exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+ cnc_list = g_slist_append (cnc_list, cnc);
+ }
+ if (getenv ("GDA_SQL_CNC")) {
+ GdaConnection *cnc;
+ cnc = open_connection (getenv ("GDA_SQL_CNC"), &error);
+ if (!cnc) {
+ g_print ("Can't open connection defined by GDA_SQL_CNC: %s\n",
+ error && error->message ? error->message : "No detail");
+ exit_status = EXIT_FAILURE;
+ goto cleanup;
+ }
+ cnc_list = g_slist_append (cnc_list, cnc);
+ }
+
+
+ /* report provider's status for all the connections */
+ for (list = cnc_list; list; list = list->next) {
+ if (!report_provider_status (prov, GDA_CONNECTION (list->data))) {
+ exit_status = EXIT_FAILURE;
+ goto cleanup;
+
+ }
+ }
+
+ g_slist_foreach (HTML_CONFIG (config)->all_files, (GFunc) html_file_write, config);
+
+ /* cleanups */
+ cleanup:
+ g_slist_foreach (cnc_list, (GFunc) g_object_unref, NULL);
+ g_slist_free (cnc_list);
+
+ return exit_status;
+}
+
+
+/*
+ * Open a connection
+ */
+static GdaConnection*
+open_connection (const gchar *cnc_string, GError **error)
+{
+ GdaConnection *cnc = NULL;
+
+ GdaDataSourceInfo *info;
+ gchar *user, *pass, *real_cnc, *real_provider, *real_auth_string = NULL;
+ gda_connection_string_split (cnc_string, &real_cnc, &real_provider, &user, &pass);
+ if (!real_cnc) {
+ g_free (user);
+ g_free (pass);
+ g_free (real_provider);
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
+ "Malformed connection string '%s'", cnc_string);
+ return NULL;
+ }
+
+ if (ask_pass) {
+ if (user && !*user) {
+ gchar buf[80];
+ g_print ("\tUsername for '%s': ", cnc_string);
+ if (scanf ("%80s", buf) == -1) {
+ g_free (real_cnc);
+ g_free (user);
+ g_free (pass);
+ g_free (real_provider);
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
+ "No username for '%s'", cnc_string);
+ return NULL;
+ }
+ g_free (user);
+ user = g_strdup (buf);
+ }
+ if (pass && !*pass) {
+ gchar buf[80];
+ g_print ("\tPassword for '%s': ", cnc_string);
+ if (scanf ("%80s", buf) == -1) {
+ g_free (real_cnc);
+ g_free (user);
+ g_free (pass);
+ g_free (real_provider);
+ g_set_error (error, GDA_CONNECTION_ERROR, GDA_CONNECTION_DSN_NOT_FOUND_ERROR,
+ "No password for '%s'", cnc_string);
+ return NULL;
+ }
+ g_free (pass);
+ pass = g_strdup (buf);
+ }
+ if (user || pass) {
+ gchar *s1;
+ s1 = gda_rfc1738_encode (user);
+ if (pass) {
+ gchar *s2;
+ s2 = gda_rfc1738_encode (pass);
+ real_auth_string = g_strdup_printf ("USERNAME=%s;PASSWORD=%s", s1, s2);
+ g_free (s2);
+ }
+ else
+ real_auth_string = g_strdup_printf ("USERNAME=%s", s1);
+ g_free (s1);
+ }
+ }
+
+ info = gda_config_get_dsn (real_cnc);
+ if (info && !real_provider)
+ cnc = gda_connection_open_from_dsn (cnc_string, real_auth_string, 0, error);
+ else
+ cnc = gda_connection_open_from_string (NULL, cnc_string, real_auth_string, 0, error);
+
+ g_free (real_cnc);
+ g_free (user);
+ g_free (pass);
+ g_free (real_provider);
+ g_free (real_auth_string);
+
+ return cnc;
+}
+
+static gboolean
+report_provider_status (GdaServerProvider *prov, GdaConnection *cnc)
+{
+ gchar *str;
+ HtmlFile *file = config->index;
+
+ if (prov && cnc && (prov != gda_connection_get_provider_obj (cnc)))
+ /* ignoring connection as it has a different provider */
+ return TRUE;
+ g_assert (prov || cnc);
+
+ /* section */
+ if (cnc)
+ str = g_strdup_printf ("Report for connection '%s'", gda_connection_get_cnc_string (cnc));
+ else
+ str = g_strdup_printf ("Report for '%s' provider", gda_server_provider_get_name (prov));
+ html_add_header (HTML_CONFIG (config), file, str);
+ g_free (str);
+
+ /* provider info */
+ if (!prov)
+ prov = gda_connection_get_provider_obj (cnc);
+ xmlNodePtr table, tr, td, hnode;
+ GdaSqlParser *parser;
+
+ hnode = xmlNewChild (file->body, NULL, "h3", "General information");
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+ //xmlSetProp(table, "width", (xmlChar*)"100%");
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Property");
+ xmlNewChild (tr, NULL, "th", "Value");
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", "Provider's name");
+ xmlNewChild (tr, NULL, "td", gda_server_provider_get_name (prov));
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", "Provider's version");
+ xmlNewChild (tr, NULL, "td", gda_server_provider_get_version (prov));
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", "Provider's server version");
+ xmlNewChild (tr, NULL, "td", cnc ? gda_server_provider_get_server_version (prov, cnc) : "---");
+
+ parser = gda_server_provider_create_parser (prov, cnc);
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", "Creates its own SQL parser");
+ xmlNewChild (tr, NULL, "td", parser ? "Yes" : "No");
+ if (parser)
+ g_object_unref (parser);
+
+ /* supported features */
+ GdaConnectionFeature f;
+ hnode = xmlNewChild (file->body, NULL, "h3", "Supported features");
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Feature");
+ xmlNewChild (tr, NULL, "th", "Supported ?");
+ for (f = 0; f < GDA_CONNECTION_FEATURE_LAST; f++) {
+ GEnumValue *ev;
+
+ ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_CONNECTION_FEATURE), f);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", ev->value_name);
+ xmlNewChild (tr, NULL, "td", gda_server_provider_supports_feature (prov, cnc, f) ? "Yes" : "No");
+ }
+
+ /* supported operations */
+ GdaServerOperationType op;
+ hnode = xmlNewChild (file->body, NULL, "h3", "Supported server operations");
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Server operation");
+ xmlNewChild (tr, NULL, "th", "Supported ?");
+ for (op = 0; op < GDA_SERVER_OPERATION_NB; op++) {
+ GEnumValue *ev;
+
+ ev = g_enum_get_value ((GEnumClass *) g_type_class_ref (GDA_TYPE_SERVER_OPERATION_TYPE), op);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "td", ev->value_name);
+ xmlNewChild (tr, NULL, "td", gda_server_provider_supports_operation (prov, cnc, op, NULL) ? "Yes" : "No");
+ }
+
+ /* virtual methods implementation */
+ gint i;
+ typedef void (*AFunc) (void);
+ typedef struct {
+ const gchar *name;
+ gboolean should_be;
+ void (*func) (void);
+ } ProvFunc;
+ GdaServerProviderClass *pclass = (GdaServerProviderClass*)
+ G_OBJECT_GET_CLASS (prov);
+ ProvFunc fa[] = {
+ {"get_name", TRUE, (AFunc) pclass->get_name},
+ {"get_version", TRUE, (AFunc) pclass->get_version},
+ {"get_server_version", TRUE, (AFunc) pclass->get_server_version},
+ {"supports_feature", TRUE, (AFunc) pclass->supports_feature},
+ {"get_data_handler", TRUE, (AFunc) pclass->get_data_handler},
+ {"get_def_dbms_type", TRUE, (AFunc) pclass->get_def_dbms_type},
+ {"escape_string", TRUE, (AFunc) pclass->escape_string},
+ {"unescape_string", TRUE, (AFunc) pclass->unescape_string},
+ {"open_connection", TRUE, (AFunc) pclass->open_connection},
+ {"close_connection", TRUE, (AFunc) pclass->close_connection},
+ {"get_database", TRUE, (AFunc) pclass->get_database},
+ {"supports_operation", TRUE, (AFunc) pclass->supports_operation},
+ {"create_operation", FALSE, (AFunc) pclass->create_operation},
+ {"render_operation", FALSE, (AFunc) pclass->render_operation},
+ {"perform_operation", FALSE, (AFunc) pclass->perform_operation},
+ {"begin_transaction", FALSE, (AFunc) pclass->begin_transaction},
+ {"commit_transaction", FALSE, (AFunc) pclass->commit_transaction},
+ {"rollback_transaction", FALSE, (AFunc) pclass->rollback_transaction},
+ {"add_savepoint", FALSE, (AFunc) pclass->add_savepoint},
+ {"rollback_savepoint", FALSE, (AFunc) pclass->rollback_savepoint},
+ {"delete_savepoint", FALSE, (AFunc) pclass->delete_savepoint},
+ {"create_parser", FALSE, (AFunc) pclass->create_parser},
+ {"statement_to_sql", TRUE, (AFunc) pclass->statement_to_sql},
+ {"statement_prepare", TRUE, (AFunc) pclass->statement_prepare},
+ {"statement_execute", TRUE, (AFunc) pclass->statement_execute},
+ };
+ hnode = xmlNewChild (file->body, NULL, "h3", "Main virtual methods implementation");
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Server's virtual method");
+ xmlNewChild (tr, NULL, "th", "Implemented ?");
+
+ for (i = 0; i < sizeof (fa) / sizeof (ProvFunc); i++) {
+ gchar *str;
+ ProvFunc *pf = &(fa[i]);
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ str = g_strdup_printf ("%s ()", pf->name);
+ xmlNewChild (tr, NULL, "td", str);
+ g_free (str);
+ td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+ if (pf->should_be && !pf->func)
+ xmlSetProp(td, "class", (xmlChar*)"error");
+ }
+
+ /* meta data implementation */
+ ProvFunc md[] = {
+ {"_info", TRUE, (AFunc) pclass->meta_funcs._info},
+ {"_btypes", TRUE, (AFunc) pclass->meta_funcs._btypes},
+ {"_udt", TRUE, (AFunc) pclass->meta_funcs._udt},
+ {"udt", TRUE, (AFunc) pclass->meta_funcs.udt},
+ {"_udt_cols", TRUE, (AFunc) pclass->meta_funcs._udt_cols},
+ {"udt_cols", TRUE, (AFunc) pclass->meta_funcs.udt_cols},
+ {"_enums", TRUE, (AFunc) pclass->meta_funcs._enums},
+ {"enums", TRUE, (AFunc) pclass->meta_funcs.enums},
+ {"_domains", TRUE, (AFunc) pclass->meta_funcs._domains},
+ {"domains", TRUE, (AFunc) pclass->meta_funcs.domains},
+ {"_constraints_dom", TRUE, (AFunc) pclass->meta_funcs._constraints_dom},
+ {"constraints_dom", TRUE, (AFunc) pclass->meta_funcs.constraints_dom},
+ {"_el_types", TRUE, (AFunc) pclass->meta_funcs._el_types},
+ {"el_types", TRUE, (AFunc) pclass->meta_funcs.el_types},
+ {"_collations", TRUE, (AFunc) pclass->meta_funcs._collations},
+ {"collations", TRUE, (AFunc) pclass->meta_funcs.collations},
+ {"_character_sets", TRUE, (AFunc) pclass->meta_funcs._character_sets},
+ {"character_sets", TRUE, (AFunc) pclass->meta_funcs.character_sets},
+ {"_schemata", TRUE, (AFunc) pclass->meta_funcs._schemata},
+ {"schemata", TRUE, (AFunc) pclass->meta_funcs.schemata},
+ {"_tables_views", TRUE, (AFunc) pclass->meta_funcs._tables_views},
+ {"tables_views", TRUE, (AFunc) pclass->meta_funcs.tables_views},
+ {"_columns", TRUE, (AFunc) pclass->meta_funcs._columns},
+ {"columns", TRUE, (AFunc) pclass->meta_funcs.columns},
+ {"_view_cols", TRUE, (AFunc) pclass->meta_funcs._view_cols},
+ {"view_cols", TRUE, (AFunc) pclass->meta_funcs.view_cols},
+ {"_constraints_tab", TRUE, (AFunc) pclass->meta_funcs._constraints_tab},
+ {"constraints_tab", TRUE, (AFunc) pclass->meta_funcs.constraints_tab},
+ {"_constraints_ref", TRUE, (AFunc) pclass->meta_funcs._constraints_ref},
+ {"constraints_ref", TRUE, (AFunc) pclass->meta_funcs.constraints_ref},
+ {"_key_columns", TRUE, (AFunc) pclass->meta_funcs._key_columns},
+ {"key_columns", TRUE, (AFunc) pclass->meta_funcs.key_columns},
+ {"_check_columns", TRUE, (AFunc) pclass->meta_funcs._check_columns},
+ {"check_columns", TRUE, (AFunc) pclass->meta_funcs.check_columns},
+ {"_triggers", TRUE, (AFunc) pclass->meta_funcs._triggers},
+ {"triggers", TRUE, (AFunc) pclass->meta_funcs.triggers},
+ {"_routines", TRUE, (AFunc) pclass->meta_funcs._routines},
+ {"routines", TRUE, (AFunc) pclass->meta_funcs.routines},
+ {"_routine_col", TRUE, (AFunc) pclass->meta_funcs._routine_col},
+ {"routine_col", TRUE, (AFunc) pclass->meta_funcs.routine_col},
+ {"_routine_par", TRUE, (AFunc) pclass->meta_funcs._routine_par},
+ {"routine_par", TRUE, (AFunc) pclass->meta_funcs.routine_par},
+ };
+ hnode = xmlNewChild (file->body, NULL, "h3", "Meta data methods implementation");
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Meta data's method");
+ xmlNewChild (tr, NULL, "th", "Implemented ?");
+
+ for (i = 0; i < sizeof (md) / sizeof (ProvFunc); i++) {
+ gchar *str;
+ ProvFunc *pf = &(md[i]);
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ str = g_strdup_printf ("%s ()", pf->name);
+ xmlNewChild (tr, NULL, "td", str);
+ g_free (str);
+ td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+ if (pf->should_be && !pf->func)
+ xmlSetProp(td, "class", (xmlChar*)"error");
+ }
+
+ /* distributed transaction implementation */
+ gboolean has_xa = gda_server_provider_supports_feature (prov, cnc,
+ GDA_CONNECTION_FEATURE_XA_TRANSACTIONS);
+ hnode = xmlNewChild (file->body, NULL, "h3", "Distributed transaction implementation");
+ if (pclass->xa_funcs) {
+ if (!has_xa) {
+ xmlNodePtr para;
+ para = xmlNewChild (file->body, NULL, "para",
+ "The provider has the 'xa_funcs' part but "
+ "reports that distributed transactions are "
+ "not supported.");
+ xmlSetProp(para, "class", (xmlChar*)"warning");
+ }
+
+ ProvFunc dt[] = {
+ {"xa_start", TRUE, (AFunc) pclass->xa_funcs->xa_start},
+ {"xa_end", FALSE, (AFunc) pclass->xa_funcs->xa_end},
+ {"xa_prepare", TRUE, (AFunc) pclass->xa_funcs->xa_prepare},
+ {"xa_commit", TRUE, (AFunc) pclass->xa_funcs->xa_commit},
+ {"xa_rollback", TRUE, (AFunc) pclass->xa_funcs->xa_rollback},
+ {"xa_recover", TRUE, (AFunc) pclass->xa_funcs->xa_recover},
+ };
+
+ table = xmlNewChild (file->body, NULL, "table", NULL);
+
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ xmlNewChild (tr, NULL, "th", "Meta data's method");
+ xmlNewChild (tr, NULL, "th", "Implemented ?");
+
+ for (i = 0; i < sizeof (dt) / sizeof (ProvFunc); i++) {
+ gchar *str;
+ ProvFunc *pf = &(dt[i]);
+ tr = xmlNewChild (table, NULL, "tr", NULL);
+ str = g_strdup_printf ("%s ()", pf->name);
+ xmlNewChild (tr, NULL, "td", str);
+ g_free (str);
+ td = xmlNewChild (tr, NULL, "td", pf->func ? "Yes" : "No");
+ if (pf->should_be && !pf->func)
+ xmlSetProp(td, "class", (xmlChar*)"error");
+ }
+ }
+ else {
+ if (has_xa) {
+ xmlNodePtr para;
+ para = xmlNewChild (file->body, NULL, "para",
+ "The provider does not have the 'xa_funcs' part but "
+ "reports that distributed transactions are "
+ "supported.");
+ xmlSetProp(para, "class", (xmlChar*)"warning");
+ }
+ xmlNewChild (tr, NULL, "para", "Not implemented");
+ }
+
+
+ return TRUE;
+}
Added: trunk/testing/html.c
==============================================================================
--- (empty file)
+++ trunk/testing/html.c Wed Jun 4 20:35:49 2008
@@ -0,0 +1,357 @@
+#include "html.h"
+#include <glib/gi18n-lib.h>
+
+static gint counter = 0;
+
+void
+html_init_config (HtmlConfig *config)
+{
+ g_assert (config);
+
+ config->nodes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+}
+
+HtmlFile *
+html_file_new (HtmlConfig *config, const gchar *name, const gchar *title)
+{
+ HtmlFile *file;
+ xmlNodePtr topnode, head, node;
+
+ file = g_new0 (HtmlFile, 1);
+ file->name = g_strdup (name);
+ file->doc = xmlNewDoc ("1.0");
+ topnode = xmlNewDocNode (file->doc, NULL, "html", NULL);
+ xmlDocSetRootElement (file->doc, topnode);
+
+ /* head */
+ head = xmlNewChild (topnode, NULL, "head", NULL);
+
+ node = xmlNewChild (head, NULL, "meta", NULL);
+ xmlSetProp(node, "content", (xmlChar*)"charset=ISO-8859-1");
+ xmlSetProp(node, "http-equiv", (xmlChar*)"content-type");
+
+ node = xmlNewChild (head, NULL, "title", title);
+ node = xmlNewChild (head, NULL, "style",
+"body { "
+" margin: 0px; padding: 0px; border:0px; "
+" font: 8pt/16pt georgia; "
+" color: #555753; "
+" margin: 5px; "
+" }"
+""
+"a:visited, a:link { "
+" text-decoration: none ; color: #4085cd; "
+"}"
+""
+"a:hover { "
+" text-decoration: none; color: #FF0000; "
+"}"
+""
+"p { "
+" font: 8pt/16pt georgia; "
+" margin-top: 0px; "
+" text-align: justify;"
+" }"
+"h2 { "
+" font: italic normal 14pt georgia; "
+" letter-spacing: 1px; "
+" margin-bottom: 0px; "
+" color: #7D775C;"
+" }"
+""
+"table {"
+" font-size: 8pt;"
+" /*border: 1pt solid #A8E775;*/"
+" padding: 3px;"
+"}"
+""
+"tr {"
+" background: #EFEEEF;"
+"}"
+""
+".none {"
+" list-style : none;"
+" padding-left: 0px;"
+"}"
+""
+".error {"
+" color: #FF0000;"
+" font: bold;"
+" font-size: large;"
+"}"
+""
+".warning {"
+" color: #ff9900;"
+" font: bold;"
+" font-size: medium;"
+"}"
+""
+".notice {"
+" color: #22bb00;"
+" font: bold;"
+" /*font-size: medium;*/"
+"}"
+""
+"#inactive {"
+" background-color: #CCCCFF;"
+"}"
+""
+".null {"
+" color: lightblue;"
+"}"
+);
+
+ /* body */
+ node = xmlNewChild (topnode, NULL, "body", NULL);
+ file->body = node;
+
+ /* title */
+ node = xmlNewChild (file->body, NULL, "h1", title);
+ xmlSetProp(node, "class", (xmlChar*)"title");
+
+ /* toc */
+ file->toc = xmlNewChild (file->body, NULL, "ul", _("Table of contents"));
+ xmlSetProp(file->toc, "class", (xmlChar*)"none");
+
+ /* add to @config's list of files */
+ config->all_files = g_slist_append (config->all_files, file);
+
+ return file;
+}
+
+gboolean
+html_file_write (HtmlFile *file, HtmlConfig *config)
+{
+ gchar *str;
+
+ str = g_strdup_printf ("%s/%s", config->dir, file->name);
+ gint i;
+ i = xmlSaveFormatFile (str, file->doc, TRUE);
+ if (i == -1)
+ g_warning (_("Error writing XML file %s"), str);
+ g_free (str);
+
+ return i!=-1;
+}
+
+void
+html_file_free (HtmlFile *file)
+{
+ xmlFreeDoc (file->doc);
+ g_free (file->name);
+ g_free (file);
+}
+
+void
+html_declare_node (HtmlConfig *config, const gchar *path, xmlNodePtr node)
+{
+ html_declare_node_own (config, g_strdup (path), node);
+}
+
+void
+html_declare_node_own (HtmlConfig *config, gchar *path, xmlNodePtr node)
+{
+ xmlNodePtr enode;
+
+ enode = g_hash_table_lookup (config->nodes, path);
+ if (enode) {
+ g_warning ("Node path %s is already attributed", path);
+ g_free (path);
+ return;
+ }
+
+ g_hash_table_insert (config->nodes, path, node);
+ /*g_print ("--- Added node @ %s\n", path);*/
+}
+
+/*
+ * if @link_to starts with a '/' then a # is prepended (internal link)
+ */
+void
+real_html_add_link_to_node (xmlNodePtr node, const gchar *text, const gchar *link_to)
+{
+ xmlNodePtr href;
+ gchar *tmp;
+
+ href = xmlNewNode (NULL, (xmlChar*)"a");
+ tmp = g_strdup_printf (" [%s] ", text);
+ xmlNodeSetContent (href, tmp);
+ g_free (tmp);
+ if (node->children) {
+ xmlNodePtr sibl;
+
+ sibl = node->children;
+ while (sibl && xmlNodeIsText (sibl))
+ sibl = sibl->next;
+ if (sibl)
+ xmlAddPrevSibling (sibl, href);
+ else
+ xmlAddChild (node, href);
+ }
+ else
+ xmlAddChild (node, href);
+ if (*link_to == '/') {
+ tmp = g_strdup_printf ("#%s", link_to);
+ xmlSetProp(href, (xmlChar*)"href", tmp);
+ g_free (tmp);
+ }
+ else
+ xmlSetProp(href, (xmlChar*)"href", link_to);
+}
+
+void
+html_add_link_to_node (HtmlConfig *config, const gchar *nodepath, const gchar *text, const gchar *link_to)
+{
+ xmlNodePtr node;
+
+ node = g_hash_table_lookup (config->nodes, nodepath);
+ if (!node) {
+ g_warning ("Can't link non existant node '%s'", nodepath);
+ return;
+ }
+
+ real_html_add_link_to_node (node, text, link_to);
+}
+
+void
+html_add_to_toc (HtmlConfig *config, HtmlFile *file, const gchar *text, const gchar *link_to)
+{
+ xmlNodePtr li;
+
+ li = xmlNewChild (file->toc, NULL, "li", NULL);
+ real_html_add_link_to_node (li, text, link_to);
+}
+
+xmlNodePtr
+html_add_header (HtmlConfig *config, HtmlFile *file, const gchar *text)
+{
+ xmlNodePtr hnode, ntmp;
+ gchar *tmp;
+
+ hnode = xmlNewChild (file->body, NULL, "h2", text);
+ tmp = g_strdup_printf ("/a/%d", counter++);
+ html_add_to_toc (config, file, text, tmp);
+ ntmp = xmlNewChild (hnode, NULL, "a", "");
+ xmlSetProp(ntmp, (xmlChar*)"name", tmp);
+ g_free (tmp);
+
+ return hnode;
+}
+
+void
+html_mark_path_error (HtmlConfig *config, const gchar *nodepath)
+{
+ xmlNodePtr node;
+
+ node = g_hash_table_lookup (config->nodes, nodepath);
+ if (!node) {
+ g_warning ("Can't link non existant node '%s'", nodepath);
+ return;
+ }
+ html_mark_node_error (config, node);
+}
+
+void
+html_mark_node_error (HtmlConfig *config, xmlNodePtr node)
+{
+ xmlSetProp(node, "class", (xmlChar*)"error");
+}
+
+void
+html_mark_node_warning (HtmlConfig *config, xmlNodePtr node)
+{
+ xmlSetProp(node, "class", (xmlChar*)"warning");
+}
+
+void
+html_mark_node_notice (HtmlConfig *config, xmlNodePtr node)
+{
+ xmlSetProp(node, "class", (xmlChar*)"notice");
+}
+
+xmlNodePtr
+html_render_attribute_str (xmlNodePtr parent, const gchar *node_type,
+ const gchar *att_name, const gchar *att_val)
+{
+ xmlNodePtr node;
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("%s = %s", att_name, att_val);
+ node = xmlNewChild (parent, NULL, node_type, tmp);
+ g_free (tmp);
+
+ return node;
+}
+
+xmlNodePtr
+html_render_attribute_bool (xmlNodePtr parent, const gchar *node_type,
+ const gchar *att_name, gboolean att_val)
+{
+ xmlNodePtr node;
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("%s = %s", att_name, att_val ? _("Yes") : _("No"));
+ node = xmlNewChild (parent, NULL, node_type, tmp);
+ g_free (tmp);
+
+ return node;
+}
+
+xmlNodePtr
+html_render_data_model (xmlNodePtr parent, GdaDataModel *model)
+{
+ xmlNodePtr node, tr, td;
+ gint rows, cols, i;
+
+ g_return_val_if_fail (GDA_IS_DATA_MODEL (model), NULL);
+
+ node = xmlNewChild (parent, NULL, "table", "");
+
+ cols = gda_data_model_get_n_columns (model);
+ rows = gda_data_model_get_n_rows (model);
+
+ /* set the table structure */
+ tr = xmlNewChild (node, NULL, "tr", NULL);
+ for (i = 0; i < cols; i++) {
+ GdaColumn *column;
+
+ column = gda_data_model_describe_column (model, i);
+ if (!column) {
+ xmlFreeNode (node);
+ return NULL;
+ }
+
+ td = xmlNewChild (tr, NULL, "th", gda_column_get_name (column));
+ }
+
+ /* add the model data to the XML output */
+ if (rows > 0) {
+ gint r, c;
+
+ for (r = 0; r < rows; r++) {
+ tr = xmlNewChild (node, NULL, "tr", "");
+ for (c = 0 ; c < cols; c++) {
+ GValue *value;
+ gchar *str;
+
+ value = (GValue *) gda_data_model_get_value_at (model, c, r);
+ if (!value || gda_value_is_null (value)) {
+ xmlNodePtr p;
+ td = xmlNewChild (tr, NULL, "td", NULL);
+ p = xmlNewChild (td, NULL, "p", "NULL");
+ xmlSetProp(p, "class", (xmlChar*)"null");
+ }
+ else {
+ if (G_VALUE_TYPE (value) == G_TYPE_BOOLEAN)
+ str = g_strdup (g_value_get_boolean (value) ? "TRUE" : "FALSE");
+ else
+ str = gda_value_stringify (value);
+ td = xmlNewChild (tr, NULL, "td", str);
+ g_free (str);
+ }
+ }
+ }
+ }
+
+ return node;
+}
Added: trunk/testing/html.h
==============================================================================
--- (empty file)
+++ trunk/testing/html.h Wed Jun 4 20:35:49 2008
@@ -0,0 +1,46 @@
+#include <glib.h>
+#include <libxml/tree.h>
+#include <libgda/libgda.h>
+
+typedef struct {
+ gchar *name;
+ xmlDocPtr doc;
+ xmlNodePtr body;
+ xmlNodePtr toc;
+} HtmlFile;
+
+typedef struct {
+ HtmlFile *index;
+
+ GHashTable *nodes; /* key=node name, value=xmlNodePtr */
+ gchar *dir;
+ GSList *all_files;
+} HtmlConfig;
+#define HTML_CONFIG(x) ((HtmlConfig*)(x))
+
+
+/*
+ * HTML output files manipulation
+ * Files are built as XML files and then printed at the end
+ */
+void html_init_config (HtmlConfig *config);
+HtmlFile *html_file_new (HtmlConfig *config,
+ const gchar *name, const gchar *title);
+gboolean html_file_write (HtmlFile *file, HtmlConfig *config);
+void html_file_free (HtmlFile *file);
+void html_declare_node (HtmlConfig *config, const gchar *path, xmlNodePtr node);
+void html_declare_node_own (HtmlConfig *config, gchar *path, xmlNodePtr node);
+void html_add_link_to_node (HtmlConfig *config, const gchar *nodepath,
+ const gchar *text, const gchar *link_to);
+void html_add_to_toc (HtmlConfig *config, HtmlFile *file, const gchar *text, const gchar *link_to);
+xmlNodePtr html_add_header (HtmlConfig *config, HtmlFile *file, const gchar *text);
+void html_mark_path_error (HtmlConfig *config, const gchar *nodepath);
+void html_mark_node_error (HtmlConfig *config, xmlNodePtr node);
+void html_mark_node_warning (HtmlConfig *config, xmlNodePtr node);
+void html_mark_node_notice (HtmlConfig *config, xmlNodePtr node);
+
+xmlNodePtr html_render_attribute_str (xmlNodePtr parent, const gchar *node_type,
+ const gchar *att_name, const gchar *att_val);
+xmlNodePtr html_render_attribute_bool (xmlNodePtr parent, const gchar *node_type,
+ const gchar *att_name, gboolean att_val);
+xmlNodePtr html_render_data_model (xmlNodePtr parent, GdaDataModel *model);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]