libgda r3105 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser libgda/sqlite providers/postgres tests/parser tools
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: libgda r3105 - in trunk: . doc/C doc/C/tmpl libgda libgda/sql-parser libgda/sqlite providers/postgres tests/parser tools
- Date: Wed, 2 Apr 2008 20:23:00 +0100 (BST)
Author: vivien
Date: Wed Apr 2 20:22:59 2008
New Revision: 3105
URL: http://svn.gnome.org/viewvc/libgda?rev=3105&view=rev
Log:
2008-04-02 Vivien Malerba <malerba gnome-db org>
* libgda/sqlite/gda-sqlite-provider.c: corrected mem leak (thanks to Phil Longstaff)
* libgda/gda-connection.c: corrected a mis-usage of variable number of arguments in
gda_connection_get_meta_store_data(), possibly fixes bug #524837
* libgda/gda-data-comparator.[ch]: new object to make it easy to compare the contents
of two data models.
* libgda/gda-server-provider.h:
* libgda/gda-connection.h:
* libgda/Makefile.am:
* libgda/libgda.h.in:
* libgda/gda-column-index.[ch]:
* libgda/gda-data-model-index.[ch]: removed useless code
* libgda/gda-data-model.c:
* libgda/gda-util.[ch]: removed unused functions: gda_utility_build_encoded_id(),
gda_utility_build_decoded_id(), gda_file_load(), gda_file_save(), gda_string_hash_to_list(),
and started to implement a new gda_compute_dml_statements() to compute INSERT, DELETE
and UPDATE statements corresponding to a SELECT statement (for writable data models)
* doc/C: added a HOWTO section for most common tasks, and misc. doc updates
* tools/gda-list-server-op.c: corrected version 3.0 to 4.0
* libgda/gda-statement.[ch]:
* libgda/sql-parser/gda-statement-struct.c: s/statement_check_connection/statement_check_validity/
for easier API understanding
* libgda/sql-parser/gda-statement-struct.[ch]:
* gda-statement-struct-parts.[ch]:
* gda-statement-struct-pspec.h: when validating a statement, first make sure it has a correct
structure, and then use a GdaMetaStruct object to find references to database objects.
* tests/parser/Makefile.am:
* tests/parser/testvalid.xml:
* tests/parser/check_validation.c: added a new test to verify statement validation and
computed (INSERT, UPDATE, DELETE) statements from SELECT statement
* libgda/gda-easy.[ch]:
* libgda/gda-init.c:
* libgda/gda-connection.[ch]: applied patch from Daniel Espinosa to implement the
gda_prepare_drop_table(), gda_perform_drop_table(), gda_prepare_create_table(),
gda_perform_create_table() and gda_connection_create_operation(), and also implemented
the gda_connection_perform_operation(), see bug #525603
* providers/postgres/gda-postgres-meta.c: code cleanup
* libgda/sql-parser/gda-statement-struct-*: added a check_validity() method which
can be implemented by some kind of statement to validate a statement using a
connection's meta data
* tests/parser/testvalid.xml:
* tests/parser/check_validation.c: new test for statement validation purposes
Added:
trunk/doc/C/howto.xml
trunk/doc/C/tmpl/gda-data-comparator.sgml
trunk/libgda/gda-data-comparator.c
trunk/libgda/gda-data-comparator.h
trunk/tests/parser/check_validation.c
trunk/tests/parser/testvalid.xml
Removed:
trunk/doc/C/tmpl/gda-column-index.sgml
trunk/doc/C/tmpl/gda-data-model-index.sgml
trunk/libgda/gda-column-index.c
trunk/libgda/gda-column-index.h
trunk/libgda/gda-data-model-index.c
trunk/libgda/gda-data-model-index.h
Modified:
trunk/ChangeLog
trunk/doc/C/gettingstarted.xml
trunk/doc/C/libgda-4.0-docs.sgml
trunk/doc/C/libgda-4.0-sections.txt
trunk/doc/C/libgda-4.0.types.in
trunk/doc/C/tmpl/gda-connection.sgml
trunk/doc/C/tmpl/gda-convenient.sgml
trunk/doc/C/tmpl/gda-sql-statement.sgml
trunk/doc/C/tmpl/gda-statement.sgml
trunk/doc/C/tmpl/gda-util.sgml
trunk/libgda/Makefile.am
trunk/libgda/gda-connection.c
trunk/libgda/gda-connection.h
trunk/libgda/gda-data-model.c
trunk/libgda/gda-easy.c
trunk/libgda/gda-easy.h
trunk/libgda/gda-init.c
trunk/libgda/gda-marshal.list
trunk/libgda/gda-meta-store.c
trunk/libgda/gda-meta-struct.c
trunk/libgda/gda-server-provider.c
trunk/libgda/gda-server-provider.h
trunk/libgda/gda-statement.c
trunk/libgda/gda-statement.h
trunk/libgda/gda-util.c
trunk/libgda/gda-util.h
trunk/libgda/libgda.h.in
trunk/libgda/sql-parser/gda-statement-struct-compound.c
trunk/libgda/sql-parser/gda-statement-struct-decl.h
trunk/libgda/sql-parser/gda-statement-struct-delete.c
trunk/libgda/sql-parser/gda-statement-struct-insert.c
trunk/libgda/sql-parser/gda-statement-struct-parts.c
trunk/libgda/sql-parser/gda-statement-struct-parts.h
trunk/libgda/sql-parser/gda-statement-struct-pspec.h
trunk/libgda/sql-parser/gda-statement-struct-select.c
trunk/libgda/sql-parser/gda-statement-struct-trans.c
trunk/libgda/sql-parser/gda-statement-struct-unknown.c
trunk/libgda/sql-parser/gda-statement-struct-update.c
trunk/libgda/sql-parser/gda-statement-struct.c
trunk/libgda/sql-parser/gda-statement-struct.h
trunk/libgda/sqlite/gda-sqlite-provider.c
trunk/providers/postgres/gda-postgres-meta.c
trunk/tests/parser/ (props changed)
trunk/tests/parser/Makefile.am
trunk/tools/gda-list-server-op.c
Modified: trunk/doc/C/gettingstarted.xml
==============================================================================
--- trunk/doc/C/gettingstarted.xml (original)
+++ trunk/doc/C/gettingstarted.xml Wed Apr 2 20:22:59 2008
@@ -55,7 +55,9 @@
<title>Connecting</title>
<para>
&LIBGDA; allows data sources (DSN) to be defined and refered to by a unique name which contains all the
- required information to actually open a connection (except the name and password if they are required). Of
+ required information to actually open a connection (except the name and password if they are required);
+ see the <link linkend="libgda-40-Configuration">Configuration section</link> for more information about
+ how to manage data sources. Of
course it's still possible to open a connection without having defined a DSN, in which case a <emphasis>connection
string</emphasis> is used to specify all the parameters resuired to open a connection. For more information
about connection strings, see the <link linkend="gda-connection-open-from-string">gda_connection_open_from_string ()</link>'s documentation.
@@ -74,6 +76,10 @@
g_print ("CONNECTING\n");
connection = gda_connection_open_from_dsn ("calvaris", NULL,
GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+ if (!connection) {
+ g_print ("CONNECTION FAILED\n");
+ return;
+ }
g_print ("CONNECTED\n");
/* use the connection */
Added: trunk/doc/C/howto.xml
==============================================================================
--- (empty file)
+++ trunk/doc/C/howto.xml Wed Apr 2 20:22:59 2008
@@ -0,0 +1,345 @@
+<chapter id="howto">
+ <title>HOWTO for common tasks</title>
+ <para>
+ This section is a list of small HOWTOs to get started quickly for some specific tasks, without the
+ need to read all the documentation: quickly get to the code and read the corresponding documentation
+ for further details.
+ </para>
+
+ <sect1>
+ <title>Open a connection</title>
+ <para>
+ Opening a connection to a database creates a <link linkend="GdaConnection">GdaConnection</link>
+ object which is required to execute commands. The connections' parameters (which are specific to each
+ type of database) can be either specified when opening the connection, or be used to define a
+ data source (<link linkend="connections">DSN</link>) and the DSN name is then specified to open the connection.
+ </para>
+ <para>
+ For example, opening a connection to a PostgreSQL database named "mydb" one could use the following code:
+ <programlisting>
+GdaConnection *connection;
+connection = gda_connection_open_from_string ("PostgreSQL", "DB_NAME=mydb",
+ "USERNAME=martin;PASSWORD=luther",
+ GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+if (!connection)
+ g_print ("CONNECTION FAILED\n");
+else {
+ /* use the opened connection */
+
+ /* close the connection (assuming it's not used by another object) */
+ g_object_unref (connection);
+}
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Define a data source (DSN)</title>
+ <para>
+ The <link linkend="libgda-40-Configuration">Configuration section</link> details how to manage data sources
+ definitions. To define a data source, one needs to create and fill a
+ <link linkend="GdaDataSourceInfo">GdaDataSourceInfo</link> structure, and use the
+ <link linkend="gda-config-define-dsn">gda_config_define_dsn()</link> function.
+ </para>
+ <para>
+ For example the following code defines a data source:
+ <programlisting>
+GError *error = NULL;
+GdaDataSourceInfo dsn_info = {
+ "My DSN",
+ "MySQL",
+ "Sample MySQL data source",
+ "HOST=myserver;DB_NAME=testdb"
+ NULL,
+ FALSE
+};
+if (!gda_config_define_dsn (&dsn_info, &error)) {
+ /* an error occurred, the details are in error */
+ g_error_free (error);
+}
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1 id="howto-exec-select">
+ <title>Execute a SELECT command</title>
+ <para>
+ Any SQL command in &LIBGDA; must be converted to a <link linkend="GdaStatement">GdaStatement</link> object
+ which is then executed; if the statement defines some variable (place holders), then variables binding
+ (assigning values to variables) is done at execution time. Each database provider (database
+ <emphasis>driver</emphasis> or <emphasis>adaptator</emphasis>) can implement its own parser to
+ be able to parse its specific SQL dialect. Except for binding variables, and for reusability, the
+ <link linkend="GdaStatement">GdaStatement</link> object guarantees that it contains only one SQL statement
+ (it's not possible for it to contain several ones separated by a semicolon).
+ </para>
+ <para>
+ Parsing an SQL statement into a <link linkend="GdaStatement">GdaStatement</link> object is the job of an
+ <link linkend="SqlParser">SqlParser</link>.
+ </para>
+ <para>
+ However when one only wants to run a simple SQL statement, &LIBGDA; provides the
+ <link linkend="gda-execute-select-command">gda_execute_select_command()</link> function which does
+ everything in one step. The following codes illustrates parsing and executing a SELECT statement:
+ </para>
+ <para>
+ <programlisting>
+GdaSqlParser *parser;
+GdaStatament *stmt;
+GError *error = NULL;
+
+parser = gda_connection_create_parser (cnc);
+if (!parser) {
+ /* the database provider used by cnc does not implement its own parser,
+ * let's use a generic one */
+ parser = gda_sql_parser_new ();
+stmt = gda_sql_parser_parse_string (parser, "SELECT * FROM customers", NULL, &error);
+g_object_unref (parser);
+if (!stmt) {
+ /* there was an error while parsing */
+}
+else {
+ GdaDataModel *model;
+ model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+ if (model) {
+ /* dump to results to STDOUT */
+ gda_data_model_dump (model, stdout);
+ g_object_unref (model);
+ }
+ else {
+ /* there was an error while executing the statement */
+ }
+}
+g_object_unref (stmt);
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1 id="howto-exec-non-select">
+ <title>Execute an INSERT, UPDATE or DELETE command</title>
+ <para>
+ INSERT, UPDATE or DELETE are treated in the same way as the SELECT command (see the
+ <link linkend="howto-exec-select">HOWTO</link> about executing
+ a SELECT command), except that the function to execute the command is different because the retuned value
+ is not a data model but a success/failure value.
+ </para>
+ <para>
+ The following codes illustrates parsing and executing an UPDATE statement:
+ <programlisting>
+GdaSqlParser *parser;
+GdaStatament *stmt;
+GError *error = NULL;
+
+parser = gda_connection_create_parser (cnc);
+if (!parser) {
+ /* the database provider used by cnc does not implement its own parser,
+ * let's use a generic one */
+ parser = gda_sql_parser_new ();
+stmt = gda_sql_parser_parse_string (parser, "UPDATE customers set name='Joe' WHERE id=123", NULL, &error);
+g_object_unref (parser);
+if (!stmt) {
+ /* there was an error while parsing */
+}
+else {
+ gint res;
+ res = gda_connection_statement_execute_non_select (cnc, stmt, NULL, NULL, &error);
+ if (res == -1) {
+ /* there was an error while executing the statement */
+ }
+ else if (res >= 0)
+ g_print ("Command Ok, %d row(s) impacted\n", res);
+ else
+ g_print ("Command Ok, number of rows impacted is not reported\n");
+}
+g_object_unref (stmt);
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Get the last inserted row</title>
+ <para>
+ &LIBGDA; allows one to get the last inserted row right after an INSERT statement has been
+ executed. &LIBGDA; returns a new <link linkend="GdaSet">GdaSet</link> object (which the caller
+ must unref when not needed anymore) which contains named values, one for each column of the
+ table in which data has been inserted. To get that object, pass a place holder to the
+ <parameter>last_insert_row</parameter> of
+ <link linkend="gda-connection-statement-execute-non-select">gda_connection_statement_execute_non_select()</link>
+ </para>
+ <para>
+ The following code example show how to use the returned <link linkend="GdaSet">GdaSet</link> object:
+ <programlisting>
+GdaSet *last_row;
+GdaStatement *stmt;
+stmt = gda_sql_parser_parse_string (parser, "INSERT INTO mytable (name) VALUES ('joe')", NULL, NULL);
+if (gda_connection_statement_execute_non_select (connection, stmt, NULL, &last_row, &error) == -1) {
+ g_warning ("Can't execute INSERT: %s\n",
+ error && error->message ? error->message : "???");
+ if (error)
+ g_error_free (error);
+}
+else {
+ if (!last_row)
+ g_print ("Last row not reported\n");
+ else {
+ GSList *list;
+ for (list = last_row->holders; list; list = list->next) {
+ GdaHolder *h = GDA_HOLDER (list->data);
+ gchar *str;
+ str = gda_value_stringify (gda_holder_get_value (h));
+ g_print ("\t%s => %s\n", gda_holder_get_id (h), str);
+ g_free (str);
+ }
+ g_object_unref (last_row);
+}
+g_object_unref (stmt);
+ </programlisting>
+ Which gives the following output (considering that in the example the "mytable" table has two columns: an Id
+ and a Name columns):
+ <programlisting>
+ +0 => 1
+ +1 => joe
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Execute a DDL command</title>
+ <para>
+ DDL commands (commands to modify the database schema such as create tables and views, change
+ users' access rights, etc) are treated in the same way as non select commands (refer to
+ the <link linkend="howto-exec-select">HOWTO</link> about executing non SELECT commands). However
+ &LIBGDA; offers a better and more portable way of executing such commands: using a
+ <link linkend="GdaServerOperation">GdaServerOperation</link> object.
+ </para>
+ <para>
+ Executing a DDL command involves the following steps:
+ <orderedlist>
+ <listitem><para>Request a new <link linkend="GdaServerOperation">GdaServerOperation</link> object from
+ the database provider for a specific operation using the
+ <link linkend="gda-server-provider-create-operation">gda_server_provider_create_operation()</link> function.
+ </para></listitem>
+ <listitem><para>Specify the <link linkend="GdaServerOperation">GdaServerOperation</link> object's
+ behaviour by setting some pre-defined parameters; for example when creating a table, the parameters
+ to be set include the tables name, the names of the columns, the constraints, etc. The list
+ of parameters to set is listed by the <link linkend="libgda-list-server-op">gda-list-server-op</link>
+ program.
+ </para></listitem>
+ <listitem><para>Ask the server provider to execute the operation based on the
+ <link linkend="GdaServerOperation">GdaServerOperation</link> object
+ </para></listitem>
+ </orderedlist>
+ </para>
+ <para>
+ The following code in part illustrates how to create a view:
+ <programlisting>
+GdaServerOperation *op;
+
+op = gda_connection_create_operation (cnc, GDA_SERVER_OPERATION_CREATE_VIEW, NULL, &error);
+if (!op)
+ /* there was an error while creating the GdaServerOperation object */
+else {
+ /* define the view to create */
+ if (!gda_server_operation_set_value_at (op, "myview", &error,
+ "/VIEW_DEF_P/VIEW_NAME") ||
+ !gda_server_operation_set_value_at (op, "SELECT * FROM customers", &error,
+ "/VIEW_DEF_P/VIEW_DEF"))
+ /* there was an error */
+ else {
+ if (! gda_connection_perform_operation (cnc, op, &error))
+ g_print ("Error\n");
+ else
+ g_print ("View created\n");
+ }
+ g_object_unref (op);
+}
+ </programlisting>
+ </para>
+ <para>
+ Please also note that &LIBGDA; provides some convenient functions to wrap this process, see the
+ <link linkend="libgda-40-Convenient-functions">Convenient functions</link> section for more
+ information.
+ </para>
+ </sect1>
+
+ <sect1 id="howto-meta1">
+ <title>Get information about a table's columns</title>
+ <para>
+ &LIBGDA; supports reporting meta data about a database (for which there is an opened connection). The
+ meta data are stored in a database (usually an in-memory database) which structure is close to the
+ information schema SQL standard (ISO/IEC 9075), and adapted (form information, this database is managed by a
+ <link linkend="GdaMetaStore">GdaMetaStore</link> object). As databases don't notify the changes made to
+ their objects, it is necessary to update (or synchronize) the meta data if the database's schema has been
+ changed, or if the meta data has not yet been extracted: call
+ <link linkend="gda-connection-update-meta-store">gda_connection_update_meta_store()</link> for this purpose.
+ </para>
+ <para>
+ One then needs to find the data requested among the (rather large) quantity of meta data available, there are
+ two possibilities:
+ <itemizedlist>
+ <listitem><para>Knowing the information schema's structure (tables and views) used,
+ run some SELECT commands on the
+ <link linkend="GdaMetaStore">GdaMetaStore</link> object's internal connection: this solution is the most
+ powerfull but requires some knowledge of the information schema's structure, and the data
+ is not easy to use.</para></listitem>
+ <listitem><para>Use a <link linkend="GdaMetaStruct">GdaMetaStruct</link> object which
+ <emphasis>exports</emphasis> the meta data as a dynamic tree of pre-defined data structures,
+ easy to use.</para></listitem>
+ </itemizedlist>
+ </para>
+ <para>
+ The following code shows how to list all the colums of the "customers" table of a connection (the connection
+ is assumed to already be opened):
+ <programlisting>
+GdaMetaStruct *mstruct;
+GdaMetaDbObject *dbo;
+GValue *table_name;
+if (!gda_connection_update_meta_store (cnc, NULL, &error)) {
+ /* there was an error */
+ return;
+}
+mstruct = gda_meta_struct_new (GDA_META_STRUCT_FEATURE_NONE);
+table_name = gda_value_new (G_TYPE_STRING);
+g_value_set_string (value, "customers");
+dbo = gda_meta_struct_complement (mstruct, gda_connection_get_meta_store (cnc),
+ GDA_META_DB_TABLE, NULL, NULL,
+ table_name, &error);
+gda_value_free (table_name);
+if (dbo) {
+ /* the "customers" table has been found, its details are in dbo */
+ GdaMetaTable *table = GDA_META_DB_OBJECT_GET_TABLE (dbo);
+ GSList *list;
+ for (list = table->columns: list; list = list->next)
+ g_print ("Column: %s\n", ((GdaMetaTableColumn*) list->data)->column_name);
+}
+else
+ g_print ("Table not found\n");
+g_object_unref (mstruct);
+ </programlisting>
+ </para>
+ </sect1>
+
+ <sect1>
+ <title>Validate a DML statement</title>
+ <para>
+ &LIBGDA; supports validating DML (SELECT, INSERT, UPDATE and DELETE) statements: making sure every
+ database object referenced in the statement actually exists in the database being accessed through
+ a connection.
+ The validation process involves the meta data associated to a connection, son one must make that
+ meta data is up to date with the database being accessed, using
+ <link linkend="gda-connection-update-meta-store">gda_connection_update_meta_store()</link> (also see the
+ <link linkend="howto-meta1">Get information about a table's columns</link> section).
+ </para>
+ <para>
+ The following code shows how to validate a statement (assuming the statement already exists):
+ <programlisting>
+if (!gda_statement_check_validity (stmt, cnc, &error))
+ g_print ("Invalid statement: %s\n",
+ error && error->message ? error->message : "No detail");
+else
+ g_print ("Statement is valid\n");
+ </programlisting>
+ </para>
+ </sect1>
+
+</chapter>
+
Modified: trunk/doc/C/libgda-4.0-docs.sgml
==============================================================================
--- trunk/doc/C/libgda-4.0-docs.sgml (original)
+++ trunk/doc/C/libgda-4.0-docs.sgml Wed Apr 2 20:22:59 2008
@@ -55,8 +55,6 @@
<!ENTITY libgda-GdaDataProxy SYSTEM "xml/gda-data-proxy.xml">
<!ENTITY libgda-GdaConnection-event SYSTEM "xml/gda-connection-event.xml">
<!ENTITY libgda-GdaColumn SYSTEM "xml/gda-column.xml">
-<!ENTITY libgda-GdaColumnIndex SYSTEM "xml/gda-column-index.xml">
-<!ENTITY libgda-GdaDataModelIndex SYSTEM "xml/gda-data-model-index.xml">
<!ENTITY libgda-init SYSTEM "xml/libgda.xml">
<!ENTITY libgda-log SYSTEM "xml/gda-log.xml">
<!ENTITY libgda-quark-list SYSTEM "xml/gda-quark-list.xml">
@@ -102,9 +100,11 @@
<!ENTITY libgda-PStmt SYSTEM "xml/gda-pstmt.xml">
<!ENTITY libgda-Enums SYSTEM "xml/gda-enums.xml">
<!ENTITY libgda-convenient SYSTEM "xml/gda-convenient.xml">
+<!ENTITY libgda-GdaDataComparator SYSTEM "xml/gda-data-comparator.xml">
<!ENTITY provider-writing SYSTEM "prov-writing.xml">
<!ENTITY provider-support SYSTEM "xml/provider-support.xml">
<!ENTITY fdl-appendix SYSTEM "fdl-appendix.sgml">
+<!ENTITY howto SYSTEM "howto.xml">
<!ENTITY libgda-TreeIndex SYSTEM "xml/tree_index.sgml">
]>
@@ -412,6 +412,7 @@
The following sections describe the API available for &GDA; applications.
</para>
+ &howto;
<chapter>
<title>Object Hierarchy</title>
&libgda-TreeIndex;
@@ -567,10 +568,9 @@
&libgda-GdaDataModelArray;
&libgda-GdaDataModelBdb;
&libgda-GdaDataModelDir;
- &libgda-GdaDataModelQuery;
&libgda-GdaDataProxy;
- &libgda-GdaDataModelIndex;
- &libgda-GdaColumnIndex;
+ &libgda-GdaDataComparator;
+ &libgda-GdaDataModelQuery;
<para>
The following UML diagram shows the various implementations of the GdaDataModel interface and their usage:
<mediaobject>
Modified: trunk/doc/C/libgda-4.0-sections.txt
==============================================================================
--- trunk/doc/C/libgda-4.0-sections.txt (original)
+++ trunk/doc/C/libgda-4.0-sections.txt Wed Apr 2 20:22:59 2008
@@ -1,32 +1,4 @@
<SECTION>
-<FILE>gda-column-index</FILE>
-<TITLE>GdaColumnIndex</TITLE>
-GdaColumnIndex
-GdaSorting
-GdaColumnIndex
-GdaColumnIndexClass
-GdaColumnIndexPrivate
-gda_column_index_new
-gda_column_index_copy
-gda_column_index_equal
-gda_column_index_get_column_name
-gda_column_index_set_column_name
-gda_column_index_get_defined_size
-gda_column_index_set_defined_size
-gda_column_index_get_sorting
-gda_column_index_set_sorting
-gda_column_index_get_references
-gda_column_index_set_references
-<SUBSECTION Standard>
-GDA_COLUMN_INDEX
-GDA_COLUMN_INDEX_CLASS
-GDA_IS_COLUMN_INDEX
-GDA_IS_COLUMN_INDEX_CLASS
-GDA_TYPE_COLUMN_INDEX
-gda_column_index_get_type
-</SECTION>
-
-<SECTION>
<FILE>gda-column</FILE>
<TITLE>GdaColumn</TITLE>
GdaColumn
@@ -174,8 +146,12 @@
gda_connection_get_events
gda_connection_clear_events_list
<SUBSECTION>
+gda_connection_create_operation
+gda_connection_perform_operation
+<SUBSECTION>
GdaConnectionFeature
gda_connection_supports_feature
+gda_connection_get_meta_store
gda_connection_update_meta_store
GdaConnectionMetaType
gda_connection_get_meta_store_data
@@ -318,32 +294,6 @@
gda_data_access_wrapper_get_type
</SECTION>
-
-<SECTION>
-<FILE>gda-data-model-index</FILE>
-<TITLE>GdaDataModelIndex</TITLE>
-GdaDataModelIndex
-gda_data_model_index_new
-gda_data_model_index_copy
-gda_data_model_index_free
-gda_data_model_index_equal
-gda_data_model_index_get_name
-gda_data_model_index_set_name
-gda_data_model_index_get_table_name
-gda_data_model_index_set_table_name
-gda_data_model_index_get_primary_key
-gda_data_model_index_set_primary_key
-gda_data_model_index_get_unique_key
-gda_data_model_index_set_unique_key
-gda_data_model_index_get_references
-gda_data_model_index_set_references
-gda_data_model_index_get_column_index_list
-gda_data_model_index_set_column_index_list
-<SUBSECTION Standard>
-GDA_TYPE_DATA_MODEL_INDEX
-gda_data_model_index_get_type
-</SECTION>
-
<SECTION>
<FILE>gda-data-model</FILE>
<TITLE>GdaDataModel</TITLE>
@@ -965,8 +915,10 @@
gda_execute_select_command
gda_execute_non_select_command
<SUBSECTION>
-gda_create_table
-gda_drop_table
+gda_prepare_create_table
+gda_perform_create_table
+gda_prepare_drop_table
+gda_perform_drop_table
<SUBSECTION>
gda_insert_row_into_table
gda_insert_row_into_table_from_string
@@ -1130,7 +1082,7 @@
gda_statement_get_statement_type
gda_statement_is_useless
gda_statement_check_structure
-gda_statement_check_connection
+gda_statement_check_validity
<SUBSECTION Standard>
GDA_IS_STATEMENT
GDA_STATEMENT
@@ -1190,7 +1142,7 @@
gda_sql_statement_type_to_string
gda_sql_statement_string_to_type
gda_sql_statement_check_structure
-gda_sql_statement_check_connection
+gda_sql_statement_check_validity
gda_sql_statement_check_clean
<SUBSECTION>
GdaSqlAnyPart
@@ -1474,3 +1426,25 @@
<SUBSECTION>
gda_connection_get_meta_store
</SECTION>
+
+<SECTION>
+<FILE>gda-data-comparator</FILE>
+<TITLE>GdaDataComparator</TITLE>
+GdaDataComparator
+GdaDataComparatorClass
+GdaDataComparatorPrivate
+gda_data_comparator_new
+gda_data_comparator_set_key_columns
+GdaDiff
+GdaDiffType
+gda_data_comparator_compute_diff
+gda_data_comparator_get_n_diffs
+gda_data_comparator_get_diff
+<SUBSECTION Standard>
+GDA_DATA_COMPARATOR
+GDA_DATA_COMPARATOR_CLASS
+GDA_DATA_COMPARATOR_ERROR
+GDA_IS_DATA_COMPARATOR
+GDA_TYPE_DATA_COMPARATOR
+gda_data_comparator_get_type
+</SECTION>
Modified: trunk/doc/C/libgda-4.0.types.in
==============================================================================
--- trunk/doc/C/libgda-4.0.types.in (original)
+++ trunk/doc/C/libgda-4.0.types.in Wed Apr 2 20:22:59 2008
@@ -8,7 +8,6 @@
#include <DocBook/gda-report-docbook-document.h>
gda_blob_op_get_type
gda_column_get_type
-gda_column_index_get_type
gda_config_get_type
gda_connection_get_type
gda_connection_event_get_type
@@ -25,7 +24,6 @@
gda_data_model_row_get_type
gda_data_model_get_type
gda_data_model_import_get_type
-gda_data_model_index_get_type
gda_data_model_iter_get_type
gda_data_model_query_get_type
gda_data_access_wrapper_get_type
Modified: trunk/doc/C/tmpl/gda-connection.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-connection.sgml (original)
+++ trunk/doc/C/tmpl/gda-connection.sgml Wed Apr 2 20:22:59 2008
@@ -458,6 +458,29 @@
@cnc:
+<!-- ##### FUNCTION gda_connection_create_operation ##### -->
+<para>
+
+</para>
+
+ cnc:
+ type:
+ options:
+ error:
+ Returns:
+
+
+<!-- ##### FUNCTION gda_connection_perform_operation ##### -->
+<para>
+
+</para>
+
+ cnc:
+ op:
+ error:
+ Returns:
+
+
<!-- ##### ENUM GdaConnectionFeature ##### -->
<para>
@@ -490,6 +513,15 @@
@Returns:
+<!-- ##### FUNCTION gda_connection_get_meta_store ##### -->
+<para>
+
+</para>
+
+ cnc:
+ Returns:
+
+
<!-- ##### FUNCTION gda_connection_update_meta_store ##### -->
<para>
Modified: trunk/doc/C/tmpl/gda-convenient.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-convenient.sgml (original)
+++ trunk/doc/C/tmpl/gda-convenient.sgml Wed Apr 2 20:22:59 2008
@@ -81,7 +81,7 @@
@Returns:
-<!-- ##### FUNCTION gda_create_table ##### -->
+<!-- ##### FUNCTION gda_prepare_create_table ##### -->
<para>
</para>
@@ -93,7 +93,17 @@
@Returns:
-<!-- ##### FUNCTION gda_drop_table ##### -->
+<!-- ##### FUNCTION gda_perform_create_table ##### -->
+<para>
+
+</para>
+
+ op:
+ error:
+ Returns:
+
+
+<!-- ##### FUNCTION gda_prepare_drop_table ##### -->
<para>
</para>
@@ -104,6 +114,16 @@
@Returns:
+<!-- ##### FUNCTION gda_perform_drop_table ##### -->
+<para>
+
+</para>
+
+ op:
+ error:
+ Returns:
+
+
<!-- ##### FUNCTION gda_insert_row_into_table ##### -->
<para>
Added: trunk/doc/C/tmpl/gda-data-comparator.sgml
==============================================================================
--- (empty file)
+++ trunk/doc/C/tmpl/gda-data-comparator.sgml Wed Apr 2 20:22:59 2008
@@ -0,0 +1,124 @@
+<!-- ##### SECTION Title ##### -->
+GdaDataComparator
+
+<!-- ##### SECTION Short_Description ##### -->
+Simple data model's contents comparison
+
+<!-- ##### SECTION Long_Description ##### -->
+<para>
+ The #GdaDataComparator is a simple object which takes two #GdaDataModel objects and compare them.
+ Actual comparison is performed when the gda_data_comparator_compute_diff() is called; for each
+ difference found, the <link linkend="GdaDataComparator-diff-computed">diff-computed</link> signal
+ is emitted (any user installed signal handler which returns FALSE stops the computing process).
+</para>
+<para>
+ After the differences have been computed, they can each be accessed using gda_data_comparator_get_diff(),
+ the number of differences found being returned by gda_data_comparator_get_n_diffs().
+</para>
+<para>
+ There are some limitations to this object:
+ <itemizedlist>
+ <listitem><para>The data models compared must have the same number and type of columns</para></listitem>
+ <listitem><para>The comparison is done column-for-column: one cannot omit columns in the comparison, nor compare
+ columns with different positions</para></listitem>
+ </itemizedlist>
+</para>
+
+<!-- ##### SECTION See_Also ##### -->
+<para>
+
+</para>
+
+<!-- ##### SECTION Stability_Level ##### -->
+
+
+<!-- ##### STRUCT GdaDataComparator ##### -->
+<para>
+
+</para>
+
+ object:
+ priv:
+
+<!-- ##### STRUCT GdaDataComparatorClass ##### -->
+<para>
+
+</para>
+
+ parent_class:
+ diff_computed:
+
+<!-- ##### STRUCT GdaDataComparatorPrivate ##### -->
+<para>
+
+</para>
+
+
+<!-- ##### FUNCTION gda_data_comparator_new ##### -->
+<para>
+
+</para>
+
+ old_model:
+ new_model:
+ Returns:
+
+
+<!-- ##### FUNCTION gda_data_comparator_set_key_columns ##### -->
+<para>
+
+</para>
+
+ comp:
+ col_numbers:
+ nb_cols:
+
+
+<!-- ##### STRUCT GdaDiff ##### -->
+<para>
+
+</para>
+
+ type:
+ old_row:
+ new_row:
+ values:
+
+<!-- ##### ENUM GdaDiffType ##### -->
+<para>
+
+</para>
+
+ GDA_DIFF_ADD_ROW:
+ GDA_DIFF_REMOVE_ROW:
+ GDA_DIFF_MODIFY_ROW:
+
+<!-- ##### FUNCTION gda_data_comparator_compute_diff ##### -->
+<para>
+
+</para>
+
+ comp:
+ error:
+ Returns:
+
+
+<!-- ##### FUNCTION gda_data_comparator_get_n_diffs ##### -->
+<para>
+
+</para>
+
+ comp:
+ Returns:
+
+
+<!-- ##### FUNCTION gda_data_comparator_get_diff ##### -->
+<para>
+
+</para>
+
+ comp:
+ pos:
+ Returns:
+
+
Modified: trunk/doc/C/tmpl/gda-sql-statement.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-sql-statement.sgml (original)
+++ trunk/doc/C/tmpl/gda-sql-statement.sgml Wed Apr 2 20:22:59 2008
@@ -43,6 +43,7 @@
@stmt_type: the type of statement (SELECT, INSERT, etc) as a #GdaSqlStatementType enum
@contents: the actual contents of the statement, depends on @stmt_type (can be a pointer to a
#GdaSqlStatementSelect, #GdaSqlStatementInsert, etc)
+ validity_meta_struct:
<!-- ##### ENUM GdaSqlStatementType ##### -->
<para>
@@ -126,7 +127,7 @@
@Returns:
-<!-- ##### FUNCTION gda_sql_statement_check_connection ##### -->
+<!-- ##### FUNCTION gda_sql_statement_check_validity ##### -->
<para>
</para>
@@ -688,7 +689,7 @@
@is_param:
@nullok:
@g_type:
- dict_type:
+ validity_meta_dict:
<!-- ##### FUNCTION gda_sql_param_spec_new ##### -->
<para>
@@ -768,6 +769,7 @@
@any: inheritance structure
@field_name: a table's field name, in the form [[[catalog.]schema.]table.]field_name
+ validity_meta_table_column:
<!-- ##### FUNCTION gda_sql_field_new ##### -->
<para>
@@ -820,7 +822,7 @@
@any: inheritance structure
@table_name: a table's name, in the form [[catalog.]schema.]table
- full_table_name:
+ validity_meta_object:
<!-- ##### FUNCTION gda_sql_table_new ##### -->
<para>
@@ -874,7 +876,7 @@
@any: inheritance structure
@function_name: name of the function , in the form [[catalog.]schema.]function_name
@args_list: list of #GdaSqlExpr expressions, one for each argument
- full_function_name:
+ validity_meta_function:
<!-- ##### FUNCTION gda_sql_function_new ##### -->
<para>
@@ -1084,7 +1086,8 @@
@field_name: field name part of @expr if @expr represents a field
@table_name: table name part of @expr if @expr represents a field
@as: alias
- full_table_name:
+ validity_meta_object:
+ validity_meta_table_column:
<!-- ##### FUNCTION gda_sql_select_field_new ##### -->
<para>
@@ -1158,7 +1161,7 @@
@expr: expression
@table_name: table name part of @expr if @expr represents a table
@as: alias
- full_table_name:
+ validity_meta_object:
<!-- ##### FUNCTION gda_sql_select_target_new ##### -->
<para>
Modified: trunk/doc/C/tmpl/gda-statement.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-statement.sgml (original)
+++ trunk/doc/C/tmpl/gda-statement.sgml Wed Apr 2 20:22:59 2008
@@ -195,7 +195,7 @@
@Returns:
-<!-- ##### FUNCTION gda_statement_check_connection ##### -->
+<!-- ##### FUNCTION gda_statement_check_validity ##### -->
<para>
</para>
Modified: trunk/doc/C/tmpl/gda-util.sgml
==============================================================================
--- trunk/doc/C/tmpl/gda-util.sgml (original)
+++ trunk/doc/C/tmpl/gda-util.sgml Wed Apr 2 20:22:59 2008
@@ -17,15 +17,6 @@
<!-- ##### SECTION Stability_Level ##### -->
-<!-- ##### FUNCTION gda_string_hash_to_list ##### -->
-<para>
-
-</para>
-
- hash_table:
- Returns:
-
-
<!-- ##### FUNCTION gda_default_escape_string ##### -->
<para>
@@ -35,26 +26,6 @@
@Returns:
-<!-- ##### FUNCTION gda_file_load ##### -->
-<para>
-
-</para>
-
- filename:
- Returns:
-
-
-<!-- ##### FUNCTION gda_file_save ##### -->
-<para>
-
-</para>
-
- filename:
- buffer:
- len:
- Returns:
-
-
<!-- ##### FUNCTION gda_server_provider_get_schema_nb_columns ##### -->
<para>
Modified: trunk/libgda/Makefile.am
==============================================================================
--- trunk/libgda/Makefile.am (original)
+++ trunk/libgda/Makefile.am Wed Apr 2 20:22:59 2008
@@ -28,11 +28,11 @@
gda-batch.h \
gda-blob-op.h \
gda-column.h \
- gda-column-index.h \
gda-config.h \
gda-connection-event.h \
gda-connection.h \
gda-connection-private.h \
+ gda-data-comparator.h \
gda-data-handler.h \
gda-data-model-array.h \
gda-data-model-row.h \
@@ -41,7 +41,6 @@
gda-data-model-dir.h \
gda-data-model-extra.h \
gda-data-model-import.h \
- gda-data-model-index.h \
gda-data-model-iter.h \
gda-data-model-private.h \
gda-data-model-query.h \
@@ -81,10 +80,10 @@
$(gda_headers) \
gda-blob-op.c \
gda-column.c \
- gda-column-index.c \
gda-config.c \
gda-connection.c \
gda-connection-event.c \
+ gda-data-comparator.c \
gda-data-handler.c \
gda-data-model-array.c \
$(GDA_BDB_S) \
@@ -94,7 +93,6 @@
gda-data-model-dsn-list.c \
gda-data-model-dsn-list.h \
gda-data-model-import.c \
- gda-data-model-index.c \
gda-data-model-iter.c \
gda-data-model-query.c \
gda-data-access-wrapper.c \
Modified: trunk/libgda/gda-connection.c
==============================================================================
--- trunk/libgda/gda-connection.c (original)
+++ trunk/libgda/gda-connection.c Wed Apr 2 20:22:59 2008
@@ -1074,6 +1074,54 @@
}
/**
+ * gda_connection_create_operation
+ * @cnc: a #GdaConnection object
+ * @type: the type of operation requested
+ * @options: an optional list of parameters
+ * @error: a place to store an error, or %NULL
+ *
+ * Creates a new #GdaServerOperation object which can be modified in order
+ * to perform the type type of action. It is a wrapper around the gda_server_provider_create_operation()
+ * method.
+ *
+ * Returns: a new #GdaServerOperation object, or %NULL in the connection's provider does not support the @type type
+ * of operation or if an error occurred
+ */
+GdaServerOperation*
+gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type,
+ GdaSet *options, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+ g_return_val_if_fail (cnc->priv, NULL);
+ g_return_val_if_fail (cnc->priv->provider_obj, NULL);
+
+ return gda_server_provider_create_operation (cnc->priv->provider_obj, cnc, type, options, error);
+}
+
+/**
+ * gda_connection_perform_operation
+ * @cnc: a #GdaConnection object
+ * @op: a #GdaServerOperation object
+ * @error: a place to store an error, or %NULL
+ *
+ * Performs the operation described by @op (which should have been created using
+ * gda_connection_create_operation()). It is a wrapper around the gda_server_provider_perform_operation()
+ * method.
+ *
+ * Returns: TRUE if no error occurred
+ */
+gboolean
+gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error)
+{
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (cnc->priv, FALSE);
+ g_return_val_if_fail (cnc->priv->provider_obj, FALSE);
+ g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
+
+ return gda_server_provider_perform_operation (cnc->priv->provider_obj, cnc, op, error);
+}
+
+/**
* gda_connection_create_parser
* @cnc: a #GdaConnection object
*
@@ -1082,7 +1130,7 @@
* then %NULL is returned, and a general SQL parser can be obtained
* using gda_sql_parser_new().
*
- * Returns: a new #GdaSqlParser object
+ * Returns: a new #GdaSqlParser object, or %NULL
*/
GdaSqlParser *
gda_connection_create_parser (GdaConnection *cnc)
@@ -2902,7 +2950,6 @@
static GHashTable *stmt_hash = NULL;
GdaStatement *stmt;
GdaSet *set = NULL;
- va_list ap;
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
g_return_val_if_fail (cnc->priv->provider_obj, NULL);
@@ -2919,24 +2966,28 @@
stmt_hash = prepare_meta_statements_hash ();
key.meta_type = meta_type;
key.nb_filters = nb_filters;
- key.filters = g_new (gchar *, nb_filters);
- va_start (ap, nb_filters);
- for (i = 0, fname = va_arg (ap, gchar*); fname && (i < nb_filters); fname = va_arg (ap, gchar*), i++) {
- GdaHolder *h;
- GValue *v;
-
- v = va_arg (ap, GValue*);
- if (!v || gda_value_is_null (v))
- continue;
- if (!set)
- set = gda_set_new (NULL);
- h = g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (v), "id", fname, NULL);
- gda_holder_set_value (h, v);
- gda_set_add_holder (set, h);
- g_object_unref (h);
- key.filters[i] = fname;
+ key.filters = NULL;
+ if (nb_filters > 0) {
+ va_list ap;
+ key.filters = g_new (gchar *, nb_filters);
+ va_start (ap, nb_filters);
+ for (i = 0, fname = va_arg (ap, gchar*); fname && (i < nb_filters); fname = va_arg (ap, gchar*), i++) {
+ GdaHolder *h;
+ GValue *v;
+
+ v = va_arg (ap, GValue*);
+ if (!v || gda_value_is_null (v))
+ continue;
+ if (!set)
+ set = gda_set_new (NULL);
+ h = g_object_new (GDA_TYPE_HOLDER, "g-type", G_VALUE_TYPE (v), "id", fname, NULL);
+ gda_holder_set_value (h, v);
+ gda_set_add_holder (set, h);
+ g_object_unref (h);
+ key.filters[i] = fname;
+ }
+ va_end (ap);
}
- va_end (ap);
stmt = g_hash_table_lookup (stmt_hash, &key);
g_free (key.filters);
if (!stmt) {
Modified: trunk/libgda/gda-connection.h
==============================================================================
--- trunk/libgda/gda-connection.h (original)
+++ trunk/libgda/gda-connection.h Wed Apr 2 20:22:59 2008
@@ -28,11 +28,11 @@
#include "gda-decl.h"
#include <libgda/gda-data-model.h>
-#include <libgda/gda-data-model-index.h>
#include <libgda/gda-connection-event.h>
#include <libgda/gda-transaction-status.h>
#include <libgda/gda-statement.h>
#include <libgda/gda-meta-store.h>
+#include <libgda/gda-server-operation.h>
G_BEGIN_DECLS
@@ -145,6 +145,10 @@
GdaServerProvider *gda_connection_get_provider_obj (GdaConnection *cnc);
const gchar *gda_connection_get_provider_name (GdaConnection *cnc);
+GdaServerOperation *gda_connection_create_operation (GdaConnection *cnc, GdaServerOperationType type,
+ GdaSet *options, GError **error);
+gboolean gda_connection_perform_operation (GdaConnection *cnc, GdaServerOperation *op, GError **error);
+
const gchar *gda_connection_get_dsn (GdaConnection *cnc);
gboolean gda_connection_set_dsn (GdaConnection *cnc, const gchar *datasource);
const gchar *gda_connection_get_cnc_string (GdaConnection *cnc);
Added: trunk/libgda/gda-data-comparator.c
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-data-comparator.c Wed Apr 2 20:22:59 2008
@@ -0,0 +1,590 @@
+/* gda-data-comparator.c
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include "gda-data-comparator.h"
+#include "gda-marshal.h"
+#include "gda-data-model.h"
+
+/*
+ * Main static functions
+ */
+static void gda_data_comparator_class_init (GdaDataComparatorClass * class);
+static void gda_data_comparator_init (GdaDataComparator *srv);
+static void gda_data_comparator_dispose (GObject *object);
+static void gda_data_comparator_finalize (GObject *object);
+
+static void gda_data_comparator_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gda_data_comparator_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+/* get a pointer to the parents to be able to call their destructor */
+static GObjectClass *parent_class = NULL;
+
+static void gda_diff_free (GdaDiff *diff);
+
+/* signals */
+enum
+{
+ DIFF_COMPUTED,
+ LAST_SIGNAL
+};
+
+static gint gda_data_comparator_signals[LAST_SIGNAL] = { 0 };
+
+
+/* properties */
+enum
+{
+ PROP_0,
+ PROP_OLD_MODEL,
+ PROP_NEW_MODEL
+};
+
+struct _GdaDataComparatorPrivate
+{
+ GdaDataModel *old_model;
+ GdaDataModel *new_model;
+ gint nb_key_columns;
+ gint *key_columns;
+ GArray *diffs; /* array of GdaDiff pointers */
+};
+
+
+/* module error */
+GQuark gda_data_comparator_error_quark (void)
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("gda_data_comparator_error");
+ return quark;
+}
+
+GType
+gda_data_comparator_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ static const GTypeInfo info = {
+ sizeof (GdaDataComparatorClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gda_data_comparator_class_init,
+ NULL,
+ NULL,
+ sizeof (GdaDataComparator),
+ 0,
+ (GInstanceInitFunc) gda_data_comparator_init
+ };
+
+ type = g_type_register_static (G_TYPE_OBJECT, "GdaDataComparator", &info, 0);
+ }
+ return type;
+}
+
+static gboolean
+diff_computed_accumulator (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer data)
+{
+ gboolean thisvalue;
+
+ thisvalue = g_value_get_boolean (handler_return);
+ g_value_set_boolean (return_accu, thisvalue);
+
+ return thisvalue; /* stop signal if 'thisvalue' is FALSE */
+}
+
+static gboolean
+m_diff_computed (GdaDataComparator *comparator, GdaDiff *diff)
+{
+ return TRUE; /* default is to allow differences computing to proceed */
+}
+
+static void
+gda_data_comparator_class_init (GdaDataComparatorClass *class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (class);
+
+ parent_class = g_type_class_peek_parent (class);
+
+ /* signals */
+
+ gda_data_comparator_signals [DIFF_COMPUTED] =
+ g_signal_new ("diff_computed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdaDataComparatorClass, diff_computed),
+ diff_computed_accumulator, NULL,
+ gda_marshal_BOOLEAN__POINTER, G_TYPE_BOOLEAN, 1, G_TYPE_POINTER);
+
+ class->diff_computed = m_diff_computed;
+
+ /* virtual functions */
+ object_class->dispose = gda_data_comparator_dispose;
+ object_class->finalize = gda_data_comparator_finalize;
+
+ /* Properties */
+ object_class->set_property = gda_data_comparator_set_property;
+ object_class->get_property = gda_data_comparator_get_property;
+
+ g_object_class_install_property (object_class, PROP_OLD_MODEL,
+ g_param_spec_object ("old-model", _("Old data model"), NULL,
+ GDA_TYPE_DATA_MODEL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property (object_class, PROP_NEW_MODEL,
+ g_param_spec_object ("new-model", _("New data model"), NULL,
+ GDA_TYPE_DATA_MODEL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+}
+
+static void
+gda_data_comparator_init (GdaDataComparator *comparator)
+{
+ comparator->priv = g_new0 (GdaDataComparatorPrivate, 1);
+ comparator->priv->diffs = g_array_new (FALSE, FALSE, sizeof (GdaDiff *));
+}
+
+/**
+ * gda_data_comparator_new
+ * @old_model: Data model to which the modifications should be applied
+ * @new_model: Target data model.
+ *
+ * Creates a new comparator to compute the differences from @old_model to @new_model: if one applies
+ * all the computed differences (as #GdaDiff structures) to @old_model, the resulting data model
+ * should have the same contents as @new_model.
+ *
+ * Returns: a new #GdaDataComparator object
+ */
+GObject *
+gda_data_comparator_new (GdaDataModel *old_model, GdaDataModel *new_model)
+{
+ GObject *obj;
+
+ g_return_val_if_fail (GDA_IS_DATA_MODEL (old_model), NULL);
+ g_return_val_if_fail (GDA_IS_DATA_MODEL (new_model), NULL);
+
+ obj = g_object_new (GDA_TYPE_DATA_COMPARATOR, "old-model", old_model, "new-model", new_model, NULL);
+
+ return obj;
+}
+
+static void
+clean_diff (GdaDataComparator *comparator)
+{
+ if (comparator->priv->diffs) {
+ gint i;
+ for (i = 0; i < comparator->priv->diffs->len; i++) {
+ GdaDiff *diff = g_array_index (comparator->priv->diffs, GdaDiff *, i);
+ gda_diff_free (diff);
+ }
+ g_array_free (comparator->priv->diffs, TRUE);
+ }
+ comparator->priv->diffs = g_array_new (FALSE, FALSE, sizeof (GdaDiff *));
+}
+
+static void
+gda_data_comparator_dispose (GObject *object)
+{
+ GdaDataComparator *comparator;
+
+ g_return_if_fail (GDA_IS_DATA_COMPARATOR (object));
+
+ comparator = GDA_DATA_COMPARATOR (object);
+ if (comparator->priv) {
+ if (comparator->priv->old_model) {
+ g_object_unref (comparator->priv->old_model);
+ comparator->priv->old_model = NULL;
+ }
+ if (comparator->priv->new_model) {
+ g_object_unref (comparator->priv->new_model);
+ comparator->priv->new_model = NULL;
+ }
+ clean_diff (comparator);
+ g_free (comparator->priv->key_columns);
+ g_array_free (comparator->priv->diffs, TRUE);
+ }
+
+ /* parent class */
+ parent_class->dispose (object);
+}
+
+static void
+gda_data_comparator_finalize (GObject *object)
+{
+ GdaDataComparator *comparator;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GDA_IS_DATA_COMPARATOR (object));
+
+ comparator = GDA_DATA_COMPARATOR (object);
+ if (comparator->priv) {
+ g_free (comparator->priv);
+ comparator->priv = NULL;
+ }
+
+ /* parent class */
+ parent_class->finalize (object);
+}
+
+
+static void
+gda_data_comparator_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdaDataComparator *comparator;
+ comparator = GDA_DATA_COMPARATOR (object);
+ if (comparator->priv) {
+ GdaDataModel *model;
+
+ switch (param_id) {
+ case PROP_OLD_MODEL:
+ model = (GdaDataModel*) g_value_get_object (value);
+ if (comparator->priv->old_model && (comparator->priv->old_model != model)) {
+ /* re-init */
+ clean_diff (comparator);
+ g_object_unref (comparator->priv->old_model);
+ g_free (comparator->priv->key_columns);
+ comparator->priv->key_columns = NULL;
+ }
+ comparator->priv->old_model = model;
+ if (model)
+ g_object_ref (model);
+ break;
+ case PROP_NEW_MODEL:
+ model = (GdaDataModel*) g_value_get_object (value);
+ if (comparator->priv->new_model && (comparator->priv->new_model != model)) {
+ /* re-init */
+ clean_diff (comparator);
+ g_object_unref (comparator->priv->new_model);
+ g_free (comparator->priv->key_columns);
+ comparator->priv->key_columns = NULL;
+ }
+ comparator->priv->new_model = model;
+ if (model)
+ g_object_ref (model);
+ break;
+ }
+ }
+}
+
+static void
+gda_data_comparator_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdaDataComparator *comparator;
+
+ comparator = GDA_DATA_COMPARATOR (object);
+ if (comparator->priv) {
+ switch (param_id) {
+ case PROP_OLD_MODEL:
+ g_value_set_object (value, comparator->priv->old_model);
+ break;
+ case PROP_NEW_MODEL:
+ g_value_set_object (value, comparator->priv->new_model);
+ break;
+ }
+ }
+}
+
+static void
+gda_diff_free (GdaDiff *diff)
+{
+ g_hash_table_destroy (diff->values);
+ g_free (diff);
+}
+
+/**
+ * gda_data_comparator_set_key_columns
+ * @comp: a #GdaDataComparator object
+ * @nb_cols: the size of the @col_numbers array
+ * @col_numbers: a array of @nb_cols values
+ *
+ * Defines the columns which will be used as a key when searching data. This is not mandatory but
+ * will speed things up as less data will be processed.
+ */
+void
+gda_data_comparator_set_key_columns (GdaDataComparator *comp, gint *col_numbers, gint nb_cols)
+{
+ g_return_if_fail (GDA_IS_DATA_COMPARATOR (comp));
+ g_return_if_fail (comp->priv);
+
+ g_free (comp->priv->key_columns);
+ comp->priv->key_columns = NULL;
+ if (nb_cols > 0) {
+ comp->priv->nb_key_columns = nb_cols;
+ comp->priv->key_columns = g_new0 (gint, nb_cols);
+ memcpy (comp->priv->key_columns, col_numbers, sizeof (gint) * nb_cols);
+ }
+}
+
+/*
+ * Find the row in @comp->priv->old_model from the values of @comp->priv->new_model at line @row
+ * It is assumed that both data model have the same number of columns and of "compatible" types.
+ *
+ * Returns:
+ * -1 if not found,
+ * >=0 if found (if changes need to be made, then @out_has_changed is set to TRUE).
+ */
+static gint
+find_row_in_model (GdaDataComparator *comp, gint row, gboolean *out_has_changed, GError **error)
+{
+ gint i, erow;
+ gint ncols;
+ GSList *values = NULL;
+
+ *out_has_changed = FALSE;
+ ncols = gda_data_model_get_n_columns (comp->priv->old_model);
+ if (!comp->priv->key_columns) {
+ comp->priv->nb_key_columns = ncols;
+ comp->priv->key_columns = g_new (gint, ncols);
+ for (i = 0; i < ncols; i++)
+ comp->priv->key_columns [i] = i;
+ }
+
+ for (i = 0; i < comp->priv->nb_key_columns; i++)
+ values = g_slist_append (values,
+ (gpointer) gda_data_model_get_value_at (comp->priv->new_model,
+ comp->priv->key_columns[i], row));
+
+ erow = gda_data_model_get_row_from_values (comp->priv->old_model, values, comp->priv->key_columns);
+ g_slist_free (values);
+
+ if (erow >= 0) {
+ gboolean changed = FALSE;
+ for (i = 0; i < ncols; i++) {
+ const GValue *v1, *v2;
+ v1 = gda_data_model_get_value_at (comp->priv->old_model, i, erow);
+ v2 = gda_data_model_get_value_at (comp->priv->new_model, i, row);
+ if (gda_value_compare_ext (v1, v2)) {
+ changed = TRUE;
+ break;
+ }
+ }
+ *out_has_changed = changed;
+ }
+
+ return erow;
+}
+
+/**
+ * gda_data_comparator_compute_diff
+ * @comp: a #GdaDataComparator object
+ * @error: a place to store errors, or %NULL
+ *
+ * Actually computes the differences bewteen the data models for which @comp is defined.
+ *
+ * For each difference computed, stored in a #GdaDiff structure, the "diff-computed" signal is emitted.
+ * If one connects to this signal and returns FALSE in the signal handler, then computing differences will be
+ * stopped and an error will be returned.
+ *
+ * Returns: TRUE if all the differences have been sucessfully computed
+ */
+gboolean
+gda_data_comparator_compute_diff (GdaDataComparator *comp, GError **error)
+{
+ gint oncols, nncols, i;
+ gint onrows, nnrows;
+ gboolean *rows_to_del = NULL;
+
+ g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), FALSE);
+ g_return_val_if_fail (comp->priv, FALSE);
+
+ clean_diff (comp);
+
+ /* check setup */
+ if (!comp->priv->old_model) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR,
+ _("Missing original data model"));
+ return FALSE;
+ }
+ if (!comp->priv->new_model) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR,
+ _("Missing new data model"));
+ return FALSE;
+ }
+ if (! (gda_data_model_get_access_flags (comp->priv->old_model) & GDA_DATA_MODEL_ACCESS_RANDOM) ||
+ ! (gda_data_model_get_access_flags (comp->priv->new_model) & GDA_DATA_MODEL_ACCESS_RANDOM)) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR,
+ _("Data models must support random access model"));
+ return FALSE;
+ }
+
+ /* compare columns */
+ oncols = gda_data_model_get_n_columns (comp->priv->old_model);
+ nncols = gda_data_model_get_n_columns (comp->priv->new_model);
+ if (oncols != nncols) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR, GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR,
+ _("Data models to compare don't have the same number of columns"));
+ return FALSE;
+ }
+
+ for (i = 0; i < oncols; i++) {
+ GdaColumn *ocol, *ncol;
+ ocol = gda_data_model_describe_column (comp->priv->old_model, i);
+ ncol = gda_data_model_describe_column (comp->priv->new_model, i);
+ if (gda_column_get_g_type (ocol) != gda_column_get_g_type (ncol)) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR,
+ GDA_DATA_COMPARATOR_COLUMN_TYPES_MISMATCH_ERROR,
+ _("Type mismatch for column %d: '%s' and '%s'"), i,
+ g_type_name (gda_column_get_g_type (ocol)),
+ g_type_name (gda_column_get_g_type (ncol)));
+ return FALSE;
+ }
+ }
+
+ /* actual differences computations : rows to insert / update */
+ onrows = gda_data_model_get_n_rows (comp->priv->old_model);
+ nnrows = gda_data_model_get_n_rows (comp->priv->new_model);
+ rows_to_del = g_new (gboolean, onrows);
+ memset (rows_to_del, TRUE, sizeof (gboolean) * onrows);
+ for (i = 0; i < nnrows; i++) {
+ gint erow = -1;
+ gboolean has_changed = FALSE;
+ GdaDiff *diff = NULL;
+ gboolean stop;
+
+ erow = find_row_in_model (comp, i, &has_changed, error);
+
+#ifdef DEBUG_STORE_MODIFY
+ g_print ("FIND row %d(/%d) returned row %d (%s)\n", i, new_n_rows - 1, erow,
+ has_changed ? "CHANGED" : "unchanged");
+#endif
+ if (erow < 0) {
+ gint j;
+ diff = g_new0 (GdaDiff, 1);
+ diff->type = GDA_DIFF_ADD_ROW;
+ diff->old_row = -1;
+ diff->new_row = i;
+ diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free,
+ (GDestroyNotify) gda_value_free);
+ for (j = 0; j < oncols; j++)
+ g_hash_table_insert (diff->values, g_strdup_printf ("+%d", j),
+ gda_value_copy (gda_data_model_get_value_at (comp->priv->new_model,
+ j, i)));
+ }
+ else if (has_changed) {
+ gint j;
+ diff = g_new0 (GdaDiff, 1);
+ diff->type = GDA_DIFF_MODIFY_ROW;
+ diff->old_row = erow;
+ diff->new_row = i;
+ diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free,
+ (GDestroyNotify) gda_value_free);
+ for (j = 0; j < oncols; j++) {
+ g_hash_table_insert (diff->values, g_strdup_printf ("+%d", j),
+ gda_value_copy (gda_data_model_get_value_at (comp->priv->new_model,
+ j, i)));
+ g_hash_table_insert (diff->values, g_strdup_printf ("-%d", j),
+ gda_value_copy (gda_data_model_get_value_at (comp->priv->old_model,
+ j, i)));
+ }
+ }
+ rows_to_del [i] = FALSE;
+ if (diff) {
+ g_array_append_val (comp->priv->diffs, diff);
+ g_signal_emit (comp, gda_data_comparator_signals [DIFF_COMPUTED], 0, diff, &stop);
+ if (stop) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR,
+ GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR,
+ _("Differences computation cancelled on signal handling"));
+ g_free (rows_to_del);
+ return FALSE;
+ }
+ }
+ }
+
+ /* actual differences computations : rows to delete */
+ for (i = 0; i < onrows; i++) {
+ GdaDiff *diff = NULL;
+ gboolean stop;
+ if (rows_to_del [i]) {
+ gint j;
+ diff = g_new0 (GdaDiff, 1);
+ diff->type = GDA_DIFF_ADD_ROW;
+ diff->old_row = i;
+ diff->new_row = -1;
+ diff->values = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free,
+ (GDestroyNotify) gda_value_free);
+ for (j = 0; j < oncols; j++)
+ g_hash_table_insert (diff->values, g_strdup_printf ("-%d", j),
+ gda_value_copy (gda_data_model_get_value_at (comp->priv->old_model,
+ j, i)));
+ g_array_append_val (comp->priv->diffs, diff);
+ g_signal_emit (comp, gda_data_comparator_signals [DIFF_COMPUTED], 0, diff, &stop);
+ if (stop) {
+ g_set_error (error, GDA_DATA_COMPARATOR_ERROR,
+ GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR,
+ _("Differences computation cancelled on signal handling"));
+ g_free (rows_to_del);
+ return FALSE;
+ }
+ }
+ }
+
+ g_free (rows_to_del);
+ return TRUE;
+}
+
+/**
+ * gda_data_comparator_get_n_diffs
+ * @comp: a #GdaDataComparator object
+ *
+ * Get the number of differences as computed by the last time gda_data_comparator_compute_diff() was called.
+ *
+ * Returns: the number of computed differences
+ */
+gint
+gda_data_comparator_get_n_diffs (GdaDataComparator *comp)
+{
+ g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), 0);
+ g_return_val_if_fail (comp->priv, 0);
+
+ return comp->priv->diffs->len;
+}
+
+/**
+ * gda_data_comparator_get_diff
+ * @comp: a #GdaDataComparator object
+ * @pos: the requested difference number (starting at 0)
+ *
+ * Get a pointer to the #GdaDiff structure representing the difference which number is @pos
+ *
+ * Returns: a pointer to a #GdaDiff, or %NULL if @pos is invalid
+ */
+const GdaDiff *
+gda_data_comparator_get_diff (GdaDataComparator *comp, gint pos)
+{
+ g_return_val_if_fail (GDA_IS_DATA_COMPARATOR (comp), NULL);
+ g_return_val_if_fail (comp->priv, NULL);
+
+ return g_array_index (comp->priv->diffs, GdaDiff*, pos);
+}
Added: trunk/libgda/gda-data-comparator.h
==============================================================================
--- (empty file)
+++ trunk/libgda/gda-data-comparator.h Wed Apr 2 20:22:59 2008
@@ -0,0 +1,88 @@
+/* gda-data-comparator.h
+ *
+ * Copyright (C) 2008 Vivien Malerba
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GDA_DATA_COMPARATOR_H_
+#define __GDA_DATA_COMPARATOR_H_
+
+#include "gda-decl.h"
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_DATA_COMPARATOR (gda_data_comparator_get_type())
+#define GDA_DATA_COMPARATOR(obj) G_TYPE_CHECK_INSTANCE_CAST (obj, gda_data_comparator_get_type(), GdaDataComparator)
+#define GDA_DATA_COMPARATOR_CLASS(klass) G_TYPE_CHECK_CLASS_CAST (klass, gda_data_comparator_get_type (), GdaDataComparatorClass)
+#define GDA_IS_DATA_COMPARATOR(obj) G_TYPE_CHECK_INSTANCE_TYPE (obj, gda_data_comparator_get_type ())
+
+typedef struct _GdaDataComparator GdaDataComparator;
+typedef struct _GdaDataComparatorClass GdaDataComparatorClass;
+typedef struct _GdaDataComparatorPrivate GdaDataComparatorPrivate;
+
+/* error reporting */
+extern GQuark gda_data_comparator_error_quark (void);
+#define GDA_DATA_COMPARATOR_ERROR gda_data_comparator_error_quark ()
+
+typedef enum {
+ GDA_DATA_COMPARATOR_MISSING_DATA_MODEL_ERROR,
+ GDA_DATA_COMPARATOR_COLUMN_TYPES_MISMATCH_ERROR,
+ GDA_DATA_COMPARATOR_MODEL_ACCESS_ERROR,
+ GDA_DATA_COMPARATOR_USER_CANCELLED_ERROR
+} GdaDataComparatorError;
+
+/* differences reporting */
+typedef enum {
+ GDA_DIFF_ADD_ROW,
+ GDA_DIFF_REMOVE_ROW,
+ GDA_DIFF_MODIFY_ROW,
+} GdaDiffType;
+
+typedef struct {
+ GdaDiffType type;
+ gint old_row;
+ gint new_row;
+ GHashTable *values; /* key = ('+' or '-') and a column position starting at 0 (string)
+ * value = a GValue pointer */
+} GdaDiff;
+
+/* struct for the object's data */
+struct _GdaDataComparator
+{
+ GObject object;
+ GdaDataComparatorPrivate *priv;
+};
+
+/* struct for the object's class */
+struct _GdaDataComparatorClass
+{
+ GObjectClass parent_class;
+ gboolean (* diff_computed) (GdaDataComparator *comp, GdaDiff *diff);
+};
+
+GType gda_data_comparator_get_type (void) G_GNUC_CONST;
+GObject *gda_data_comparator_new (GdaDataModel *old_model, GdaDataModel *new_model);
+void gda_data_comparator_set_key_columns (GdaDataComparator *comp, gint *col_numbers, gint nb_cols);
+gboolean gda_data_comparator_compute_diff (GdaDataComparator *comp, GError **error);
+gint gda_data_comparator_get_n_diffs (GdaDataComparator *comp);
+const GdaDiff *gda_data_comparator_get_diff (GdaDataComparator *comp, gint pos);
+
+G_END_DECLS
+
+#endif
Modified: trunk/libgda/gda-data-model.c
==============================================================================
--- trunk/libgda/gda-data-model.c (original)
+++ trunk/libgda/gda-data-model.c Wed Apr 2 20:22:59 2008
@@ -1282,12 +1282,10 @@
}
}
- if (! gda_file_save (file, body, strlen (body))) {
- g_set_error (error, 0, 0, _("Could not save file %s"), file);
+ if (! g_file_set_contents (file, body, -1, error)) {
g_free (body);
return FALSE;
}
-
g_free (body);
return TRUE;
}
Modified: trunk/libgda/gda-easy.c
==============================================================================
--- trunk/libgda/gda-easy.c (original)
+++ trunk/libgda/gda-easy.c Wed Apr 2 20:22:59 2008
@@ -25,6 +25,15 @@
static GdaSqlParser *internal_parser = NULL;
+/* module error */
+GQuark gda_easy_error_quark (void)
+{
+ static GQuark quark;
+ if (!quark)
+ quark = g_quark_from_static_string ("gda_easy_error");
+ return quark;
+}
+
/**
* gda_prepare_create_database
* @provider: the database provider to use
@@ -228,128 +237,142 @@
}
/**
- * gda_create_table
+ * gda_prepare_create_table
* @cnc: an opened connection
* @table_name:
* @num_columns
* @error: a place to store errors, or %NULL
- * @...: pairs of column name and #GType, finish with NULL
+ * @...: group of three arguments for column's name, column's #GType
+ * and a #GdaEasyCreateTableFlag flag, finished with NULL
*
- * Create a Table over an opened connection using a pair list of colum name and
- * GType as arguments, you need to finish the list using NULL.
- *
- * This is just a convenient function to create tables quickly,
- * using defaults for the provider and converting the #GType passed to the corresponding
- * type in the provider; to use a custom type or more advanced characteristics in a
- * specific provider use the #GdaServerOperation framework.
- *
- * Returns: TRUE if the table was created; FALSE and set @error otherwise
+ * Create a #GdaServerOperation object using an opened connection, taking three
+ * arguments, a colum's name the column's GType and #GdaEasyCreateTableFlag
+ * flag, you need to finish the list using NULL.
+ *
+ * You'll be able to modify the #GdaServerOperation object to add custom options
+ * to the operation. When finish call #gda_perform_create_table
+ * or #gda_server_operation_perform_operation
+ * in order to execute the operation.
+ *
+ * Returns: a #GdaServerOperation if no errors; NULL and set @error otherwise
*/
-gboolean
-gda_create_table (GdaConnection *cnc, const gchar *table_name, GError **error, ...)
+GdaServerOperation*
+gda_prepare_create_table (GdaConnection *cnc, const gchar *table_name, GError **error, ...)
{
GdaServerOperation *op;
GdaServerProvider *server;
-
- g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
- g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE);
+
+ g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE);
server = gda_connection_get_provider_obj(cnc);
- op = gda_server_provider_create_operation (server, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error);
- if (GDA_IS_SERVER_OPERATION (op)) {
+ if (!table_name) {
+ g_set_error (error, GDA_EASY_ERROR, GDA_EASY_OBJECT_NAME_ERROR,
+ _("Unspecified table name"));
+ return NULL;
+ }
+
+ if (gda_server_provider_supports_operation (server, cnc, GDA_SERVER_OPERATION_CREATE_TABLE, NULL)) {
va_list args;
gchar *arg;
GType type;
gchar *dbms_type;
- xmlDocPtr parameters;
- xmlNodePtr root;
- xmlNodePtr table, op_data, array_data, array_row, array_value;
-
- if (table_name == NULL) {
- g_set_error (error, GDA_GENERAL_ERROR, GDA_GENERAL_OBJECT_NAME_ERROR,
- _("Couldn't create table with a NULL string"));
- return FALSE;
- }
-
+ GdaEasyCreateTableFlag flag;
+ gint i;
- /* Initation of the xmlDoc */
- parameters = xmlNewDoc ((xmlChar*)"1.0");
-
- root = xmlNewDocNode (parameters, NULL, (xmlChar*)"serv_op_data", NULL);
- xmlDocSetRootElement (parameters, root);
- table = xmlNewChild (root, NULL, (xmlChar*)"op_data", (xmlChar*)table_name);
- xmlSetProp(table, (xmlChar*)"path", (xmlChar*)"/TABLE_DEF_P/TABLE_NAME");
-
- op_data = xmlNewChild (root, NULL, (xmlChar*)"op_data", NULL);
- xmlSetProp(op_data, (xmlChar*)"path", (xmlChar*)"/FIELDS_A");
- array_data = xmlNewChild (op_data, NULL, (xmlChar*)"gda_array_data", NULL);
-
+ op = gda_server_provider_create_operation (server, cnc,
+ GDA_SERVER_OPERATION_CREATE_TABLE, NULL, error);
+ gda_server_operation_set_value_at (op, table_name, error, "/TABLE_DEF_P/TABLE_NAME");
+
va_start (args, error);
type = 0;
arg = NULL;
+ i = 0;
while ((arg = va_arg (args, gchar*))) {
+ /* First argument for Column's name */
+ gda_server_operation_set_value_at (op, arg, error, "/FIELDS_A/@COLUMN_NAME/%d", i);
+
+ /* Second to Define column's type */
type = va_arg (args, GType);
if (type == 0) {
- g_set_error(error, GDA_GENERAL_ERROR, GDA_GENERAL_INCORRECT_VALUE_ERROR,
- _("Error the number of arguments are incorrect; couldn't create the table"));
+ g_set_error (error, GDA_EASY_ERROR, GDA_EASY_INCORRECT_VALUE_ERROR,
+ _("Invalid type"));
g_object_unref (op);
- xmlFreeDoc(parameters);
- return FALSE;
+ return NULL;
}
-
dbms_type = (gchar *) gda_server_provider_get_default_dbms_type (server,
cnc, type);
- array_row = xmlNewChild (array_data, NULL, (xmlChar*)"gda_array_row", NULL);
- array_value = xmlNewChild (array_row, NULL, (xmlChar*)"gda_array_value", (xmlChar*)arg);
- xmlSetProp(array_value, (xmlChar*)"colid", (xmlChar*)"COLUMN_NAME");
+ gda_server_operation_set_value_at (op, dbms_type, error, "/FIELDS_A/@COLUMN_TYPE/%d", i);
- array_value = xmlNewChild(array_row, NULL, (xmlChar*)"gda_array_value", (xmlChar*)dbms_type);
- xmlSetProp(array_value, (xmlChar*)"colid", (xmlChar*)"COLUMN_TYPE");
-
+ /* Third for column's flags */
+ flag = va_arg (args, GdaEasyCreateTableFlag);
+ if (flag & GDA_EASY_CREATE_TABLE_PKEY_FLAG)
+ gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_PKEY/%d", i);
+ if (flag & GDA_EASY_CREATE_TABLE_NOT_NULL_FLAG)
+ gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_NNUL/%d", i);
+ if (flag & GDA_EASY_CREATE_TABLE_AUTOINC_FLAG)
+ gda_server_operation_set_value_at (op, "TRUE", error, "/FIELDS_A/@COLUMN_AUTOINC/%d", i);
+ i++;
}
+
+ va_end (args);
- va_end(args);
-
- if (!gda_server_operation_load_data_from_xml (op, root, error)) {
- g_set_error (error, GDA_GENERAL_ERROR, GDA_GENERAL_OPERATION_ERROR,
- _("The XML operation doesn't exist or could't be loaded"));
- g_object_unref (op);
- xmlFreeDoc(parameters);
- return FALSE;
- }
- else {
- if (!gda_server_provider_perform_operation (server, cnc, op, error)) {
- g_object_unref (op);
- xmlFreeDoc(parameters);
- return FALSE;
- }
- }
+ g_object_set_data (G_OBJECT (op), "_gda_connection", cnc);
+ g_object_set_data (G_OBJECT (op), "_gda_provider_obj", server);
- g_object_unref (op);
- xmlFreeDoc(parameters);
+ return op;
}
+ else {
+ g_set_error (error, GDA_EASY_ERROR, GDA_EASY_OBJECT_NAME_ERROR,
+ _("CREATE TABLE operation is not supported by the database server"));
+ return NULL;
+ }
+}
+
+/**
+ * gda_perform_create_table
+ * @op: a valid #GdaServerOperation
+ * @error: a place to store errors, or %NULL
+ *
+ * Performs a prepared #GdaServerOperation to create a table. This could perform
+ * an operation created by #gda_prepare_create_table or any other using the
+ * the #GdaServerOperation API.
+ *
+ * Returns: TRUE if the table was created; FALSE and set @error otherwise
+ */
+gboolean
+gda_perform_create_table (GdaServerOperation *op, GError **error)
+{
+ GdaConnection *cnc;
+ GdaServerProvider *server;
- return TRUE;
+ g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
+ g_return_val_if_fail (gda_server_operation_get_op_type (op) ==
+ GDA_SERVER_OPERATION_CREATE_TABLE, FALSE);
+
+ server = GDA_SERVER_PROVIDER (g_object_get_data (G_OBJECT (op), "_gda_provider_obj"));
+ cnc = GDA_CONNECTION (g_object_get_data (G_OBJECT (op), "_gda_connection"));
+
+ return gda_server_provider_perform_operation (server, cnc, op, error);
}
/**
- * gda_drop_table
+ * gda_prepare_drop_table
* @cnc: an opened connection
* @table_name:
* @error: a place to store errors, or %NULL
*
- * This is just a convenient function to drop a table in an opened connection.
+ * This is just a convenient function to create a #GdaServerOperation to drop a
+ * table in an opened connection.
*
- * Returns: TRUE if the table was dropped
+ * Returns: a new #GdaServerOperation or NULL if couldn't create the opereration.
*/
-gboolean
-gda_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error)
+GdaServerOperation*
+gda_prepare_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error)
{
GdaServerOperation *op;
GdaServerProvider *server;
- gboolean retval = TRUE;
server = gda_connection_get_provider_obj (cnc);
@@ -357,37 +380,46 @@
GDA_SERVER_OPERATION_DROP_TABLE, NULL, error);
if (GDA_IS_SERVER_OPERATION (op)) {
- xmlDocPtr parameters;
- xmlNodePtr root;
- xmlNodePtr table;
-
g_return_val_if_fail (table_name != NULL
|| GDA_IS_CONNECTION (cnc)
- || !gda_connection_is_opened (cnc), FALSE);
-
- parameters = xmlNewDoc ((xmlChar*)"1.0");
- root = xmlNewDocNode (parameters, NULL, (xmlChar*)"serv_op_data", NULL);
- xmlDocSetRootElement (parameters, root);
- table = xmlNewChild (root, NULL, (xmlChar*)"op_data", (xmlChar*)table_name);
- xmlSetProp(table, (xmlChar*)"path", (xmlChar*)"/TABLE_DESC_P/TABLE_NAME");
-
- if (!gda_server_operation_load_data_from_xml (op, root, error)) {
- /* error */
- retval = FALSE;
- }
- else if (!gda_server_provider_perform_operation (server, cnc, op, error)) {
- /* error */
- retval = FALSE;
+ || !gda_connection_is_opened (cnc), NULL);
+
+ if (gda_server_operation_set_value_at (op, table_name,
+ error, "/TABLE_DESC_P/TABLE_NAME")) {
+ g_object_set_data (G_OBJECT (op), "_gda_connection", cnc);
+ g_object_set_data (G_OBJECT (op), "_gda_provider_obj", server);
+ return op;
}
- g_object_unref (op);
- xmlFreeDoc(parameters);
+ else
+ return NULL;
}
- else {
- g_message("The Server doesn't support the DROP TABLE operation!\n\n");
- retval = FALSE;
- }
-
- return retval;
+ else
+ return NULL;
+}
+
+/**
+ * gda_perform_drop_table
+ * @op: a #GdaServerOperation object
+ * @error: a place to store errors, or %NULL
+ *
+ * This is just a convenient function to perform a drop a table operation.
+ *
+ * Returns: TRUE if the table was dropped
+ */
+gboolean
+gda_perform_drop_table (GdaServerOperation *op, GError **error)
+{
+ GdaConnection *cnc;
+ GdaServerProvider *server;
+
+ g_return_val_if_fail (GDA_IS_SERVER_OPERATION (op), FALSE);
+ g_return_val_if_fail (gda_server_operation_get_op_type (op) ==
+ GDA_SERVER_OPERATION_DROP_TABLE, FALSE);
+
+ server = GDA_SERVER_PROVIDER (g_object_get_data (G_OBJECT (op), "_gda_provider_obj"));
+ cnc = GDA_CONNECTION (g_object_get_data (G_OBJECT (op), "_gda_connection"));
+
+ return gda_server_provider_perform_operation (server, cnc, op, error);
}
static guint
@@ -477,7 +509,7 @@
g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
g_return_val_if_fail (gda_connection_is_opened (cnc), FALSE);
g_return_val_if_fail (table_name && *table_name, FALSE);
-
+
TO_IMPLEMENT;
return FALSE;
}
Modified: trunk/libgda/gda-easy.h
==============================================================================
--- trunk/libgda/gda-easy.h (original)
+++ trunk/libgda/gda-easy.h Wed Apr 2 20:22:59 2008
@@ -3,6 +3,7 @@
*
* AUTHORS:
* Vivien Malerba <malerba gnome-db org>
+ * Daniel Espinosa <esodan 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
@@ -34,14 +35,24 @@
G_BEGIN_DECLS
-extern GQuark gda_general_error_quark (void);
-#define GDA_GENERAL_ERROR gda_general_error_quark ()
+extern GQuark gda_easy_error_quark (void);
+#define GDA_EASY_ERROR gda_easy_error_quark ()
typedef enum {
- GDA_GENERAL_OBJECT_NAME_ERROR,
- GDA_GENERAL_INCORRECT_VALUE_ERROR,
- GDA_GENERAL_OPERATION_ERROR
-} GdaGeneralError;
+ GDA_EASY_OBJECT_NAME_ERROR,
+ GDA_EASY_INCORRECT_VALUE_ERROR,
+ GDA_EASY_OPERATION_ERROR
+} GdaEasyError;
+
+typedef enum
+{
+ GDA_EASY_CREATE_TABLE_PKEY_FLAG = 1 << 0,
+ GDA_EASY_CREATE_TABLE_NOT_NULL_FLAG = 1 << 1,
+ GDA_EASY_CREATE_TABLE_UNIQUE_FLAG = 1 << 2,
+ GDA_EASY_CREATE_TABLE_AUTOINC_FLAG = 1 << 3,
+ /* Flags combinations */
+ GDA_EASY_CREATE_TABLE_PKEY_AUTOINC_FLAG = GDA_EASY_CREATE_TABLE_PKEY_FLAG | GDA_EASY_CREATE_TABLE_AUTOINC_FLAG
+} GdaEasyCreateTableFlag;
/*
* Convenient Functions
@@ -66,8 +77,10 @@
/*
* Tables creation and destruction
*/
-gboolean gda_create_table (GdaConnection *cnc, const gchar *table_name, GError **error, ...);
-gboolean gda_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error);
+GdaServerOperation *gda_prepare_create_table (GdaConnection *cnc, const gchar *table_name, GError **error, ...);
+gboolean gda_perform_create_table (GdaServerOperation *op, GError **error);
+GdaServerOperation *gda_prepare_drop_table (GdaConnection *cnc, const gchar *table_name, GError **error);
+gboolean gda_perform_drop_table (GdaServerOperation *op, GError **error);
/*
* Data in tables manipulation
Modified: trunk/libgda/gda-init.c
==============================================================================
--- trunk/libgda/gda-init.c (original)
+++ trunk/libgda/gda-init.c Wed Apr 2 20:22:59 2008
@@ -236,16 +236,3 @@
GDA_UNLOCK ();
}
-/*
- * Convenient Functions
- */
-
-
-/* module error */
-GQuark gda_general_error_quark (void)
-{
- static GQuark quark;
- if (!quark)
- quark = g_quark_from_static_string ("gda_general_error");
- return quark;
-}
Modified: trunk/libgda/gda-marshal.list
==============================================================================
--- trunk/libgda/gda-marshal.list (original)
+++ trunk/libgda/gda-marshal.list Wed Apr 2 20:22:59 2008
@@ -41,3 +41,4 @@
BOOLEAN:INT
BOOLEAN:INT,INT
POINTER:POINTER
+BOOLEAN:POINTER
Modified: trunk/libgda/gda-meta-store.c
==============================================================================
--- trunk/libgda/gda-meta-store.c (original)
+++ trunk/libgda/gda-meta-store.c Wed Apr 2 20:22:59 2008
@@ -2419,7 +2419,8 @@
*/
static gint
find_row_in_model (GdaDataModel *find_in, GdaDataModel *data, gint row, gint *pk_cols, gint pk_cols_nb,
- gboolean *out_has_changed, GError **error) {
+ gboolean *out_has_changed, GError **error)
+{
gint i, erow;
GSList *values = NULL;
Modified: trunk/libgda/gda-meta-struct.c
==============================================================================
--- trunk/libgda/gda-meta-struct.c (original)
+++ trunk/libgda/gda-meta-struct.c Wed Apr 2 20:22:59 2008
@@ -123,8 +123,11 @@
/**
* gda_meta_struct_new
- * @features: the kind of information the new #GdaMetaStruct object will compute (the more features, the more time
- * it takes to run)
+ * @features: the kind of extra information the new #GdaMetaStruct object will compute
+ *
+ * Creates a new #GdaMetaStruct object. The @features specifies the extra features which will also be computed:
+ * the more features, the more time it takes to run. Features such as table's columns, each column's attributes, etc
+ * are not optional and will always be computed.
*
* Returns: the newly created #GdaMetaStruct object
*/
@@ -494,12 +497,13 @@
goto onerror;
nrows = gda_data_model_get_n_rows (model);
- if (0 && nrows >= 1) {
+ if (nrows >= 1) {
GdaDataModel *pkmodel;
- sql = "SELECT column_name FROM _key_column_usage WHERE constraint_catalog = ##cc::string AND constraint_schema = ##cs::string AND constraint_name = ##cname::string ORDER BY ordinal_position";
+ sql = "SELECT column_name FROM _key_column_usage WHERE table_catalog = ##cc::string AND table_schema = ##cs::string AND table_name = ##tname::string AND constraint_name = ##cname::string ORDER BY ordinal_position";
pkmodel = gda_meta_store_extract (store, sql, error,
- "cc", gda_data_model_get_value_at (model, 0, 0),
- "cs", gda_data_model_get_value_at (model, 1, 0),
+ "cc", catalog,
+ "cs", schema,
+ "tname", name,
"cname", gda_data_model_get_value_at (model, 0, 0), NULL);
if (!pkmodel) {
g_object_unref (model);
@@ -511,11 +515,11 @@
for (i = 0; i < nrows; i++) {
GdaMetaTableColumn *tcol;
tcol = gda_meta_struct_get_table_column (mstruct, mt,
- gda_data_model_get_value_at (model, 0, i));
+ gda_data_model_get_value_at (pkmodel, 0, i));
if (!tcol) {
mt->pk_cols_array [i] = -1;
g_warning (_("Internal GdaMetaStore error: column %s not found"),
- g_value_get_string (gda_data_model_get_value_at (model, 0, i)));
+ g_value_get_string (gda_data_model_get_value_at (pkmodel, 0, i)));
}
else {
mt->pk_cols_array [i] = g_slist_index (mt->columns, tcol);
Modified: trunk/libgda/gda-server-provider.c
==============================================================================
--- trunk/libgda/gda-server-provider.c (original)
+++ trunk/libgda/gda-server-provider.c Wed Apr 2 20:22:59 2008
@@ -404,8 +404,8 @@
* Creates a new #GdaServerOperation object which can be modified in order to perform the @type type of
* action. The @options can contain:
* <itemizedlist>
- * <listitem>parameters which ID is a path in the resulting GdaServerOperation object, to initialize some value</listitem>
- * <listitem>parameters which may change the contents of the GdaServerOperation, see <link linkend="gda-server-op-information-std">this section</link> for more information</listitem>
+ * <listitem>named values which ID is a path in the resulting GdaServerOperation object, to initialize some value</listitem>
+ * <listitem>named values which may change the contents of the GdaServerOperation, see <link linkend="gda-server-op-information-std">this section</link> for more information</listitem>
* </itemizedlist>
*
* Returns: a new #GdaServerOperation object, or %NULL in the provider does not support the @type type
@@ -524,7 +524,8 @@
* @op: a #GdaServerOperation object
* @error: a place to store an error, or %NULL
*
- * Performs the operation described by @op.
+ * Performs the operation described by @op. Note that @op is not destroyed by this method
+ * and can be reused.
*
* Returns: TRUE if no error occurred
*/
Modified: trunk/libgda/gda-server-provider.h
==============================================================================
--- trunk/libgda/gda-server-provider.h (original)
+++ trunk/libgda/gda-server-provider.h Wed Apr 2 20:22:59 2008
@@ -28,7 +28,6 @@
#include <libgda/gda-server-operation.h>
#include <libgda/gda-connection.h>
#include <libgda/gda-data-model.h>
-#include <libgda/gda-data-model-index.h>
#include <libgda/gda-quark-list.h>
#include <libgda/gda-statement.h>
#include <libgda/gda-meta-store.h>
Modified: trunk/libgda/gda-statement.c
==============================================================================
--- trunk/libgda/gda-statement.c (original)
+++ trunk/libgda/gda-statement.c Wed Apr 2 20:22:59 2008
@@ -364,7 +364,7 @@
}
/**
- * gda_statement_check_connection
+ * gda_statement_check_validity
* @stmt: a #GdaStatement object
* @cnc: a #GdaConnection object, or %NULL
* @error: a place to store errors, or %NULL
@@ -374,17 +374,19 @@
*
* If @cnc is %NULL, then cleans anything related to @cnc in @stmt.
*
+ * See gda_sql_statement_check_validity() for more information.
+ *
* Returns: TRUE if every object actually exists in @cnc's database
*/
gboolean
-gda_statement_check_connection (GdaStatement *stmt, GdaConnection *cnc, GError **error)
+gda_statement_check_validity (GdaStatement *stmt, GdaConnection *cnc, GError **error)
{
gboolean retval;
g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
g_return_val_if_fail (stmt->priv, FALSE);
g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
- retval = gda_sql_statement_check_connection (stmt->priv->internal_struct, cnc, error);
+ retval = gda_sql_statement_check_validity (stmt->priv->internal_struct, cnc, error);
g_signal_emit (stmt, gda_statement_signals [CHECKED], 0, cnc, retval);
return retval;
Modified: trunk/libgda/gda-statement.h
==============================================================================
--- trunk/libgda/gda-statement.h (original)
+++ trunk/libgda/gda-statement.h Wed Apr 2 20:22:59 2008
@@ -96,13 +96,7 @@
GdaSqlStatementType gda_statement_get_statement_type (GdaStatement *stmt);
gboolean gda_statement_is_useless (GdaStatement *stmt);
gboolean gda_statement_check_structure (GdaStatement *stmt, GError **error);
-gboolean gda_statement_check_connection (GdaStatement *stmt, GdaConnection *cnc, GError **error);
-
-/*
-GdaObject *gda_statement_execute (GdaStatement *stmt, GdaConnection *cnc,
- GdaParameterList *params,
- GdaStatementModelUsage usage, GError **error);
-*/
+gboolean gda_statement_check_validity (GdaStatement *stmt, GdaConnection *cnc, GError **error);
G_END_DECLS
Modified: trunk/libgda/gda-util.c
==============================================================================
--- trunk/libgda/gda-util.c (original)
+++ trunk/libgda/gda-util.c Wed Apr 2 20:22:59 2008
@@ -38,6 +38,7 @@
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
+#include <libgda/sql-parser/gda-sql-statement.h>
#include <libgda/binreloc/gda-binreloc.h>
@@ -201,373 +202,6 @@
return retval;
}
-/* function called by g_hash_table_foreach to add items to a GList */
-static void
-add_string_key_to_list (gpointer key, gpointer value, gpointer user_data)
-{
- GList **list = (GList **) user_data;
-
- *list = g_list_append (*list, g_strdup (key));
-}
-
-/**
- * gda_string_hash_to_list
- * @hash_table: a hash table.
- *
- * Creates a new list of strings, which contains all keys of a given hash
- * table. After using it, you should free this list by calling g_list_free.
- *
- * Returns: a new GList.
- */
-GList *
-gda_string_hash_to_list (GHashTable *hash_table)
-{
- GList *list = NULL;
-
- g_return_val_if_fail (hash_table != NULL, NULL);
-
- g_hash_table_foreach (hash_table, (GHFunc) add_string_key_to_list, &list);
- return list;
-}
-
-/**
- * gda_file_load
- * @filename: path for the file to be loaded.
- *
- * Loads a file, specified by the given @uri, and returns the file
- * contents as a string.
- *
- * It is the caller's responsibility to free the returned value.
- *
- * Returns: the file contents as a newly-allocated string, or %NULL
- * if there is an error.
- */
-gchar *
-gda_file_load (const gchar *filename)
-{
- gchar *retval = NULL;
- gsize length = 0;
- GError *error = NULL;
-
- g_return_val_if_fail (filename != NULL, NULL);
-
- if (g_file_get_contents (filename, &retval, &length, &error))
- return retval;
-
- gda_log_error (_("Error while reading %s: %s"), filename, error->message);
- g_error_free (error);
-
- return NULL;
-}
-
-/**
- * gda_file_save
- * @filename: path for the file to be saved.
- * @buffer: contents of the file.
- * @len: size of @buffer.
- *
- * Saves a chunk of data into a file.
- *
- * Returns: %TRUE if successful, %FALSE on error.
- */
-gboolean
-gda_file_save (const gchar *filename, const gchar *buffer, gint len)
-{
- gint fd;
- gint res;
-
- g_return_val_if_fail (filename != NULL, FALSE);
-
- fd = open (filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
- if (fd == -1) {
- gda_log_error (_("Could not create file %s"), filename);
- return FALSE;
- }
-
- res = write (fd, (const void *) buffer, len);
- close (fd);
-
- return res == -1 ? FALSE : TRUE;
-}
-
-/**
- * gda_utility_build_encoded_id
- *
- * Creates a BASE64 kind encoded string. It's not really a BASE64 because:
- * - the characters + and / of BASE64 are replaced with - and _
- * - no padding is done using the = character
- *
- * The created string is a valid NCName XML token.
- */
-static inline unsigned char
-to_uchar (gchar ch)
-{
- return ch;
-}
-
-gchar *
-gda_utility_build_encoded_id (const gchar *prefix, const gchar *id)
-{
- const gchar conv[64] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
- gchar *str, *out;
- const gchar *in;
- int ln = 0, pln = 0;
- int offset;
-
- /* size computation */
- if (prefix) {
- pln = strlen (prefix);
- ln = pln;
- }
-
- ln += (strlen (id) * 4 + 2) / 3 + 1;
- str = g_new0 (char, ln);
-
- /* copy prefix */
- out = str;
- if (prefix) {
- strcpy (str, prefix);
- out += pln;
- }
-
- /* create data */
- offset = 4;
- for (in = id; offset == 4; in += 3) {
- offset = 0;
-
- if (in[0]) {
- offset = 2;
-
- out[0] = conv [to_uchar (in[0]) >> 2];
-
- if (in[1]) {
- offset = 3;
- out[1] = conv [((to_uchar (in[0]) << 4) +
- (to_uchar (in[1]) >> 4)) & 0x3f];
-
- if (in[2]) {
- offset = 4;
-
- out[2] = conv [((to_uchar (in[1]) << 2) +
- (to_uchar (in[2]) >> 6)) & 0x3f];
- out[3] = conv [to_uchar (in[2]) & 0x3f];
- }
- else
- out[2] = conv [(to_uchar (in[1]) << 2) & 0x3f];
- }
- else
- out[1] = conv [(to_uchar (in[0]) << 4) & 0x3f];
-
-
- out += offset;
- }
- }
-
- return str;
-}
-
-#define B64(x) \
- ((x) == 'A' ? 0 \
- : (x) == 'B' ? 1 \
- : (x) == 'C' ? 2 \
- : (x) == 'D' ? 3 \
- : (x) == 'E' ? 4 \
- : (x) == 'F' ? 5 \
- : (x) == 'G' ? 6 \
- : (x) == 'H' ? 7 \
- : (x) == 'I' ? 8 \
- : (x) == 'J' ? 9 \
- : (x) == 'K' ? 10 \
- : (x) == 'L' ? 11 \
- : (x) == 'M' ? 12 \
- : (x) == 'N' ? 13 \
- : (x) == 'O' ? 14 \
- : (x) == 'P' ? 15 \
- : (x) == 'Q' ? 16 \
- : (x) == 'R' ? 17 \
- : (x) == 'S' ? 18 \
- : (x) == 'T' ? 19 \
- : (x) == 'U' ? 20 \
- : (x) == 'V' ? 21 \
- : (x) == 'W' ? 22 \
- : (x) == 'X' ? 23 \
- : (x) == 'Y' ? 24 \
- : (x) == 'Z' ? 25 \
- : (x) == 'a' ? 26 \
- : (x) == 'b' ? 27 \
- : (x) == 'c' ? 28 \
- : (x) == 'd' ? 29 \
- : (x) == 'e' ? 30 \
- : (x) == 'f' ? 31 \
- : (x) == 'g' ? 32 \
- : (x) == 'h' ? 33 \
- : (x) == 'i' ? 34 \
- : (x) == 'j' ? 35 \
- : (x) == 'k' ? 36 \
- : (x) == 'l' ? 37 \
- : (x) == 'm' ? 38 \
- : (x) == 'n' ? 39 \
- : (x) == 'o' ? 40 \
- : (x) == 'p' ? 41 \
- : (x) == 'q' ? 42 \
- : (x) == 'r' ? 43 \
- : (x) == 's' ? 44 \
- : (x) == 't' ? 45 \
- : (x) == 'u' ? 46 \
- : (x) == 'v' ? 47 \
- : (x) == 'w' ? 48 \
- : (x) == 'x' ? 49 \
- : (x) == 'y' ? 50 \
- : (x) == 'z' ? 51 \
- : (x) == '0' ? 52 \
- : (x) == '1' ? 53 \
- : (x) == '2' ? 54 \
- : (x) == '3' ? 55 \
- : (x) == '4' ? 56 \
- : (x) == '5' ? 57 \
- : (x) == '6' ? 58 \
- : (x) == '7' ? 59 \
- : (x) == '8' ? 60 \
- : (x) == '9' ? 61 \
- : (x) == '-' ? 62 \
- : (x) == '_' ? 63 \
- : -1)
-
-static const signed char b64[0x100] = {
- B64 (0), B64 (1), B64 (2), B64 (3),
- B64 (4), B64 (5), B64 (6), B64 (7),
- B64 (8), B64 (9), B64 (10), B64 (11),
- B64 (12), B64 (13), B64 (14), B64 (15),
- B64 (16), B64 (17), B64 (18), B64 (19),
- B64 (20), B64 (21), B64 (22), B64 (23),
- B64 (24), B64 (25), B64 (26), B64 (27),
- B64 (28), B64 (29), B64 (30), B64 (31),
- B64 (32), B64 (33), B64 (34), B64 (35),
- B64 (36), B64 (37), B64 (38), B64 (39),
- B64 (40), B64 (41), B64 (42), B64 (43),
- B64 (44), B64 (45), B64 (46), B64 (47),
- B64 (48), B64 (49), B64 (50), B64 (51),
- B64 (52), B64 (53), B64 (54), B64 (55),
- B64 (56), B64 (57), B64 (58), B64 (59),
- B64 (60), B64 (61), B64 (62), B64 (63),
- B64 (64), B64 (65), B64 (66), B64 (67),
- B64 (68), B64 (69), B64 (70), B64 (71),
- B64 (72), B64 (73), B64 (74), B64 (75),
- B64 (76), B64 (77), B64 (78), B64 (79),
- B64 (80), B64 (81), B64 (82), B64 (83),
- B64 (84), B64 (85), B64 (86), B64 (87),
- B64 (88), B64 (89), B64 (90), B64 (91),
- B64 (92), B64 (93), B64 (94), B64 (95),
- B64 (96), B64 (97), B64 (98), B64 (99),
- B64 (100), B64 (101), B64 (102), B64 (103),
- B64 (104), B64 (105), B64 (106), B64 (107),
- B64 (108), B64 (109), B64 (110), B64 (111),
- B64 (112), B64 (113), B64 (114), B64 (115),
- B64 (116), B64 (117), B64 (118), B64 (119),
- B64 (120), B64 (121), B64 (122), B64 (123),
- B64 (124), B64 (125), B64 (126), B64 (127),
- B64 (128), B64 (129), B64 (130), B64 (131),
- B64 (132), B64 (133), B64 (134), B64 (135),
- B64 (136), B64 (137), B64 (138), B64 (139),
- B64 (140), B64 (141), B64 (142), B64 (143),
- B64 (144), B64 (145), B64 (146), B64 (147),
- B64 (148), B64 (149), B64 (150), B64 (151),
- B64 (152), B64 (153), B64 (154), B64 (155),
- B64 (156), B64 (157), B64 (158), B64 (159),
- B64 (160), B64 (161), B64 (162), B64 (163),
- B64 (164), B64 (165), B64 (166), B64 (167),
- B64 (168), B64 (169), B64 (170), B64 (171),
- B64 (172), B64 (173), B64 (174), B64 (175),
- B64 (176), B64 (177), B64 (178), B64 (179),
- B64 (180), B64 (181), B64 (182), B64 (183),
- B64 (184), B64 (185), B64 (186), B64 (187),
- B64 (188), B64 (189), B64 (190), B64 (191),
- B64 (192), B64 (193), B64 (194), B64 (195),
- B64 (196), B64 (197), B64 (198), B64 (199),
- B64 (200), B64 (201), B64 (202), B64 (203),
- B64 (204), B64 (205), B64 (206), B64 (207),
- B64 (208), B64 (209), B64 (210), B64 (211),
- B64 (212), B64 (213), B64 (214), B64 (215),
- B64 (216), B64 (217), B64 (218), B64 (219),
- B64 (220), B64 (221), B64 (222), B64 (223),
- B64 (224), B64 (225), B64 (226), B64 (227),
- B64 (228), B64 (229), B64 (230), B64 (231),
- B64 (232), B64 (233), B64 (234), B64 (235),
- B64 (236), B64 (237), B64 (238), B64 (239),
- B64 (240), B64 (241), B64 (242), B64 (243),
- B64 (244), B64 (245), B64 (246), B64 (247),
- B64 (248), B64 (249), B64 (250), B64 (251),
- B64 (252), B64 (253), B64 (254), B64 (255)
-};
-
-/* This is the previous version:
- * It caused a warning: "comparison is always true due to limited range of data type"
- *
- * #define isbase64(x) ((to_uchar (x) <= 255) && (0 <= b64[to_uchar (x)]))
- *
- * murrayc
- */
-#define isbase64(x) ((0 <= b64[to_uchar (x)]))
-
-
-/**
- * gda_utility_build_decoded_id
- *
- * Reverse of gda_utility_build_encoded_id()
- */
-gchar *
-gda_utility_build_decoded_id (const gchar *prefix, const gchar *id)
-{
- gchar *str;
- gchar *out;
- const gchar *in;
- int ln = 0;
- int offset;
-
- /* go to the first byte of actual data */
- in = id;
- if (prefix) {
- const gchar *tmp;
- tmp = prefix;
- while (*tmp) {
- in++;
- tmp++;
- }
- }
-
- ln = (strlen (in) * 3) / 4 + 3;
- str = g_new0 (char, ln);
- out = str;
-
- /* create data */
- offset = 3;
- for (; offset == 3; in += 4) {
- offset = 0;
-
- if (isbase64 (in[0]) && isbase64 (in[1])) {
- out[0] = ((b64 [to_uchar (in[0])] << 2) |
- (b64 [to_uchar (in[1])] >> 4));
-
- if (isbase64 (in[2])) {
- out[1] = (((b64 [to_uchar (in[1])] << 4) & 0xf0) |
- (b64 [to_uchar (in[2])] >> 2));
-
- if (isbase64 (in[3])) {
- out[2] = (((b64 [to_uchar (in[2])] << 6) & 0xc0) |
- b64 [to_uchar (in[3])]);
- offset = 3;
- }
- }
- }
-
- out += offset;
- }
-
- return str;
-}
-
-
/**
* gda_utility_check_data_model
* @model: a #GdaDataModel object
@@ -972,3 +606,203 @@
return text;
}
+/*
+ * Statement computation from meta store
+ * @select_stmt: must be a SELECT statement (compound statements not handled)
+ */
+gboolean
+gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk,
+ GdaStatement **insert, GdaStatement **update, GdaStatement **delete, GError **error)
+{
+ GdaSqlStatement *sel_struct;
+ GdaSqlStatementSelect *stsel;
+ GdaStatement *ret_insert = NULL;
+ GdaStatement *ret_update = NULL;
+ GdaStatement *ret_delete = NULL;
+ GdaMetaStruct *mstruct;
+ gboolean retval = TRUE;
+ GdaMetaTable *mtable;
+
+ g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+ g_return_val_if_fail (GDA_IS_STATEMENT (select_stmt), FALSE);
+ g_return_val_if_fail (gda_statement_get_statement_type (select_stmt) == GDA_SQL_STATEMENT_SELECT, FALSE);
+
+ /*g_print ("*** %s\n", gda_statement_serialize (select_stmt));*/
+
+ g_object_get (G_OBJECT (select_stmt), "structure", &sel_struct, NULL);
+ stsel = (GdaSqlStatementSelect*) sel_struct->contents;
+ if (!stsel->from) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("SELECT statement has no FROM part"));
+ retval = FALSE;
+ goto cleanup;
+ }
+ if (stsel->from->targets && stsel->from->targets->next) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("SELECT statement involves more than one table or expression"));
+ retval = FALSE;
+ goto cleanup;
+ }
+ GdaSqlSelectTarget *target;
+ target = (GdaSqlSelectTarget*) stsel->from->targets->data;
+ if (!target->table_name) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("SELECT statement involves more than one table or expression"));
+ retval = FALSE;
+ goto cleanup;
+ }
+ if (!gda_sql_statement_check_validity (sel_struct, cnc, error)) {
+ retval = FALSE;
+ goto cleanup;
+ }
+
+ mstruct = sel_struct->validity_meta_struct;
+ g_assert (mstruct); /* because gda_sql_statement_check_validity() returned TRUE */
+
+ /* check that we want to modify a table */
+ if (target->validity_meta_object->obj_type != GDA_META_DB_TABLE) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("Can only build modification statement for tables"));
+ retval = FALSE;
+ goto cleanup;
+ }
+
+ /* check that the condition will be buildable */
+ mtable = GDA_META_DB_OBJECT_GET_TABLE (target->validity_meta_object);
+ if ((update || delete) && require_pk) {
+ gint i;
+ if (mtable->pk_cols_nb == 0) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("Table does not have any primary key"));
+ retval = FALSE;
+ goto cleanup;
+ }
+ for (i = 0; i < mtable->pk_cols_nb; i++) {
+ TO_IMPLEMENT;
+ }
+ }
+
+ /* actual statement structure's computation */
+ GdaSqlStatementInsert *ist;
+ GdaSqlStatementUpdate *ust;
+ GdaSqlStatementDelete *dst;
+
+ if (insert) {
+ ist = g_new0 (GdaSqlStatementInsert, 1);
+ GDA_SQL_ANY_PART (ist)->type = GDA_SQL_ANY_STMT_INSERT;
+ ist->table = gda_sql_table_new (GDA_SQL_ANY_PART (ist));
+ ist->table->table_name = g_strdup ((gchar *) target->table_name);
+ }
+
+ if (update) {
+ ust = g_new0 (GdaSqlStatementUpdate, 1);
+ GDA_SQL_ANY_PART (ust)->type = GDA_SQL_ANY_STMT_UPDATE;
+ ust->table = gda_sql_table_new (GDA_SQL_ANY_PART (ust));
+ ust->table->table_name = g_strdup ((gchar *) target->table_name);
+ }
+
+ if (delete) {
+ dst = g_new0 (GdaSqlStatementDelete, 1);
+ GDA_SQL_ANY_PART (dst)->type = GDA_SQL_ANY_STMT_DELETE;
+ dst->table = gda_sql_table_new (GDA_SQL_ANY_PART (dst));
+ dst->table->table_name = g_strdup ((gchar *) target->table_name);
+ }
+
+ GSList *expr_list;
+ gint colindex;
+ GSList *insert_values_list = NULL;
+ GHashTable *fields_hash; /* key = a table's field's name, value = we don't care */
+ fields_hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (expr_list = stsel->expr_list, colindex = 0;
+ expr_list;
+ expr_list = expr_list->next, colindex++) {
+ GdaSqlSelectField *selfield = (GdaSqlSelectField *) expr_list->data;
+ if (selfield->expr && selfield->expr->value &&
+ !strcmp (g_value_get_string (selfield->expr->value), "*")) {
+ TO_IMPLEMENT;
+ continue;
+ }
+ else {
+ if ((selfield->validity_meta_object != target->validity_meta_object) ||
+ !selfield->validity_meta_table_column)
+ continue;
+ }
+
+ /* field to insert into */
+ if (g_hash_table_lookup (fields_hash, selfield->field_name))
+ continue;
+ g_hash_table_insert (fields_hash, selfield->field_name, GINT_TO_POINTER (1));
+ if (insert) {
+ GdaSqlField *field;
+ field = gda_sql_field_new (GDA_SQL_ANY_PART (ist));
+ field->field_name = g_strdup (selfield->field_name);
+ ist->fields_list = g_slist_append (ist->fields_list, field);
+ }
+ if (update) {
+ GdaSqlField *field;
+ field = gda_sql_field_new (GDA_SQL_ANY_PART (ust));
+ field->field_name = g_strdup (selfield->field_name);
+ ust->fields_list = g_slist_append (ust->fields_list, field);
+ }
+
+ /* parameter for the inserted value */
+ GdaSqlParamSpec *pspec = g_new0 (GdaSqlParamSpec, 1);
+ GdaSqlExpr *expr;
+ GdaMetaTableColumn *tcol;
+
+ tcol = selfield->validity_meta_table_column;
+ if (insert) {
+ pspec->name = g_strdup_printf ("+%d", colindex);
+ pspec->g_type = tcol->gtype != G_TYPE_INVALID ? tcol->gtype: G_TYPE_STRING;
+ pspec->type = g_strdup (gda_g_type_to_string (pspec->g_type));
+ pspec->nullok = tcol->nullok;
+ expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ist));
+ expr->param_spec = pspec;
+ insert_values_list = g_slist_append (insert_values_list, expr);
+ }
+ if (update) {
+ pspec->name = g_strdup_printf ("+%d", colindex);
+ pspec->g_type = tcol->gtype != G_TYPE_INVALID ? tcol->gtype: G_TYPE_STRING;
+ pspec->type = g_strdup (gda_g_type_to_string (pspec->g_type));
+ pspec->nullok = tcol->nullok;
+ expr = gda_sql_expr_new (GDA_SQL_ANY_PART (ust));
+ expr->param_spec = pspec;
+ ust->expr_list = g_slist_append (ust->expr_list, expr);
+ }
+ }
+ g_hash_table_destroy (fields_hash);
+
+ /* finish the statements */
+ if (insert) {
+ GdaSqlStatement *st;
+ ist->values_list = g_slist_append (NULL, insert_values_list);
+ st = gda_sql_statement_new (GDA_SQL_STATEMENT_INSERT);
+ st->contents = ist;
+ ret_insert = g_object_new (GDA_TYPE_STATEMENT, "structure", st, NULL);
+ gda_sql_statement_free (st);
+ }
+ if (update) {
+ GdaSqlStatement *st;
+ st = gda_sql_statement_new (GDA_SQL_STATEMENT_UPDATE);
+ st->contents = ust;
+ ret_update = g_object_new (GDA_TYPE_STATEMENT, "structure", st, NULL);
+ gda_sql_statement_free (st);
+ }
+ if (delete) {
+ GdaSqlStatement *st;
+ st = gda_sql_statement_new (GDA_SQL_STATEMENT_DELETE);
+ st->contents = dst;
+ ret_delete = g_object_new (GDA_TYPE_STATEMENT, "structure", st, NULL);
+ gda_sql_statement_free (st);
+ }
+
+ cleanup:
+ gda_sql_statement_free (sel_struct);
+ if (insert)
+ *insert = ret_insert;
+ if (update)
+ *update = ret_update;
+ if (delete)
+ *delete = ret_delete;
+ return retval;
+}
Modified: trunk/libgda/gda-util.h
==============================================================================
--- trunk/libgda/gda-util.h (original)
+++ trunk/libgda/gda-util.h Wed Apr 2 20:22:59 2008
@@ -38,8 +38,6 @@
const gchar *gda_g_type_to_string (GType type);
GType gda_g_type_from_string (const gchar *str);
-GList *gda_string_hash_to_list (GHashTable *hash_table);
-
/*
* SQL escaping
*/
@@ -47,30 +45,26 @@
gchar *gda_default_unescape_string (const gchar *string);
/*
- * File management utility functions
- */
-gchar *gda_file_load (const gchar *filename);
-gboolean gda_file_save (const gchar *filename, const gchar *buffer, gint len);
-
-/*
- * XML Id encoding and decoding
- */
-gchar *gda_utility_build_encoded_id (const gchar *prefix, const gchar *id);
-gchar *gda_utility_build_decoded_id (const gchar *prefix, const gchar *id);
-
-/*
* Param & model utilities
*/
-gboolean gda_utility_check_data_model (GdaDataModel *model, gint nbcols, ...);
-void gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent,
+gboolean gda_utility_check_data_model (GdaDataModel *model, gint nbcols, ...);
+void gda_utility_data_model_dump_data_to_xml (GdaDataModel *model, xmlNodePtr parent,
const gint *cols, gint nb_cols, const gint *rows, gint nb_rows,
gboolean use_col_ids);
-void gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources);
+void gda_utility_holder_load_attributes (GdaHolder *holder, xmlNodePtr node, GSList *sources);
-/* translate any text to an alphanumerical text */
-gchar *gda_text_to_alphanum (const gchar *text);
-gchar *gda_alphanum_to_text (gchar *text);
+/*
+ * translate any text to an alphanumerical text
+ */
+gchar *gda_text_to_alphanum (const gchar *text);
+gchar *gda_alphanum_to_text (gchar *text);
+/*
+ * Statement computation from meta store
+ */
+gboolean gda_compute_dml_statements (GdaConnection *cnc, GdaStatement *select_stmt, gboolean require_pk,
+ GdaStatement **insert, GdaStatement **update, GdaStatement **delete,
+ GError **error);
G_END_DECLS
#endif
Modified: trunk/libgda/libgda.h.in
==============================================================================
--- trunk/libgda/libgda.h.in (original)
+++ trunk/libgda/libgda.h.in Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/* GDA library
- * Copyright (C) 1998 - 2006 The GNOME Foundation.
+ * Copyright (C) 1998 - 2008 The GNOME Foundation.
*
* AUTHORS:
* Michael Lausch <michael lausch at>
@@ -27,15 +27,14 @@
#define __LIBGDA_H__
#include <libgda/gda-easy.h>
-#include <libgda/gda-column-index.h>
#include <libgda/gda-column.h>
#include <libgda/gda-config.h>
#include <libgda/gda-connection-event.h>
#include <libgda/gda-connection.h>
#include <libgda/gda-connection-private.h>
+#include <libgda/gda-data-comparator.h>
#include <libgda/gda-data-model-array.h>
@LIBGDA_BDB_INC@
-#include <libgda/gda-data-model-index.h>
#include <libgda/gda-data-model-query.h>
#include <libgda/gda-data-model.h>
#include <libgda/gda-data-model-iter.h>
Modified: trunk/libgda/sql-parser/gda-statement-struct-compound.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-compound.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-compound.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -24,8 +24,8 @@
#include <string.h>
#include <glib/gi18n-lib.h>
-static gpointer gda_sql_statement_compound_new (void);
-static gboolean gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
+static gpointer gda_sql_statement_compound_new (void);
+static gboolean gda_sql_statement_compound_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
GdaSqlStatementContentsInfo compound_infos = {
GDA_SQL_STATEMENT_COMPOUND,
@@ -35,7 +35,8 @@
gda_sql_statement_compound_copy,
gda_sql_statement_compound_serialize,
- gda_sql_statement_compound_check_structure
+ gda_sql_statement_compound_check_structure,
+ NULL
};
GdaSqlStatementContentsInfo *
Modified: trunk/libgda/sql-parser/gda-statement-struct-decl.h
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-decl.h (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-decl.h Wed Apr 2 20:22:59 2008
@@ -22,6 +22,9 @@
#include <glib.h>
#include <glib-object.h>
+#include <libgda/gda-decl.h>
+#include <libgda/gda-meta-store.h>
+#include <libgda/gda-meta-struct.h>
/* error reporting */
extern GQuark gda_sql_error_quark (void);
@@ -30,7 +33,7 @@
typedef enum {
GDA_SQL_STRUCTURE_CONTENTS_ERROR,
GDA_SQL_MALFORMED_IDENTIFIER_ERROR,
- GDA_SQL_DICT_ELEMENT_MISSING_ERROR
+ GDA_SQL_VALIDATION_ERROR
} GdaSqlErrorType;
/*
@@ -137,6 +140,17 @@
/* augmenting information precision using a dictionary */
GdaSqlForeachFunc check_structure_func;
+ GdaSqlForeachFunc check_validity_func;
} GdaSqlStatementContentsInfo;
+/*
+ * Validation against a dictionary
+ */
+
+typedef struct {
+ GdaConnection *cnc;
+ GdaMetaStore *store;
+ GdaMetaStruct *mstruct;
+} GdaSqlStatementCheckValidityData;
+
#endif
Modified: trunk/libgda/sql-parser/gda-statement-struct-delete.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-delete.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-delete.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -39,7 +39,8 @@
gda_sql_statement_delete_copy,
gda_sql_statement_delete_serialize,
- gda_sql_statement_delete_check_structure
+ gda_sql_statement_delete_check_structure,
+ NULL
};
GdaSqlStatementContentsInfo *
Modified: trunk/libgda/sql-parser/gda-statement-struct-insert.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-insert.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-insert.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -40,7 +40,8 @@
gda_sql_statement_insert_copy,
gda_sql_statement_insert_serialize,
- gda_sql_statement_insert_check_structure
+ gda_sql_statement_insert_check_structure,
+ NULL
};
GdaSqlStatementContentsInfo *
Modified: trunk/libgda/sql-parser/gda-statement-struct-parts.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-parts.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-parts.c Wed Apr 2 20:22:59 2008
@@ -219,6 +219,7 @@
copy = gda_sql_field_new (NULL);
if (field->field_name)
copy->field_name = g_strdup (field->field_name);
+ copy->validity_meta_table_column = field->validity_meta_table_column;
return copy;
}
@@ -274,6 +275,7 @@
copy = gda_sql_table_new (NULL);
if (table->table_name)
copy->table_name = g_strdup (table->table_name);
+ copy->validity_meta_object = table->validity_meta_object;
return copy;
}
@@ -345,7 +347,8 @@
gda_sql_any_part_set_parent (copy->args_list->data, copy);
}
copy->args_list = g_slist_reverse (copy->args_list);
- }
+ }
+ copy->validity_meta_function = function->validity_meta_function;
return copy;
}
@@ -782,6 +785,10 @@
copy->table_name = g_strdup (field->table_name);
if (field->as)
copy->as = g_strdup (field->as);
+
+ copy->validity_meta_object = field->validity_meta_object;
+ copy->validity_meta_table_column = field->validity_meta_table_column;
+
return copy;
}
@@ -913,6 +920,9 @@
copy->table_name = g_strdup (target->table_name);
if (target->as)
copy->as = g_strdup (target->as);
+
+ copy->validity_meta_object = target->validity_meta_object;
+
return copy;
}
Modified: trunk/libgda/sql-parser/gda-statement-struct-parts.h
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-parts.h (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-parts.h Wed Apr 2 20:22:59 2008
@@ -25,6 +25,7 @@
#include <sql-parser/gda-statement-struct.h>
#include <sql-parser/gda-statement-struct-pspec.h>
#include <sql-parser/gda-statement-struct-decl.h>
+#include <libgda/gda-meta-struct.h>
typedef struct _GdaSqlExpr GdaSqlExpr;
typedef struct _GdaSqlField GdaSqlField;
@@ -66,6 +67,9 @@
struct _GdaSqlField {
GdaSqlAnyPart any;
gchar *field_name;
+
+ /* validity check with a connection */
+ GdaMetaTableColumn *validity_meta_table_column;
};
GdaSqlField *gda_sql_field_new (GdaSqlAnyPart *parent);
void gda_sql_field_free (GdaSqlField *field);
@@ -83,8 +87,8 @@
GdaSqlAnyPart any;
gchar *table_name;
- /* GdaMetaStore check */
- gpointer full_table_name;
+ /* validity check with a connection */
+ GdaMetaDbObject *validity_meta_object;
};
GdaSqlTable *gda_sql_table_new (GdaSqlAnyPart *parent);
@@ -103,8 +107,8 @@
gchar *function_name;
GSList *args_list;
- /* GdaDict check */
- gchar *full_function_name;
+ /* validity check with a connection */
+ gpointer validity_meta_function; /* to be replaced with a pointer to a structure representing a DBMS data type in GdaMetaStruct */
};
GdaSqlFunction *gda_sql_function_new (GdaSqlAnyPart *parent);
@@ -195,8 +199,9 @@
gchar *table_name; /* may be NULL if expr does not refer to a table.field */
gchar *as;
- /* GdaDict check */
- gchar *full_table_name;
+ /* validity check with a connection */
+ GdaMetaDbObject *validity_meta_object;
+ GdaMetaTableColumn *validity_meta_table_column;
};
GdaSqlSelectField *gda_sql_select_field_new (GdaSqlAnyPart *parent);
@@ -219,8 +224,8 @@
gchar *table_name; /* may be NULL if expr does not refer to a table */
gchar *as;
- /* GdaDict check */
- gchar *full_table_name;
+ /* validity check with a connection */
+ GdaMetaDbObject *validity_meta_object;
};
GdaSqlSelectTarget *gda_sql_select_target_new (GdaSqlAnyPart *parent);
Modified: trunk/libgda/sql-parser/gda-statement-struct-pspec.h
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-pspec.h (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-pspec.h Wed Apr 2 20:22:59 2008
@@ -37,7 +37,7 @@
gboolean nullok;
GType g_type;
- gpointer dict_type;
+ gpointer validity_meta_dict; /* to be replaced with a pointer to a structure representing a DBMS data type in GdaMetaStruct */
};
GdaSqlParamSpec *gda_sql_param_spec_new (GValue *simple_spec);
GdaSqlParamSpec *gda_sql_param_spec_copy (GdaSqlParamSpec *pspec);
Modified: trunk/libgda/sql-parser/gda-statement-struct-select.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-select.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-select.c Wed Apr 2 20:22:59 2008
@@ -25,6 +25,7 @@
#include <glib/gi18n-lib.h>
static gboolean gda_sql_statement_select_check_structure (GdaSqlAnyPart *stmt, gpointer data, GError **error);
+static gboolean gda_sql_statement_select_check_validity (GdaSqlAnyPart *stmt, gpointer data, GError **error);
GdaSqlStatementContentsInfo select_infos = {
GDA_SQL_STATEMENT_SELECT,
@@ -34,7 +35,8 @@
gda_sql_statement_select_copy,
gda_sql_statement_select_serialize,
- gda_sql_statement_select_check_structure
+ gda_sql_statement_select_check_structure,
+ gda_sql_statement_select_check_validity
};
GdaSqlStatementContentsInfo *
@@ -335,3 +337,48 @@
}
return TRUE;
}
+
+static gboolean
+gda_sql_statement_select_check_validity (GdaSqlAnyPart *stmt, gpointer data, GError **error)
+{
+ GdaSqlStatementSelect *select = (GdaSqlStatementSelect *) stmt;
+ GdaSqlStatementCheckValidityData *ddata = (GdaSqlStatementCheckValidityData*) data;
+ gboolean retval = TRUE;
+
+ /* validate target's names and aliases:
+ * - there can't be 2 targets with the same alias
+ * - each target name or alias can only reference at most one target
+ */
+ if (select->from && select->from->targets) {
+ GHashTable *hash; /* key = target name or alias, value = GdaSqlSelectTarget pointer */
+ GSList *list;
+ hash = g_hash_table_new (g_str_hash, g_str_equal);
+ for (list = select->from->targets; list; list = list->next) {
+ GdaSqlSelectTarget *t = (GdaSqlSelectTarget*) list->data;
+ if (t->table_name) {
+ if (g_hash_table_lookup (hash, t->table_name)) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Multiple targets named or aliased '%s'"), t->table_name);
+ retval = FALSE;
+ break;
+ }
+ g_hash_table_insert (hash, t->table_name, t);
+ }
+ if (t->as) {
+ if (g_hash_table_lookup (hash, t->as)) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Multiple targets named or aliased '%s'"), t->as);
+ retval = FALSE;
+ break;
+ }
+ g_hash_table_insert (hash, t->as, t);
+ }
+
+ if (!retval)
+ break;
+ }
+ g_hash_table_destroy (hash);
+ }
+
+ return retval;
+}
Modified: trunk/libgda/sql-parser/gda-statement-struct-trans.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-trans.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-trans.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -36,6 +36,7 @@
gda_sql_statement_trans_free,
gda_sql_statement_trans_copy,
gda_sql_statement_trans_serialize,
+ NULL,
NULL
};
Modified: trunk/libgda/sql-parser/gda-statement-struct-unknown.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-unknown.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-unknown.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -34,6 +34,7 @@
gda_sql_statement_unknown_free,
gda_sql_statement_unknown_copy,
gda_sql_statement_unknown_serialize,
+ NULL,
NULL
};
Modified: trunk/libgda/sql-parser/gda-statement-struct-update.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct-update.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct-update.c Wed Apr 2 20:22:59 2008
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Vivien Malerba
+ * Copyright (C) 2007 - 2008 Vivien Malerba
*
* This Library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License as
@@ -39,7 +39,8 @@
gda_sql_statement_update_copy,
gda_sql_statement_update_serialize,
- gda_sql_statement_update_check_structure
+ gda_sql_statement_update_check_structure,
+ NULL
};
GdaSqlStatementContentsInfo *
Modified: trunk/libgda/sql-parser/gda-statement-struct.c
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct.c (original)
+++ trunk/libgda/sql-parser/gda-statement-struct.c Wed Apr 2 20:22:59 2008
@@ -22,6 +22,7 @@
#include <libgda/sql-parser/gda-statement-struct.h>
#include <libgda/gda-debug-macros.h>
#include <libgda/gda-connection.h>
+#include <libgda/gda-meta-struct.h>
#include <libgda/sql-parser/gda-statement-struct-util.h>
#include <libgda/sql-parser/gda-statement-struct-unknown.h>
#include <libgda/sql-parser/gda-statement-struct-trans.h>
@@ -111,6 +112,10 @@
}
else
TO_IMPLEMENT;
+ if (stmt->validity_meta_struct) {
+ copy->validity_meta_struct = stmt->validity_meta_struct;
+ g_object_ref (copy->validity_meta_struct);
+ }
return copy;
}
@@ -129,6 +134,9 @@
else
TO_IMPLEMENT;
}
+ if (stmt->validity_meta_struct)
+ g_object_unref (stmt->validity_meta_struct);
+
g_free (stmt);
}
@@ -223,64 +231,99 @@
/*
* Check with dict data structure
*/
-typedef struct {
- GdaConnection *cnc;
-} DictCheckData;
-
-static gboolean foreach_check_cnc (GdaSqlAnyPart *node, DictCheckData *data, GError **error);
-static gboolean gda_sql_expr_check_cnc (GdaSqlExpr *expr, DictCheckData *data, GError **error);
-static gboolean gda_sql_field_check_cnc (GdaSqlField *field, DictCheckData *data, GError **error);
-static gboolean gda_sql_table_check_cnc (GdaSqlTable *table, DictCheckData *data, GError **error);
-static gboolean gda_sql_function_check_cnc (GdaSqlFunction *function, DictCheckData *data, GError **error);
-static gboolean gda_sql_select_field_check_cnc (GdaSqlSelectField *field, DictCheckData *data, GError **error);
-static gboolean gda_sql_select_target_check_cnc (GdaSqlSelectTarget *target, DictCheckData *data, GError **error);
+static gboolean foreach_check_clean (GdaSqlAnyPart *node, gpointer data, GError **error);
+
+static gboolean foreach_check_validity (GdaSqlAnyPart *node, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_expr_check_validity (GdaSqlExpr *expr, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_field_check_validity (GdaSqlField *field, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_table_check_validity (GdaSqlTable *table, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_function_check_validity (GdaSqlFunction *function, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_select_field_check_validity (GdaSqlSelectField *field, GdaSqlStatementCheckValidityData *data, GError **error);
+static gboolean gda_sql_select_target_check_validity (GdaSqlSelectTarget *target, GdaSqlStatementCheckValidityData *data, GError **error);
/**
- * gda_sql_statement_check_connection
+ * gda_sql_statement_check_validity
* @stmt: a #GdaSqlStatement pointer
* @cnc: a #GdaConnection object, or %NULL
* @error: a place to store errors, or %NULL
*
* If @cnc is not %NULL, then checks that all the database objects referenced in the statement actually
* exist in the connection's database (for example the table being updated in a UPDATE statement must exist in the
- * connection's database for the check to succeed).
+ * connection's database for the check to succeed). This method fills the @stmt->validity_meta_struct attribute.
*
- * If @cnc is %NULL, then remove any information from a previous call to this method stored in @stmt.
+ * If @cnc is %NULL, then remove any information from a previous call to this method stored in @stmt. In this case,
+ * the @stmt->validity_meta_struct attribute is cleared.
*
* Returns: TRUE if no error occurred
*/
gboolean
-gda_sql_statement_check_connection (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error)
+gda_sql_statement_check_validity (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error)
{
- DictCheckData data;
-
g_return_val_if_fail (stmt, FALSE);
g_return_val_if_fail (!cnc || GDA_IS_CONNECTION (cnc), FALSE);
- data.cnc = cnc;
+ /* check the structure first */
+ if (!gda_sql_statement_check_structure (stmt, error))
+ return FALSE;
- return gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents),
- (GdaSqlForeachFunc) foreach_check_cnc, &data, error);
+ /* clear any previous setting */
+ gda_sql_statement_check_clean (stmt);
+
+ if (cnc) {
+ GdaSqlStatementCheckValidityData data;
+ gboolean retval;
+
+ /* prepare data */
+ data.cnc = cnc;
+ data.store = gda_connection_get_meta_store (cnc);
+ data.mstruct = gda_meta_struct_new (GDA_META_STRUCT_FEATURE_NONE);
+
+ /* attach the GdaMetaStruct to @stmt */
+ stmt->validity_meta_struct = data.mstruct;
+ retval = gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents),
+ (GdaSqlForeachFunc) foreach_check_validity, &data, error);
+ return retval;
+ }
+ else
+ return TRUE;
}
static gboolean
-foreach_check_cnc (GdaSqlAnyPart *node, DictCheckData *data, GError **error)
+foreach_check_validity (GdaSqlAnyPart *node, GdaSqlStatementCheckValidityData *data, GError **error)
{
if (!node) return TRUE;
switch (node->type) {
+ case GDA_SQL_ANY_STMT_SELECT:
+ case GDA_SQL_ANY_STMT_INSERT:
+ case GDA_SQL_ANY_STMT_UPDATE:
+ case GDA_SQL_ANY_STMT_DELETE:
+ case GDA_SQL_ANY_STMT_COMPOUND:
+ case GDA_SQL_ANY_STMT_BEGIN:
+ case GDA_SQL_ANY_STMT_ROLLBACK:
+ case GDA_SQL_ANY_STMT_COMMIT:
+ case GDA_SQL_ANY_STMT_SAVEPOINT:
+ case GDA_SQL_ANY_STMT_ROLLBACK_SAVEPOINT:
+ case GDA_SQL_ANY_STMT_DELETE_SAVEPOINT:
+ case GDA_SQL_ANY_STMT_UNKNOWN: {
+ GdaSqlStatementContentsInfo *cinfo;
+ cinfo = gda_sql_statement_get_contents_infos (node->type);
+ if (cinfo->check_validity_func)
+ return cinfo->check_validity_func (node, data, error);
+ break;
+ }
case GDA_SQL_ANY_EXPR:
- return gda_sql_expr_check_cnc ((GdaSqlExpr*) node, data, error);
+ return gda_sql_expr_check_validity ((GdaSqlExpr*) node, data, error);
case GDA_SQL_ANY_SQL_FIELD:
- return gda_sql_field_check_cnc ((GdaSqlField*) node, data, error);
+ return gda_sql_field_check_validity ((GdaSqlField*) node, data, error);
case GDA_SQL_ANY_SQL_TABLE:
- return gda_sql_table_check_cnc ((GdaSqlTable*) node, data, error);
+ return gda_sql_table_check_validity ((GdaSqlTable*) node, data, error);
case GDA_SQL_ANY_SQL_FUNCTION:
- return gda_sql_function_check_cnc ((GdaSqlFunction*) node, data, error);
+ return gda_sql_function_check_validity ((GdaSqlFunction*) node, data, error);
case GDA_SQL_ANY_SQL_SELECT_FIELD:
- return gda_sql_select_field_check_cnc ((GdaSqlSelectField*) node, data, error);
+ return gda_sql_select_field_check_validity ((GdaSqlSelectField*) node, data, error);
case GDA_SQL_ANY_SQL_SELECT_TARGET:
- return gda_sql_select_target_check_cnc ((GdaSqlSelectTarget*) node, data, error);
+ return gda_sql_select_target_check_validity ((GdaSqlSelectTarget*) node, data, error);
default:
break;
}
@@ -288,23 +331,31 @@
}
static gboolean
-gda_sql_expr_check_cnc (GdaSqlExpr *expr, DictCheckData *data, GError **error)
+gda_sql_expr_check_validity (GdaSqlExpr *expr, GdaSqlStatementCheckValidityData *data, GError **error)
{
if (!expr) return TRUE;
if (!expr->param_spec) return TRUE;
gda_sql_expr_check_clean (expr);
/* 2 checks to do here:
- * - try to find the GdaDictType from expr->param_spec->type
+ * - try to find the data type from expr->param_spec->type using data->mstruct (not yet possible)
* - if expr->param_spec->type is NULL, then try to identify it (and expr->param_spec->g_type)
- * using @expr context
+ * using @expr context, set expr->param_spec->validity_meta_dict.
*/
TO_IMPLEMENT;
return FALSE;
}
+void
+gda_sql_expr_check_clean (GdaSqlExpr *expr)
+{
+ if (!expr) return;
+ if (expr->param_spec && expr->param_spec->validity_meta_dict)
+ TO_IMPLEMENT;
+}
+
static gboolean
-gda_sql_field_check_cnc (GdaSqlField *field, DictCheckData *data, GError **error)
+gda_sql_field_check_validity (GdaSqlField *field, GdaSqlStatementCheckValidityData *data, GError **error)
{
GdaSqlAnyPart *any;
GdaSqlTable *stable;
@@ -331,144 +382,308 @@
g_assert_not_reached ();
if (!stable) {
- if (any->type == GDA_SQL_ANY_STMT_INSERT)
- g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
- _("Missing table in INSERT statement"));
- else
- g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
- _("Missing table in UPDATE statement"));
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Missing table in statement"));
return FALSE;
}
- if (!stable->full_table_name) {
- if (! gda_sql_table_check_cnc (stable, data, error))
- return FALSE;
- g_assert (stable->full_table_name);
-
- GdaDataModel *model;
- GValue *v1, *v2;
- g_value_set_string (v1 = gda_value_new (G_TYPE_STRING), stable->table_name);
- g_value_set_string (v2 = gda_value_new (G_TYPE_STRING), field->field_name);
- model = gda_connection_get_meta_store_data (data->cnc, GDA_CONNECTION_META_FIELDS, error, 2,
- "name", v1, "field_name", v2);
- if (!model)
- return FALSE;
- if (gda_data_model_get_n_rows (model) == 0) {
- g_set_error (error, GDA_SQL_ERROR, GDA_SQL_DICT_ELEMENT_MISSING_ERROR,
- _("Field %s.%s not found"), stable->table_name, field->field_name);
- g_object_unref (model);
+ if (!stable->validity_meta_object) {
+ if (! gda_sql_table_check_validity (stable, data, error))
return FALSE;
- }
- g_object_unref (model);
- return TRUE;
}
+ g_assert (stable->validity_meta_object);
+ GdaMetaTableColumn *tcol;
+ GValue value;
+ memset (&value, 0, sizeof (GValue));
+ g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name);
+ tcol = gda_meta_struct_get_table_column (data->mstruct,
+ GDA_META_DB_OBJECT_GET_TABLE (stable->validity_meta_object),
+ &value);
+ g_value_unset (&value);
+ field->validity_meta_table_column = tcol;
+ if (!tcol) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Column '%s' not found"), field->field_name);
+ return FALSE;
+ }
+
return TRUE;
}
-void
-gda_sql_expr_check_clean (GdaSqlExpr *expr)
-{
- if (!expr) return;
- if (expr->param_spec && expr->param_spec->dict_type)
- TO_IMPLEMENT;
-}
-
void
gda_sql_field_check_clean (GdaSqlField *field)
{
if (!field) return;
- /* nothing to do */
+ field->validity_meta_table_column = NULL;
+}
+
+/* For GdaSqlSelectTarget, GdaSqlSelectField and GdaSqlTable */
+static GdaMetaDbObject *
+find_table_or_view (GdaSqlAnyPart *part, GdaSqlStatementCheckValidityData *data, const gchar *name, GError **error)
+{
+ GdaMetaDbObject *dbo;
+ GValue value;
+ GError *lerror = NULL;
+ memset (&value, 0, sizeof (GValue));
+
+ /* use @name as the table or view's real name */
+ g_value_set_string (g_value_init (&value, G_TYPE_STRING), name);
+ dbo = gda_meta_struct_complement (data->mstruct, data->store, GDA_META_DB_UNKNOWN,
+ NULL, NULL, &value, &lerror);
+ g_value_unset (&value);
+ if (!dbo) {
+ /* use @name as a table alias in the statement */
+ GdaSqlAnyPart *any;
+
+ for (any = part->parent; any && any->parent; any = any->parent);
+ if (!any)
+ g_set_error (&lerror, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("GdaSqlSelectField is not part of a SELECT statement"));
+ else {
+ switch (any->type) {
+ case GDA_SQL_ANY_STMT_SELECT: {
+ GdaSqlStatementSelect *select = (GdaSqlStatementSelect*) any;
+ if (select->from) {
+ GSList *targets;
+ for (targets = select->from->targets; targets; targets = targets->next) {
+ GdaSqlSelectTarget *target = (GdaSqlSelectTarget*) targets->data;
+ if (!target->as)
+ continue;
+ g_value_set_string (g_value_init (&value, G_TYPE_STRING),
+ target->table_name);
+ dbo = gda_meta_struct_complement (data->mstruct, data->store,
+ GDA_META_DB_UNKNOWN,
+ NULL, NULL, &value, NULL);
+ g_value_unset (&value);
+ if (dbo)
+ break;
+ }
+ }
+ break;
+ }
+ case GDA_SQL_ANY_STMT_INSERT:
+ TO_IMPLEMENT;
+ break;
+ case GDA_SQL_ANY_STMT_UPDATE:
+ TO_IMPLEMENT;
+ break;
+ case GDA_SQL_ANY_STMT_DELETE:
+ TO_IMPLEMENT;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ }
+ }
+ if (dbo) {
+ if (lerror)
+ g_error_free (lerror);
+ }
+ else {
+ if (lerror)
+ g_propagate_error (error, lerror);
+ }
+ return dbo;
}
static gboolean
-gda_sql_table_check_cnc (GdaSqlTable *table, DictCheckData *data, GError **error)
+gda_sql_table_check_validity (GdaSqlTable *table, GdaSqlStatementCheckValidityData *data, GError **error)
{
+ GdaMetaDbObject *dbo;
+
if (!table) return TRUE;
+ gda_sql_table_check_clean (table);
- TO_IMPLEMENT;
- return FALSE;
+ if (!table->table_name) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Missing table name in statement"));
+ return FALSE;
+ }
+
+ dbo = find_table_or_view ((GdaSqlAnyPart*) table, data, table->table_name, error);
+ if (dbo && ((dbo->obj_type != GDA_META_DB_TABLE) ||
+ (dbo->obj_type != GDA_META_DB_VIEW))) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Table '%s' not found"), table->table_name);
+ return FALSE;
+ }
+ table->validity_meta_object = dbo;
+
+ return table->validity_meta_object ? TRUE : FALSE;
}
void
gda_sql_table_check_clean (GdaSqlTable *table)
{
if (!table) return;
- if (table->full_table_name) {
- g_free (table->full_table_name);
- table->full_table_name = NULL;
- }
+ table->validity_meta_object = NULL;
}
static gboolean
-gda_sql_function_check_cnc (GdaSqlFunction *function, DictCheckData *data, GError **error)
+gda_sql_function_check_validity (GdaSqlFunction *function, GdaSqlStatementCheckValidityData *data, GError **error)
{
if (!function) return TRUE;
TO_IMPLEMENT;
- return FALSE;
+ return TRUE;
}
void
gda_sql_function_check_clean (GdaSqlFunction *function)
{
if (!function) return;
- if (function->full_function_name) {
- g_free (function->full_function_name);
- function->full_function_name = NULL;
- }
+ function->validity_meta_function = NULL;
}
static gboolean
-gda_sql_select_field_check_cnc (GdaSqlSelectField *field, DictCheckData *data, GError **error)
+gda_sql_select_field_check_validity (GdaSqlSelectField *field, GdaSqlStatementCheckValidityData *data, GError **error)
{
+ GValue value;
+ GdaMetaDbObject *dbo = NULL;
+ gboolean starred_field = FALSE;
+
if (!field) return TRUE;
+ gda_sql_select_field_check_clean (field);
+
+ if (!field->field_name)
+ /* field is not a table.field */
+ return TRUE;
+
+ memset (&value, 0, sizeof (GValue));
+ if (!strcmp (field->field_name, "*"))
+ starred_field = TRUE;
+
+ if (!field->table_name) {
+ /* go through all the SELECT's targets to see if there is a table with the corresponding field */
+ GdaSqlAnyPart *any;
+ GSList *targets;
+ GdaMetaTableColumn *tcol = NULL;
+
+ for (any = GDA_SQL_ANY_PART(field)->parent;
+ any && (any->type != GDA_SQL_ANY_STMT_SELECT);
+ any = any->parent);
+ if (!any) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_STRUCTURE_CONTENTS_ERROR,
+ _("GdaSqlSelectField is not part of a SELECT statement"));
+ return FALSE;
+ }
- TO_IMPLEMENT;
- return FALSE;
+ for (targets = ((GdaSqlStatementSelect *)any)->from->targets; targets; targets = targets->next) {
+ GdaSqlSelectTarget *target = (GdaSqlSelectTarget *) targets->data;
+ if (!target->validity_meta_object &&
+ !gda_sql_select_target_check_validity (target, data, error))
+ return FALSE;
+
+ g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name);
+ tcol = gda_meta_struct_get_table_column (data->mstruct,
+ GDA_META_DB_OBJECT_GET_TABLE (target->validity_meta_object),
+ &value);
+ g_value_unset (&value);
+ if (tcol) {
+ /* found a candidate */
+ if (dbo) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Could not identify table for field '%s'"), field->field_name);
+ return FALSE;
+ }
+ dbo = target->validity_meta_object;
+ }
+ }
+ if (!dbo) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Could not identify table for field '%s'"), field->field_name);
+ return FALSE;
+ }
+ field->validity_meta_object = dbo;
+ field->validity_meta_table_column = tcol;
+ }
+ else {
+ /* table part */
+ dbo = find_table_or_view ((GdaSqlAnyPart*) field, data, field->table_name, error);
+ if (dbo && (dbo->obj_type != GDA_META_DB_TABLE) &&
+ (dbo->obj_type != GDA_META_DB_VIEW)) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Table '%s' not found"), field->table_name);
+ return FALSE;
+ }
+ field->validity_meta_object = dbo;
+ if (!field->validity_meta_object)
+ return FALSE;
+
+ /* field part */
+ if (strcmp (field->field_name, "*")) {
+ GdaMetaTableColumn *tcol;
+ g_value_set_string (g_value_init (&value, G_TYPE_STRING), field->field_name);
+ tcol = gda_meta_struct_get_table_column (data->mstruct,
+ GDA_META_DB_OBJECT_GET_TABLE (field->validity_meta_object),
+ &value);
+ g_value_unset (&value);
+ field->validity_meta_table_column = tcol;
+ if (!tcol) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Column '%s' not found"), field->field_name);
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
}
void
gda_sql_select_field_check_clean (GdaSqlSelectField *field)
{
if (!field) return;
- if (field->full_table_name) {
- g_free (field->full_table_name);
- field->full_table_name = NULL;
- }
+ field->validity_meta_object = NULL;
+ field->validity_meta_table_column = NULL;
}
static gboolean
-gda_sql_select_target_check_cnc (GdaSqlSelectTarget *target, DictCheckData *data, GError **error)
+gda_sql_select_target_check_validity (GdaSqlSelectTarget *target, GdaSqlStatementCheckValidityData *data, GError **error)
{
+ GdaMetaDbObject *dbo;
+
if (!target) return TRUE;
+ if (!target->table_name)
+ return TRUE;
- TO_IMPLEMENT;
- return FALSE;
+ dbo = find_table_or_view ((GdaSqlAnyPart*) target, data, target->table_name, error);
+ if (dbo && (dbo->obj_type != GDA_META_DB_TABLE) &&
+ (dbo->obj_type != GDA_META_DB_VIEW)) {
+ g_set_error (error, GDA_SQL_ERROR, GDA_SQL_VALIDATION_ERROR,
+ _("Table '%s' not found"), target->table_name);
+ return FALSE;
+ }
+ target->validity_meta_object = dbo;
+ return target->validity_meta_object ? TRUE : FALSE;
}
void
gda_sql_select_target_check_clean (GdaSqlSelectTarget *target)
{
if (!target) return;
- if (target->full_table_name) {
- g_free (target->full_table_name);
- target->full_table_name = NULL;
- }
+ target->validity_meta_object = NULL;
}
-static gboolean foreach_check_clean (GdaSqlAnyPart *node, gpointer data, GError **error);
/**
* gda_sql_statement_check_clean
+ * @stmt: a pinter to a #GdaSqlStatement structure
+ *
+ * Cleans any data set by a previous call to gda_sql_statement_check_validity().
*/
void
gda_sql_statement_check_clean (GdaSqlStatement *stmt)
{
g_return_if_fail (stmt);
- gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents),
- (GdaSqlForeachFunc) foreach_check_clean, NULL, NULL);
+ if (stmt->validity_meta_struct) {
+ gda_sql_any_part_foreach (GDA_SQL_ANY_PART (stmt->contents),
+ (GdaSqlForeachFunc) foreach_check_clean, NULL, NULL);
+ g_object_unref (stmt->validity_meta_struct);
+ stmt->validity_meta_struct = NULL;
+ }
}
static gboolean
Modified: trunk/libgda/sql-parser/gda-statement-struct.h
==============================================================================
--- trunk/libgda/sql-parser/gda-statement-struct.h (original)
+++ trunk/libgda/sql-parser/gda-statement-struct.h Wed Apr 2 20:22:59 2008
@@ -29,6 +29,7 @@
gchar *sql;
GdaSqlStatementType stmt_type;
gpointer contents; /* depends on stmt_type */
+ GdaMetaStruct *validity_meta_struct; /* set when gda_sql_statement_check_validity() was last called */
};
GdaSqlStatement *gda_sql_statement_new (GdaSqlStatementType type);
@@ -40,7 +41,7 @@
GdaSqlStatementType gda_sql_statement_string_to_type (const gchar *type);
gboolean gda_sql_statement_check_structure (GdaSqlStatement *stmt, GError **error);
-gboolean gda_sql_statement_check_connection(GdaSqlStatement *stmt, GdaConnection *cnc, GError **error);
+gboolean gda_sql_statement_check_validity (GdaSqlStatement *stmt, GdaConnection *cnc, GError **error);
void gda_sql_statement_check_clean (GdaSqlStatement *stmt);
GdaSqlStatementContentsInfo *gda_sql_statement_get_contents_infos (GdaSqlStatementType type) ;
Modified: trunk/libgda/sqlite/gda-sqlite-provider.c
==============================================================================
--- trunk/libgda/sqlite/gda-sqlite-provider.c (original)
+++ trunk/libgda/sqlite/gda-sqlite-provider.c Wed Apr 2 20:22:59 2008
@@ -610,7 +610,7 @@
#endif
if (filename)
- cdata->file = g_strdup (filename);
+ cdata->file = filename;
errmsg = sqlite3_open (filename, &cdata->connection);
Modified: trunk/providers/postgres/gda-postgres-meta.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-meta.c (original)
+++ trunk/providers/postgres/gda-postgres-meta.c Wed Apr 2 20:22:59 2008
@@ -33,8 +33,6 @@
#include <libgda/gda-data-model-array.h>
#include <libgda/gda-set.h>
-static gboolean append_a_row (GdaDataModel *to_model, GError **error, gint nb, ...);
-
/*
* predefined statements' IDs
*/
Modified: trunk/tests/parser/Makefile.am
==============================================================================
--- trunk/tests/parser/Makefile.am (original)
+++ trunk/tests/parser/Makefile.am Wed Apr 2 20:22:59 2008
@@ -5,12 +5,17 @@
$(LIBGDA_CFLAGS) \
-DROOT_DIR=\""$(top_srcdir)"\"
-TESTS = check_parser
-check_PROGRAMS = check_parser
+TESTS = check_parser check_validation
+check_PROGRAMS = check_parser check_validation
check_parser_SOURCES = check_parser.c
check_parser_LDADD = \
$(top_builddir)/libgda/libgda-4.0.la \
$(LIBGDA_LIBS)
-EXTRA_DIST = testdata.xml
+check_validation_SOURCES = check_validation.c
+check_validation_LDADD = \
+ $(top_builddir)/libgda/libgda-4.0.la \
+ $(LIBGDA_LIBS)
+
+EXTRA_DIST = testdata.xml testvalid.xml
Added: trunk/tests/parser/check_validation.c
==============================================================================
--- (empty file)
+++ trunk/tests/parser/check_validation.c Wed Apr 2 20:22:59 2008
@@ -0,0 +1,222 @@
+#include <stdio.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <gmodule.h>
+#include <libgda/libgda.h>
+#include <libgda/gda-util.h>
+#include <sql-parser/gda-sql-parser.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+
+GdaConnection *cnc;
+static gint do_test (const xmlChar *id, const xmlChar *sql, gboolean valid_expected,
+ const gchar *computed_type, const xmlChar *computed_exp, gboolean require_pk);
+
+int
+main (int argc, char** argv)
+{
+ xmlDocPtr doc;
+ xmlNodePtr root, node;
+ gint failures = 0;
+ gint ntests = 0;
+ gchar *fname;
+
+ gda_init ("Parser validation", ".1", argc, argv);
+
+ /* open connection */
+ gchar *cnc_string;
+ fname = g_build_filename (ROOT_DIR, "data", NULL);
+ cnc_string = g_strdup_printf ("DB_DIR=%s;DB_NAME=sales_test", fname);
+ g_free (fname);
+ cnc = gda_connection_open_from_string ("SQLite", cnc_string, NULL,
+ GDA_CONNECTION_OPTIONS_READ_ONLY, NULL);
+ if (!cnc) {
+ g_print ("Failed to open connection, cnc_string = %s\n", cnc_string);
+ exit (1);
+ }
+ if (!gda_connection_update_meta_store (cnc, NULL, NULL)) {
+ g_print ("Failed to update meta store, cnc_string = %s\n", cnc_string);
+ exit (1);
+ }
+ g_free (cnc_string);
+
+ /* load file */
+ fname = g_build_filename (ROOT_DIR, "tests", "parser", "testvalid.xml", NULL);
+ if (! g_file_test (fname, G_FILE_TEST_EXISTS)) {
+ g_print ("File '%s' does not exist\n", fname);
+ exit (1);
+ }
+
+ /* use test data */
+ doc = xmlParseFile (fname);
+ g_free (fname);
+ g_assert (doc);
+ root = xmlDocGetRootElement (doc);
+ g_assert (!strcmp ((gchar*) root->name, "testdata"));
+ for (node = root->children; node; node = node->next) {
+ if (strcmp ((gchar*) node->name, "test"))
+ continue;
+ xmlNodePtr snode;
+ xmlChar *sql = NULL;
+ xmlChar *id;
+ gboolean valid = FALSE;
+
+ id = xmlGetProp (node, BAD_CAST "id");
+ for (snode = node->children; snode; snode = snode->next) {
+ if (!strcmp ((gchar*) snode->name, "sql")) {
+ sql = xmlNodeGetContent (snode);
+ xmlChar *prop;
+ prop = xmlGetProp (snode, "valid");
+ if (prop) {
+ if ((*prop == 't') || (*prop == 'T') || (*prop == '1'))
+ valid = TRUE;
+ xmlFree (prop);
+ }
+ }
+ else if (!strcmp ((gchar*) snode->name, "insert") ||
+ !strcmp ((gchar*) snode->name, "update") ||
+ !strcmp ((gchar*) snode->name, "delete")) {
+ xmlChar *comp_exp;
+ xmlChar *prop;
+ gboolean require_pk = TRUE;
+ comp_exp = xmlNodeGetContent (snode);
+ prop = xmlGetProp (snode, "need_pk");
+ if (prop) {
+ if ((*prop == 'f') || (*prop == 'F') || (*prop == '0'))
+ require_pk = FALSE;
+ xmlFree (prop);
+ }
+ if (sql) {
+ if (!do_test (id, sql, valid, snode->name, comp_exp, require_pk))
+ failures++;
+ ntests++;
+ }
+ }
+ }
+ if (sql) {
+ if (!do_test (id, sql, valid, NULL, NULL, FALSE))
+ failures++;
+ ntests++;
+ }
+
+ /* mem free */
+ if (sql) xmlFree (sql);
+ if (id) xmlFree (id);
+ }
+ xmlFreeDoc (doc);
+
+ g_print ("TESTS COUNT: %d\n", ntests);
+ g_print ("FAILURES: %d\n", failures);
+
+ return failures != 0 ? 1 : 0;
+}
+
+/*
+ * Returns: the number of failures
+ */
+static gint
+do_test (const xmlChar *id, const xmlChar *sql, gboolean valid_expected,
+ const gchar *computed_type, const xmlChar *computed_exp, gboolean require_pk)
+{
+ static GdaSqlParser *parser = NULL;
+ GdaStatement *stmt;
+ gboolean is_valid;
+ GError *error = NULL;
+
+ if (!parser) {
+ parser = gda_connection_create_parser (cnc);
+ if (!parser)
+ parser = gda_sql_parser_new ();
+ }
+
+#ifdef GDA_DEBUG
+ if (computed_type)
+ g_print ("===== TEST %s COMPUTING %s (%s), SQL: @%s \n", id, computed_type,
+ require_pk ? "PK fields" : "All fields", sql);
+ else
+ g_print ("===== TEST %s SQL: @%s \n", id, sql);
+#endif
+
+ stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+ if (!stmt) {
+ g_print ("ERROR for test '%s': could not parse statement\n", id);
+ return FALSE;
+ }
+ is_valid = gda_statement_check_validity (stmt, cnc, &error);
+ if (is_valid && !valid_expected) {
+ g_print ("ERROR for test '%s': statement is valid but test expected it invalid\n", id);
+ g_object_unref (stmt);
+ return FALSE;
+ }
+ if (!is_valid && valid_expected) {
+ g_print ("ERROR for test '%s': statement is invalid but test expected it valid: %s\n", id,
+ error && error->message ? error->message : "No detail");
+ g_object_unref (stmt);
+ return FALSE;
+ }
+ /*g_print ("EXP %d, got %d\n", valid_expected, is_valid);*/
+ /*g_print ("PARSED: %s\n", gda_statement_serialize (stmt));*/
+
+ if (computed_exp) {
+ GdaStatement *cstmt = NULL;
+ switch (*computed_type) {
+ case 'i':
+ case 'I':
+ gda_compute_dml_statements (cnc, stmt, require_pk, &cstmt, NULL, NULL, &error);
+ break;
+ case 'u':
+ case 'U':
+ gda_compute_dml_statements (cnc, stmt, require_pk, NULL, &cstmt, NULL, &error);
+ break;
+ case 'd':
+ case 'D':
+ gda_compute_dml_statements (cnc, stmt, require_pk, NULL, NULL, &cstmt, &error);
+ break;
+ default:
+ TO_IMPLEMENT;
+ }
+
+ if (!*computed_exp && cstmt) {
+ g_object_unref (stmt);
+ gchar *serial, *rend;
+ serial = gda_statement_serialize (cstmt);
+ rend = gda_statement_to_sql (cstmt, NULL, NULL);
+ g_print ("ERROR for test '%s': %s statement created but none expected\n"
+ "\tgot: %s\n\tSQL: %s\n", id, computed_type, serial, rend);
+ g_free (serial);
+ g_free (rend);
+ g_object_unref (cstmt);
+ return FALSE;
+ }
+ if (*computed_exp && !cstmt) {
+ g_print ("ERROR for test '%s': %s statement not created but expected: %s\n", id,
+ computed_type,
+ error && error->message ? error->message : "No detail");
+ g_object_unref (stmt);
+ return FALSE;
+ }
+ if (*computed_exp && cstmt) {
+ gchar *serial;
+ serial = gda_statement_serialize (cstmt);
+ if (strcmp (serial, computed_exp)) {
+ gchar *rend;
+ rend = gda_statement_to_sql (cstmt, NULL, NULL);
+ g_print ("ERROR for test '%s': computed %s statement is incorrect:\n"
+ "\texp: %s\n\tgot: %s\n\tSQL: %s\n", id, computed_type, computed_exp, serial,
+ rend);
+ g_free (rend);
+ g_object_unref (stmt);
+ g_object_unref (cstmt);
+ g_free (serial);
+ return FALSE;
+ }
+ g_free (serial);
+ }
+ }
+ g_object_unref (stmt);
+ return TRUE;
+}
Added: trunk/tests/parser/testvalid.xml
==============================================================================
--- (empty file)
+++ trunk/tests/parser/testvalid.xml Wed Apr 2 20:22:59 2008
@@ -0,0 +1,82 @@
+<testdata>
+ <!-- table not found -->
+ <test id="1">
+ <sql valid="f">SELECT id, name FROM customer</sql>
+ </test>
+
+ <!-- column ambiguity -->
+ <test id="2">
+ <sql valid="f">SELECT id FROM customers INNER JOIN salesrep</sql>
+ </test>
+
+ <test id="3">
+ <sql valid="t">SELECT customers.id FROM customers INNER JOIN salesrep</sql>
+ </test>
+
+ <test id="3">
+ <sql valid="t">SELECT c.id FROM customers as c INNER JOIN salesrep</sql>
+ </test>
+
+ <!-- multiple targets with naming conflicts -->
+ <test id="10">
+ <sql valid="f">SELECT c.id FROM customers as c INNER JOIN salesrep as c</sql>
+ </test>
+ <test id="11">
+ <sql valid="f">SELECT c.id FROM customers INNER JOIN salesrep as customers</sql>
+ </test>
+ <test id="11">
+ <sql valid="f">SELECT version() FROM customers, customers</sql>
+ </test>
+
+ <!-- computing DML commands from SELECT -->
+
+ <!-- no target table to modify -->
+ <test id="pre0">
+ <sql valid="t">SELECT 3</sql>
+ <insert/>
+ <update/>
+ <delete/>
+ </test>
+
+ <!-- more than 1 target table to modify -->
+ <test id="pre1">
+ <sql valid="t">SELECT version() FROM customers, salesrep</sql>
+ <insert/>
+ <update/>
+ <delete/>
+ </test>
+
+ <!-- target is not a table -->
+ <test id="pre2">
+ <sql valid="t">SELECT 123 FROM (SELECT name FROM customers) as c</sql>
+ <insert/>
+ <update/>
+ <delete/>
+ </test>
+
+ <!-- target has no primary key -->
+ <test id="pre3">
+ <sql valid="t">SELECT * FROM sales_orga</sql>
+ <insert>unknown</insert>
+ <update/>
+ <delete/>
+ </test>
+
+ <test id="0">
+ <sql valid="t">SELECT id, name FROM customers</sql>
+ <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+1","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
+ <update>unknown</update>
+ <delete>unknown</delete>
+ </test>
+
+ <test id="0.1">
+ <sql valid="t">SELECT id, 3.14, name FROM customers</sql>
+ <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
+ </test>
+
+ <test id="0.2">
+ <sql valid="t">SELECT id, 3.14, name, id FROM customers</sql>
+ <insert>{"statement":{"sql":null,"stmt_type":"INSERT","contents":{"table":"customers","fields":["id","name"],"values":[[{"value":null,"param_spec":{"name":"+0","descr":null,"type":"gint","is_param":false,"nullok":false}},{"value":null,"param_spec":{"name":"+2","descr":null,"type":"gchararray","is_param":false,"nullok":false}}]]}}}</insert>
+ </test>
+
+</testdata>
Modified: trunk/tools/gda-list-server-op.c
==============================================================================
--- trunk/tools/gda-list-server-op.c (original)
+++ trunk/tools/gda-list-server-op.c Wed Apr 2 20:22:59 2008
@@ -35,7 +35,7 @@
g_option_context_free (context);
gda_init ("list-server-op", PACKAGE_VERSION, argc, argv);
- xml_dir = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-3.0", NULL);
+ xml_dir = gda_gbr_get_file_path (GDA_DATA_DIR, "libgda-4.0", NULL);
g_print (_("Using XML descriptions in %s\n"), xml_dir);
if (prov)
g_print ("For provider %s\n", prov);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]