[libgda] Correclty handle variables set to DEFAULT when executing a statement
- From: Vivien Malerba <vivien src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgda] Correclty handle variables set to DEFAULT when executing a statement
- Date: Wed, 21 Jul 2010 19:18:02 +0000 (UTC)
commit 93720d40478ef030f3b87d37b5a33cd43ac8139d
Author: Vivien Malerba <malerba gnome-db org>
Date: Wed Jul 21 17:10:18 2010 +0200
Correclty handle variables set to DEFAULT when executing a statement
this is necessary when a statement containing variables is executed
and when some of the variables are set to a default value (which
is not compatible with the variable type and can not be bound normally).
In this case the statement is re-written and executed.
doc/C/libgda-sections.txt | 2 +
doc/C/tmpl/gda-server-provider.sgml | 2 +
doc/C/tmpl/provider-support.sgml | 12 +
libgda/gda-server-provider.h | 10 +-
libgda/gda-util.c | 235 +++++++++++++++++++-
libgda/gda-util.h | 5 +-
libgda/libgda.symbols | 1 +
libgda/sqlite/gda-sqlite-provider.c | 50 ++++
providers/jdbc/gda-jdbc-provider.c | 50 ++++
providers/mysql/gda-mysql-provider.c | 48 ++++
providers/oracle/gda-oracle-provider.c | 48 ++++
providers/postgres/gda-postgres-provider.c | 58 +++++
.../skel-implementation/capi/gda-capi-provider.c | 54 +++++
providers/web/gda-web-provider.c | 53 +++++
tests/parser/.gitignore | 3 +-
tests/parser/Makefile.am | 10 +-
tests/parser/check_rewrite_for_default.c | 121 ++++++++++
17 files changed, 752 insertions(+), 10 deletions(-)
---
diff --git a/doc/C/libgda-sections.txt b/doc/C/libgda-sections.txt
index a6abc7b..39b5cc0 100644
--- a/doc/C/libgda-sections.txt
+++ b/doc/C/libgda-sections.txt
@@ -1487,6 +1487,8 @@ gda_compute_unique_table_row_condition
gda_compute_unique_table_row_condition_with_cnc
<SUBSECTION>
gda_sql_any_part_check_structure
+<SUBSECTION>
+gda_statement_rewrite_for_default_values
</SECTION>
<SECTION>
diff --git a/doc/C/tmpl/gda-server-provider.sgml b/doc/C/tmpl/gda-server-provider.sgml
index e7a91fe..5a9895b 100644
--- a/doc/C/tmpl/gda-server-provider.sgml
+++ b/doc/C/tmpl/gda-server-provider.sgml
@@ -70,6 +70,7 @@ Base class for all the DBMS providers
@xa_funcs:
@identifier_quote:
@handle_async:
+ statement_rewrite:
<!-- ##### ENUM GdaServerProviderError ##### -->
<para>
@@ -87,6 +88,7 @@ Base class for all the DBMS providers
@GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR:
@GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR:
@GDA_SERVER_PROVIDER_DATA_ERROR:
+ GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR:
<!-- ##### MACRO GDA_SERVER_PROVIDER_ERROR ##### -->
<para>
diff --git a/doc/C/tmpl/provider-support.sgml b/doc/C/tmpl/provider-support.sgml
index 1e852ff..4b0f0d3 100644
--- a/doc/C/tmpl/provider-support.sgml
+++ b/doc/C/tmpl/provider-support.sgml
@@ -466,3 +466,15 @@ Methods dedicated to implementing providers
@Returns:
+<!-- ##### FUNCTION gda_statement_rewrite_for_default_values ##### -->
+<para>
+
+</para>
+
+ stmt:
+ params:
+ remove:
+ error:
+ Returns:
+
+
diff --git a/libgda/gda-server-provider.h b/libgda/gda-server-provider.h
index de16cfe..81d4a44 100644
--- a/libgda/gda-server-provider.h
+++ b/libgda/gda-server-provider.h
@@ -57,7 +57,8 @@ typedef enum
GDA_SERVER_PROVIDER_BUSY_ERROR,
GDA_SERVER_PROVIDER_NON_SUPPORTED_ERROR,
GDA_SERVER_PROVIDER_SERVER_VERSION_ERROR,
- GDA_SERVER_PROVIDER_DATA_ERROR
+ GDA_SERVER_PROVIDER_DATA_ERROR,
+ GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR
} GdaServerProviderError;
struct _GdaServerProvider {
@@ -306,12 +307,13 @@ struct _GdaServerProviderClass {
const gchar *id,
gboolean for_meta_store, gboolean force_quotes);
- /* Async. handling@ */
- gboolean (*handle_async) (GdaServerProvider *provider, GdaConnection *cnc, GError **error);
+ /* Async. handling */
+ gboolean (*handle_async) (GdaServerProvider *provider, GdaConnection *cnc, GError **error);
+ GdaSqlStatement *(*statement_rewrite) (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
/*< private >*/
/* Padding for future expansion */
- void (*_gda_reserved3) (void);
void (*_gda_reserved4) (void);
void (*_gda_reserved5) (void);
void (*_gda_reserved6) (void);
diff --git a/libgda/gda-util.c b/libgda/gda-util.c
index b92ea32..2ecb247 100644
--- a/libgda/gda-util.c
+++ b/libgda/gda-util.c
@@ -1,5 +1,5 @@
/* GDA common library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+ * Copyright (C) 1998 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Rodrigo Moya <rodrigo gnome-db org>
@@ -38,6 +38,8 @@
#endif
#include <libgda/sql-parser/gda-sql-statement.h>
#include <sql-parser/gda-statement-struct-util.h>
+#include <libgda/gda-set.h>
+#include <libgda/gda-blob-op.h>
#include <libgda/binreloc/gda-binreloc.h>
@@ -409,7 +411,7 @@ gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent,
const GdaBinary *bin = &(blob->data);
if (blob->op &&
(bin->binary_length != gda_blob_op_get_length (blob->op)))
- gda_blob_op_read_all (blob->op, blob);
+ gda_blob_op_read_all (blob->op, (GdaBlob*) blob);
}
str = gda_value_stringify (value);
}
@@ -1201,6 +1203,235 @@ gda_compute_select_statement_from_update (GdaStatement *update_stmt, GError **er
return sel_stmt;
}
+static gboolean stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error);
+static gboolean stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error);
+static gboolean stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error);
+
+
+/**
+ * gda_statement_rewrite_for_default_values
+ * @stmt: a #GdaStatement object
+ * @params: a #GdaSet containing the variable's values to be bound when executing @stmt
+ * @remove: set to %TRUE if DEFAULT fields are removed, of %FALSE if the "DEFAULT" keyword is used
+ * @error: a place to store errors, or %NULL
+ *
+ * Rewrites @stmt and creates a new #GdaSqlStatement where all the variables which are to a DEFAULT value
+ * (as returned by gda_holder_value_is_default()) are either removed from the statement (if @remove
+ * is %TRUE) or replaced by the "DEFAULT" keyword (if @remove is %FALSE).
+ *
+ * This function is only usefull for database providers' implementations which have to deal with default
+ * values when executing statements, and is only relevant in the case of INSERT or UPDATE statements
+ * (in the latter case an error is returned if @remove is %TRUE).
+ *
+ * For example the <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, ##name::string)]]></programlisting>
+ * is re-written into <programlisting><![CDATA[INSERT INTO mytable (id, name) VALUES (23, DEFAULT)]]></programlisting>
+ * if @remove is %FALSE and into <programlisting><![CDATA[INSERT INTO mytable (id) VALUES (23)]]></programlisting>
+ * if @remove is %TRUE.
+ *
+ * Returns: a new #GdaSqlStatement, or %NULL if an error occurred
+ *
+ * Since: 4.2
+ */
+GdaSqlStatement *
+gda_statement_rewrite_for_default_values (GdaStatement *stmt, GdaSet *params, gboolean remove, GError **error)
+{
+ GdaSqlStatement *sqlst;
+ GdaSqlStatementType type;
+ gboolean ok = FALSE;
+ g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+ g_return_val_if_fail (GDA_IS_SET (params), NULL);
+ type = gda_statement_get_statement_type (stmt);
+
+ g_object_get (stmt, "structure", &sqlst, NULL);
+ if (! gda_sql_statement_check_structure (sqlst, error)) {
+ gda_sql_statement_free (sqlst);
+ return NULL;
+ }
+
+ switch (type) {
+ case GDA_SQL_STATEMENT_INSERT:
+ if (remove)
+ ok = stmt_rewrite_insert_remove ((GdaSqlStatementInsert*) sqlst->contents,
+ params, error);
+ else
+ ok = stmt_rewrite_insert_default_keyword ((GdaSqlStatementInsert*) sqlst->contents,
+ params, error);
+ break;
+ case GDA_SQL_STATEMENT_UPDATE:
+ if (remove)
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
+ _("Can't rewrite UPDATE statement to handle default values"));
+ else
+ ok = stmt_rewrite_update_default_keyword ((GdaSqlStatementUpdate*) sqlst->contents,
+ params, error);
+ break;
+ default:
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
+ "Can't rewrite statement is not INSERT or UPDATE");
+ break;
+ }
+
+ if (ok)
+ return sqlst;
+ else {
+ gda_sql_statement_free (sqlst);
+ return NULL;
+ }
+}
+
+/*
+ * Modifies @ins
+ * Returns: TRUE if rewrite is Ok
+ */
+static gboolean
+stmt_rewrite_insert_remove (GdaSqlStatementInsert *ins, GdaSet *params, GError **error)
+{
+ if (!ins->values_list)
+ /* nothing to do */
+ return TRUE;
+
+ if (ins->values_list->next) {
+ TO_IMPLEMENT;
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_DEFAULT_VALUE_HANDLING_ERROR,
+ "Not yet implemented");
+ return FALSE;
+ }
+
+ GSList *fields, *values;
+ for (fields = ins->fields_list, values = (GSList*) ins->values_list->data;
+ fields && values; ){
+ GdaHolder *h;
+ GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
+ if (! expr->param_spec || ! expr->param_spec->is_param) {
+ fields = fields->next;
+ values = values->next;
+ continue;
+ }
+ h = gda_set_get_holder (params, expr->param_spec->name);
+ if (!h) {
+ gchar *str;
+ str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
+ expr->param_spec->name);
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+ "%s", str);
+ g_free (str);
+ return FALSE;
+ }
+
+ if (gda_holder_value_is_default (h)) {
+ GSList *tmp;
+
+ gda_sql_field_free ((GdaSqlField*) fields->data);
+ tmp = fields->next;
+ ins->fields_list = g_slist_delete_link (ins->fields_list, fields);
+ fields = tmp;
+
+ gda_sql_expr_free (expr);
+ tmp = values->next;
+ ins->values_list->data = g_slist_delete_link ((GSList*) ins->values_list->data,
+ values);
+ values = tmp;
+ }
+ else {
+ fields = fields->next;
+ values = values->next;
+ }
+ }
+
+ if (! ins->values_list->data) {
+ g_slist_free (ins->values_list);
+ ins->values_list = NULL;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Modifies @ins
+ * Returns: TRUE if rewrite is Ok
+ */
+static gboolean
+stmt_rewrite_insert_default_keyword (GdaSqlStatementInsert *ins, GdaSet *params, GError **error)
+{
+ GSList *llist;
+ for (llist = ins->values_list; llist; llist = llist->next) {
+ GSList *values;
+ for (values = (GSList*) llist->data;
+ values;
+ values = values->next){
+ GdaHolder *h;
+ GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
+ if (! expr->param_spec || ! expr->param_spec->is_param)
+ continue;
+ h = gda_set_get_holder (params, expr->param_spec->name);
+ if (!h) {
+ gchar *str;
+ str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
+ expr->param_spec->name);
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+ "%s", str);
+ g_free (str);
+ return FALSE;
+ }
+
+ if (gda_holder_value_is_default (h)) {
+ GdaSqlExpr *nexpr;
+ nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (ins));
+ g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)),
+ "DEFAULT");
+ gda_sql_expr_free ((GdaSqlExpr*) values->data);
+ values->data = nexpr;
+ }
+ }
+ }
+
+ if (! ins->values_list->data) {
+ g_slist_free (ins->values_list);
+ ins->values_list = NULL;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+stmt_rewrite_update_default_keyword (GdaSqlStatementUpdate *upd, GdaSet *params, GError **error)
+{
+ GSList *values;
+ for (values = upd->expr_list; values; values = values->next) {
+ GdaHolder *h;
+ GdaSqlExpr *expr = (GdaSqlExpr*) values->data;
+ if (! expr->param_spec || ! expr->param_spec->is_param)
+ continue;
+ h = gda_set_get_holder (params, expr->param_spec->name);
+ if (!h) {
+ gchar *str;
+ str = g_strdup_printf (_("Missing parameter '%s' to execute query"),
+ expr->param_spec->name);
+ g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+ GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+ "%s", str);
+ g_free (str);
+ return FALSE;
+ }
+
+ if (gda_holder_value_is_default (h)) {
+ GdaSqlExpr *nexpr;
+ nexpr = gda_sql_expr_new (GDA_SQL_ANY_PART (upd));
+ g_value_set_string ((nexpr->value = gda_value_new (G_TYPE_STRING)),
+ "DEFAULT");
+ gda_sql_expr_free ((GdaSqlExpr*) values->data);
+ values->data = nexpr;
+ }
+ }
+
+ return TRUE;
+}
+
/**
* gda_identifier_hash
* @id: an identifier string
diff --git a/libgda/gda-util.h b/libgda/gda-util.h
index fc8a052..cd4fec1 100644
--- a/libgda/gda-util.h
+++ b/libgda/gda-util.h
@@ -1,5 +1,5 @@
/* GDA common library
- * Copyright (C) 1998 - 2009 The GNOME Foundation.
+ * Copyright (C) 1998 - 2010 The GNOME Foundation.
*
* AUTHORS:
* Rodrigo Moya <rodrigo gnome-db org>
@@ -61,6 +61,9 @@ gboolean gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNo
const gchar *gda_utility_data_model_find_column_description (GdaDataSelect *model, const gchar *field_name);
gboolean gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources, GError **error);
+GdaSqlStatement *gda_statement_rewrite_for_default_values (GdaStatement *stmt, GdaSet *params,
+ gboolean remove, GError **error);
+
/*
* translate any text to an alphanumerical text
*/
diff --git a/libgda/libgda.symbols b/libgda/libgda.symbols
index f48b266..4144617 100644
--- a/libgda/libgda.symbols
+++ b/libgda/libgda.symbols
@@ -764,6 +764,7 @@
gda_statement_model_usage_get_type
gda_statement_new
gda_statement_normalize
+ gda_statement_rewrite_for_default_values
gda_statement_serialize
gda_statement_sql_flag_get_type
gda_statement_to_sql_extended
diff --git a/libgda/sqlite/gda-sqlite-provider.c b/libgda/sqlite/gda-sqlite-provider.c
index 27b7d5d..0ac4642 100644
--- a/libgda/sqlite/gda-sqlite-provider.c
+++ b/libgda/sqlite/gda-sqlite-provider.c
@@ -261,6 +261,8 @@ static GObject *gda_sqlite_provider_statement_execute (GdaServerProv
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static GdaSqlStatement *gda_sqlite_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
/* string escaping */
static gchar *gda_sqlite_provider_escape_string (GdaServerProvider *provider, GdaConnection *cnc,
@@ -379,6 +381,7 @@ gda_sqlite_provider_class_init (GdaSqliteProviderClass *klass)
provider_class->statement_to_sql = gda_sqlite_provider_statement_to_sql;
provider_class->statement_prepare = gda_sqlite_provider_statement_prepare;
provider_class->statement_execute = gda_sqlite_provider_statement_execute;
+ provider_class->statement_rewrite = gda_sqlite_statement_rewrite;
provider_class->escape_string = gda_sqlite_provider_escape_string;
provider_class->unescape_string = gda_sqlite_provider_unescape_string;
@@ -2457,6 +2460,37 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ if (new_ps)
+ g_object_unref (ps);
+ pending_blobs_free_list (blobs_list);
+ res = gda_sqlite_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/*g_print ("BINDING param '%s' to %p\n", pname, h);*/
const GValue *value = gda_holder_get_value (h);
@@ -2743,6 +2777,22 @@ gda_sqlite_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
}
}
+/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Removes any default value inserted or updated
+ */
+static GdaSqlStatement *
+gda_sqlite_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
+}
+
/*
* SQLite's extra functions' implementations
*/
diff --git a/providers/jdbc/gda-jdbc-provider.c b/providers/jdbc/gda-jdbc-provider.c
index d00c193..88a4800 100644
--- a/providers/jdbc/gda-jdbc-provider.c
+++ b/providers/jdbc/gda-jdbc-provider.c
@@ -113,6 +113,9 @@ static GObject *gda_jdbc_provider_statement_execute (GdaServerProvid
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static GdaSqlStatement *gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
+
/* distributed transactions */
static gboolean gda_jdbc_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
@@ -191,6 +194,7 @@ gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass)
* because it only calls gda_statement_to_sql_extended() */
provider_class->statement_prepare = gda_jdbc_provider_statement_prepare;
provider_class->statement_execute = gda_jdbc_provider_statement_execute;
+ provider_class->statement_rewrite = gda_jdbc_statement_rewrite;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -1365,6 +1369,36 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ g_object_unref (ps);
+ _gda_jdbc_release_jenv (jni_detach);
+ res = gda_jdbc_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
@@ -1509,6 +1543,22 @@ gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection
}
/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Safely removes any default value inserted or updated
+ */
+static GdaSqlStatement *
+gda_jdbc_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
+}
+
+/*
* starts a distributed transaction: put the XA transaction in the ACTIVE state
*/
static gboolean
diff --git a/providers/mysql/gda-mysql-provider.c b/providers/mysql/gda-mysql-provider.c
index 9899a42..08f5c6e 100644
--- a/providers/mysql/gda-mysql-provider.c
+++ b/providers/mysql/gda-mysql-provider.c
@@ -177,6 +177,9 @@ static GObject *gda_mysql_provider_statement_execute (GdaServerProvi
GdaServerProviderExecCallback async_cb,
gpointer cb_data,
GError **error);
+static GdaSqlStatement *gda_mysql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
+
/* Quoting */
static gchar *gda_mysql_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
@@ -282,6 +285,7 @@ gda_mysql_provider_class_init (GdaMysqlProviderClass *klass)
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;
+ provider_class->statement_rewrite = gda_mysql_statement_rewrite;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -2107,6 +2111,35 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, FALSE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ free_bind_param_data (mem_to_free);
+ res = gda_mysql_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
@@ -2414,6 +2447,21 @@ gda_mysql_provider_statement_execute (GdaServerProvider *provider,
}
/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ */
+static GdaSqlStatement *
+gda_mysql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, FALSE, error);
+}
+
+
+/*
* starts a distributed transaction: put the XA transaction in the ACTIVE state
*/
static gboolean
diff --git a/providers/oracle/gda-oracle-provider.c b/providers/oracle/gda-oracle-provider.c
index ec607b8..653ac12 100644
--- a/providers/oracle/gda-oracle-provider.c
+++ b/providers/oracle/gda-oracle-provider.c
@@ -117,6 +117,8 @@ static GObject *gda_oracle_provider_statement_execute (GdaServerProv
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static GdaSqlStatement *gda_oracle_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
/* Quoting */
static gchar *gda_oracle_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
@@ -199,6 +201,7 @@ gda_oracle_provider_class_init (GdaOracleProviderClass *klass)
provider_class->statement_to_sql = gda_oracle_provider_statement_to_sql;
provider_class->statement_prepare = gda_oracle_provider_statement_prepare;
provider_class->statement_execute = gda_oracle_provider_statement_execute;
+ provider_class->statement_rewrite = gda_oracle_statement_rewrite;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -1834,6 +1837,35 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
empty_rs = TRUE;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, FALSE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ g_object_unref (ps);
+ res = gda_oracle_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/* actual binding using the C API, for parameter at position @i */
if (!ora_value) {
@@ -2057,6 +2089,22 @@ gda_oracle_provider_statement_execute (GdaServerProvider *provider, GdaConnectio
}
/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Uses the DEFAULT keyword
+ */
+static GdaSqlStatement *
+gda_oracle_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, FALSE, error);
+}
+
+/*
* starts a distributed transaction: put the XA transaction in the ACTIVE state
*/
static gboolean
diff --git a/providers/postgres/gda-postgres-provider.c b/providers/postgres/gda-postgres-provider.c
index 909aa94..35c1c30 100644
--- a/providers/postgres/gda-postgres-provider.c
+++ b/providers/postgres/gda-postgres-provider.c
@@ -125,6 +125,10 @@ static gchar *gda_postgresql_identifier_quote (GdaServerProvide
const gchar *id,
gboolean meta_store_convention, gboolean force_quotes);
+static GdaSqlStatement *gda_postgresql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
+
+
/* distributed transactions */
static gboolean gda_postgres_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
const GdaXaTransactionId *xid, GError **error);
@@ -217,6 +221,8 @@ gda_postgres_provider_class_init (GdaPostgresProviderClass *klass)
provider_class->statement_prepare = gda_postgres_provider_statement_prepare;
provider_class->statement_execute = gda_postgres_provider_statement_execute;
+ provider_class->statement_rewrite = gda_postgresql_statement_rewrite;
+
memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
provider_class->meta_funcs._info = _gda_postgres_meta__info;
provider_class->meta_funcs._btypes = _gda_postgres_meta__btypes;
@@ -1988,6 +1994,39 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, FALSE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ params_freev (param_values, param_mem, nb_params);
+ g_free (param_lengths);
+ g_free (param_formats);
+ if (transaction_started)
+ gda_connection_rollback_transaction (cnc, NULL, NULL);
+ res = gda_postgres_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
@@ -2141,6 +2180,25 @@ gda_postgres_provider_statement_execute (GdaServerProvider *provider, GdaConnect
}
/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Usually for INSERTS:
+ * - it removes any DEFAULT value
+ * - if there is no default value anymore, it uses the "DEFAULT VALUES" syntax
+ */
+static GdaSqlStatement *
+gda_postgresql_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, FALSE, error);
+}
+
+
+/*
* starts a distributed transaction: put the XA transaction in the ACTIVE state
*/
static gboolean
diff --git a/providers/skel-implementation/capi/gda-capi-provider.c b/providers/skel-implementation/capi/gda-capi-provider.c
index 306b507..c5d407d 100644
--- a/providers/skel-implementation/capi/gda-capi-provider.c
+++ b/providers/skel-implementation/capi/gda-capi-provider.c
@@ -111,6 +111,9 @@ static GObject *gda_capi_provider_statement_execute (GdaServerProvid
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static GdaSqlStatement *gda_capi_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
+
/* distributed transactions */
static gboolean gda_capi_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc,
@@ -191,6 +194,7 @@ gda_capi_provider_class_init (GdaCapiProviderClass *klass)
* not call calls gda_statement_to_sql_extended() */
provider_class->statement_prepare = gda_capi_provider_statement_prepare;
provider_class->statement_execute = gda_capi_provider_statement_execute;
+ provider_class->statement_rewrite = gda_capi_statement_rewrite;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -1125,6 +1129,39 @@ gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead
+ * needs to be adapted to take into account how the database server handles default
+ * values (some accept the DEFAULT keyword), changing the 3rd argument of the
+ * gda_statement_rewrite_for_default_values() call
+ */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ res = gda_capi_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
+
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
@@ -1202,6 +1239,23 @@ gda_capi_provider_statement_execute (GdaServerProvider *provider, GdaConnection
}
/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Usually it uses the DEFAULT keyword or removes any default value inserted or updated, see
+ * gda_statement_rewrite_for_default_values()
+ */
+static GdaSqlStatement *
+gda_capi_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
+}
+
+/*
* starts a distributed transaction: put the XA transaction in the ACTIVE state
*/
static gboolean
diff --git a/providers/web/gda-web-provider.c b/providers/web/gda-web-provider.c
index 161db77..734f5cb 100644
--- a/providers/web/gda-web-provider.c
+++ b/providers/web/gda-web-provider.c
@@ -116,6 +116,8 @@ static GObject *gda_web_provider_statement_execute (GdaServerProvide
GType *col_types, GdaSet **last_inserted_row,
guint *task_id, GdaServerProviderExecCallback async_cb,
gpointer cb_data, GError **error);
+static GdaSqlStatement *gda_web_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error);
/* Quoting */
static gchar *gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
@@ -162,6 +164,7 @@ gda_web_provider_class_init (GdaWebProviderClass *klass)
* because it only calls gda_statement_to_sql_extended() */
provider_class->statement_prepare = gda_web_provider_statement_prepare;
provider_class->statement_execute = gda_web_provider_statement_execute;
+ provider_class->statement_rewrite = gda_web_statement_rewrite;
provider_class->is_busy = NULL;
provider_class->cancel = NULL;
@@ -1517,6 +1520,40 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
continue;
}
}
+ else if (gda_holder_value_is_default (h) && !gda_holder_get_value (h)) {
+ /* create a new GdaStatement to handle all default values and execute it instead
+ * needs to be adapted to take into account how the database server handles default
+ * values (some accept the DEFAULT keyword), changing the 3rd argument of the
+ * gda_statement_rewrite_for_default_values() call
+ */
+ GdaSqlStatement *sqlst;
+ GError *lerror = NULL;
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, TRUE, &lerror);
+ if (!sqlst) {
+ event = gda_connection_point_available_event (cnc,
+ GDA_CONNECTION_EVENT_ERROR);
+ gda_connection_event_set_description (event, lerror && lerror->message ?
+ lerror->message :
+ _("Can't rewrite statement handle default values"));
+ g_propagate_error (error, lerror);
+ break;
+ }
+
+ GdaStatement *rstmt;
+ GObject *res;
+ rstmt = g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL);
+ gda_sql_statement_free (sqlst);
+ g_object_unref (ps);
+ xmlFreeDoc (doc);
+ res = gda_web_provider_statement_execute (provider, cnc,
+ rstmt, params,
+ model_usage,
+ col_types, last_inserted_row,
+ task_id,
+ async_cb, cb_data, error);
+ g_object_unref (rstmt);
+ return res;
+ }
/* actual binding using the C API, for parameter at position @i */
const GValue *value = gda_holder_get_value (h);
@@ -1637,6 +1674,22 @@ gda_web_provider_statement_execute (GdaServerProvider *provider, GdaConnection *
return retval;
}
+/*
+ * Rewrites a statement in case some parameters in @params are set to DEFAULT, for INSERT or UPDATE statements
+ *
+ * Removes any default value inserted or updated
+ */
+static GdaSqlStatement *
+gda_web_statement_rewrite (GdaServerProvider *provider, GdaConnection *cnc,
+ GdaStatement *stmt, GdaSet *params, GError **error)
+{
+ if (cnc) {
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+ }
+ return gda_statement_rewrite_for_default_values (stmt, params, TRUE, error);
+}
+
static gchar *
gda_web_identifier_quote (GdaServerProvider *provider, GdaConnection *cnc,
const gchar *id,
diff --git a/tests/parser/.gitignore b/tests/parser/.gitignore
index 5924de6..2da0e39 100644
--- a/tests/parser/.gitignore
+++ b/tests/parser/.gitignore
@@ -2,4 +2,5 @@ check_parser
check_validation
check_normalization
check_dml_comp
-check_script
\ No newline at end of file
+check_script
+check_rewrite_for_default
diff --git a/tests/parser/Makefile.am b/tests/parser/Makefile.am
index d4a7464..ee67543 100644
--- a/tests/parser/Makefile.am
+++ b/tests/parser/Makefile.am
@@ -7,8 +7,8 @@ AM_CPPFLAGS = \
-DTOP_BUILD_DIR=\""$(top_builddir)"\" \
-DTOP_SRC_DIR=\""$(top_srcdir)"\"
-TESTS = check_parser check_validation check_normalization check_dml_comp check_script
-check_PROGRAMS = check_parser check_validation check_normalization check_dml_comp check_script
+TESTS = check_parser check_validation check_normalization check_dml_comp check_script check_rewrite_for_default
+check_PROGRAMS = check_parser check_validation check_normalization check_dml_comp check_script check_rewrite_for_default
check_parser_SOURCES = check_parser.c
check_parser_LDADD = \
@@ -35,6 +35,12 @@ check_script_LDADD = \
$(top_builddir)/libgda/libgda-4.0.la \
$(LIBGDA_LIBS)
+check_rewrite_for_default_SOURCES = check_rewrite_for_default.c
+check_rewrite_for_default_LDADD = \
+ $(top_builddir)/libgda/libgda-4.0.la \
+ $(LIBGDA_LIBS)
+
+
EXTRA_DIST = testdata.xml testvalid.xml testscripts.xml \
scripts/mysql_employees.sql \
scripts/mysql_employees_partitioned.sql
diff --git a/tests/parser/check_rewrite_for_default.c b/tests/parser/check_rewrite_for_default.c
new file mode 100644
index 0000000..dc5cd72
--- /dev/null
+++ b/tests/parser/check_rewrite_for_default.c
@@ -0,0 +1,121 @@
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+#include <string.h>
+
+typedef struct {
+ gchar *sql;
+ gchar *rsql_remove;
+ gchar *rsql_default;
+} ATest;
+
+ATest tests[] = {
+ {"INSERT INTO mytable (name) VALUES (##name::string)",
+ "INSERT INTO mytable DEFAULT VALUES",
+ "INSERT INTO mytable (name) VALUES (DEFAULT)"},
+ {"INSERT INTO mytable (id, name) VALUES (23, ##name::string)",
+ "INSERT INTO mytable (id) VALUES (23)",
+ "INSERT INTO mytable (id, name) VALUES (23, DEFAULT)"},
+ {"UPDATE mytable set id=23, name=##name::string where 1",
+ NULL,
+ "UPDATE mytable SET id=23, name=DEFAULT WHERE 1"},
+ {"INSERT INTO mytable (id, name) VALUES (23, ##name::string), (44, 'joe')",
+ NULL,
+ "INSERT INTO mytable (id, name) VALUES (23, DEFAULT), (44, 'joe')"
+ },
+ {"INSERT INTO mytable (id, name) VALUES (23, ##name::string), (##id::int, 'joe')",
+ NULL,
+ "INSERT INTO mytable (id, name) VALUES (23, DEFAULT), (##id::int, 'joe')"
+ },
+ {"INSERT INTO mytable (id, name) VALUES (23, ##name::string), (##id::int, ##name::string)",
+ NULL,
+ "INSERT INTO mytable (id, name) VALUES (23, DEFAULT), (##id::int, DEFAULT)"
+ }
+};
+
+static gboolean
+do_test (ATest *test, GdaStatement *stmt, GdaSet *params, gboolean remove)
+{
+ gboolean retval = TRUE;
+ GdaSqlStatement *sqlst;
+ GError* error = NULL;
+
+ sqlst = gda_statement_rewrite_for_default_values (stmt, params, remove, &error);
+ if (!sqlst) {
+ gchar *exp;
+ exp = remove ? test->rsql_remove : test->rsql_default;
+ if (exp) {
+ g_print ("Can't rewrite stmt with %s option: %s\n", remove ? "REMOVE" : "DEFAULT keyword",
+ error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ retval = FALSE;
+ }
+ }
+ else {
+ GdaStatement *rstmt;
+ gchar *sql;
+ rstmt = GDA_STATEMENT (g_object_new (GDA_TYPE_STATEMENT, "structure", sqlst, NULL));
+
+ sql = gda_statement_to_sql (rstmt, NULL, &error);
+ if (sql) {
+ gchar *exp;
+ exp = remove ? test->rsql_remove : test->rsql_default;
+ if (g_strcmp0 (sql, exp)) {
+ g_print ("Error:\n exp: [%s]\n got: [%s]\n", exp, sql);
+ retval = FALSE;
+ }
+ g_free (sql);
+ }
+ else {
+ g_print ("Rendering error: %s\n", error && error->message ? error->message : "No detail");
+ g_clear_error (&error);
+ retval = FALSE;
+ }
+
+ g_object_unref (rstmt);
+ gda_sql_statement_free (sqlst);
+ }
+ return retval;
+}
+
+int main()
+{
+ gda_init();
+ GdaSqlParser *parser;
+ GdaStatement *stmt;
+ GdaSet *params;
+ GdaHolder *h;
+ GValue *value;
+ gint i;
+ gint n_errors = 0;
+
+ parser = gda_sql_parser_new ();
+
+ for (i = 0; i < sizeof (tests) / sizeof (ATest); i++) {
+ ATest *test = &tests[i];
+
+ stmt = gda_sql_parser_parse_string (parser, test->sql, NULL, NULL);
+ g_assert (stmt);
+ g_assert (gda_statement_get_parameters (stmt, ¶ms, NULL));
+
+ h = gda_set_get_holder (params, "name");
+ g_value_set_int ((value = gda_value_new (G_TYPE_INT)), 5);
+ gda_holder_set_default_value (h, value);
+ gda_value_free (value);
+ g_assert (gda_holder_set_value_to_default (h));
+
+ if (! do_test (test, stmt, params, TRUE))
+ n_errors++;
+ if (! do_test (test, stmt, params, FALSE))
+ n_errors++;
+ g_object_unref (params);
+ g_object_unref (stmt);
+ }
+
+ g_object_unref (parser);
+
+ if (n_errors == 0)
+ g_print ("Ok: %d tests passed\n", i*2);
+ else
+ g_print ("Failed: %d tests total, %d failed\n", i*2, n_errors);
+ return n_errors ? 1 : 0;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]