[libgda] JDBC provider: make it possible to use connection parameters similar to other providers



commit 613179a2b3857e57d3c3866a4446a19873857cfe
Author: Vivien Malerba <malerba gnome-db org>
Date:   Fri May 3 22:05:26 2013 +0200

    JDBC provider: make it possible to use connection parameters similar to other providers
    
    like HOST, DB_NAME, ...

 doc/C/limitations.xml                              |   15 +--
 doc/C/prov-notes.xml                               |   48 +++++++
 providers/jdbc/.gitignore                          |    1 +
 providers/jdbc/Makefile.am                         |   16 ++-
 providers/jdbc/gda-jdbc-provider.c                 |  136 +++++++++++++++++++-
 providers/jdbc/jdbc-mappings.xml                   |   12 ++
 providers/jdbc/jdbc.gresource.xml                  |    6 +
 ...osoft.sqlserver.jdbc.SQLServerDriver_dsn.xml.in |    9 ++
 providers/jdbc/jdbc_specs_dsn.xml.in               |    2 +-
 providers/jdbc/libmain.c                           |   10 +-
 10 files changed, 226 insertions(+), 29 deletions(-)
---
diff --git a/doc/C/limitations.xml b/doc/C/limitations.xml
index 4989aa1..e755576 100644
--- a/doc/C/limitations.xml
+++ b/doc/C/limitations.xml
@@ -202,22 +202,9 @@
       needs to load the Java Virtual Machine (JVM) runtime first).
     </para>
 
-    <sect2><title>JDBC drivers' location</title>
-      <para>
-       JDBC drivers (".jar" files) are searched for in the following locations:
-       <orderedlist>
-         <listitem><para>in each directory or JAR file in the <envar>CLASSPATH</envar> environment variable
-             (if set)</para></listitem>
-         <listitem><para>in the <filename>$HOME/.local/share/libgda/config</filename> directory (or 
-             <filename class="directory">$HOME/.libgda</filename> if if exists and
-             <filename>$HOME/.local/share/libgda/config</filename> does not)</para></listitem>
-       </orderedlist>
-      </para>
-    </sect2>
-
     <sect2><title>Last inserted row's values</title>
       <para>
-       TODO.
+       Not yet supported.
       </para>
     </sect2>
 
diff --git a/doc/C/prov-notes.xml b/doc/C/prov-notes.xml
index a897a7f..1018796 100644
--- a/doc/C/prov-notes.xml
+++ b/doc/C/prov-notes.xml
@@ -346,5 +346,53 @@ DETACH DATABASE plaintext; </programlisting>
   </sect2>
   </sect1>
 
+  <sect1 id="provider_notes_jdbc">
+    <title>For JDBC</title>
+    <sect2>
+      <title>How it works</title>
+      <para>
+       JDBC (Java Database Connectivity) is a Java-based technology to access databases, not unlike ODBC.
+       The JDBC provider runs a Java Virtual Machine in which the installed JDBC drivers are loaded. 
Connections
+       are established and used through the JDBC driver, making an extensive use of the JNI (Java Native 
Interface)
+       technology.
+      </para>
+      <para>
+       Any JDBC driver can be used, though only some of them have actually been tested. Some specializations
+       have been made to adapt to some corner cases in the way some JDBC drivers are written or some 
specificities
+       of some database engines.
+      </para>
+      <para>
+       Note that the JDBC drivers are not provided by Libgda and must be obtained and installed separately.
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>JDBC drivers' location</title>
+      <para>
+       JDBC drivers (".jar" files) are searched for in the following locations:
+       <orderedlist>
+         <listitem><para>in each directory or JAR file in the <envar>CLASSPATH</envar> environment variable
+             (if set)</para></listitem>
+         <listitem><para>in the <filename>$HOME/.local/share/libgda/config</filename> directory (or 
+             <filename class="directory">$HOME/.libgda</filename> if if exists and
+             <filename>$HOME/.local/share/libgda/config</filename> does not)</para></listitem>
+       </orderedlist>
+      </para>
+    </sect2>
+
+    <sect2>
+      <title>Connection parameters</title>
+      <para>
+       To connect to a database, the expected connection parameters are the ones required by the JDBC driver 
being
+       used, which varies from driver to driver (for more information, refer to each driver's 
documentation). Thus
+       &Libgda; expects only one argument named "URL" which it passes (without any modification) to the JDBC 
driver.
+      </para>
+      <para>
+       However, for some widely used servers (such as SqlServer), Libgda also accepts some parameters like
+       for other database providers (like DB_NAME, HOST, ...). In this case one can either provide these 
parameters
+       or provide the URL parameter (like for any JDBC provider) to specify a connection to open.
+      </para>
+    </sect2>
+  </sect1>
   
 </chapter>
diff --git a/providers/jdbc/.gitignore b/providers/jdbc/.gitignore
index 2d0d7ec..7be24f6 100644
--- a/providers/jdbc/.gitignore
+++ b/providers/jdbc/.gitignore
@@ -3,3 +3,4 @@
 gda-list-jdbc-providers-5.*
 gda-jdbc-test
 Gda*.h
+jdbc-resources.[ch]
\ No newline at end of file
diff --git a/providers/jdbc/Makefile.am b/providers/jdbc/Makefile.am
index 1a95f73..45f5871 100644
--- a/providers/jdbc/Makefile.am
+++ b/providers/jdbc/Makefile.am
@@ -29,10 +29,9 @@ jni_sources = \
 jni_headers = $(jni_sources:.c=.h) 
 jni_classes = $(jni_sources:.c=.class) 
 
-$(libgda_jdbc_la_OBJECTS): $(jni_headers)
+resources = jdbc-resources.h jdbc-resources.c
 
-aaa:
-       echo $(path_jni_sources)
+$(libgda_jdbc_la_OBJECTS): $(jni_headers) $(resources)
 
 libgda_jdbc_la_SOURCES = \
        gda-jdbc-blob-op.c \
@@ -55,8 +54,8 @@ libgda_jdbc_la_SOURCES = \
        jni-wrapper.h \
        jni-wrapper.c \
        $(jni_sources) \
-       $(jni_headers)
-
+       $(jni_headers) \
+       $(resources)
 
 libgda_jdbc_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) 
$(LIBTOOL_PROV_EXPORT_OPTIONS)
 libgda_jdbc_la_LIBADD = \
@@ -71,6 +70,10 @@ if PLATFORM_WIN32
 libgda_jdbc_la_LDFLAGS += -Wl,--kill-at
 endif
 
+jdbc-resources.h jdbc-resources.c: $(srcdir)/jdbc.gresource.xml Makefile $(shell $(GLIB_COMPILE_RESOURCES) 
--sourcedir=$(srcdir) --generate-dependencies $(srcdir)/jdbc.gresource.xml)
+       $(AM_V_GEN) $(GLIB_COMPILE_RESOURCES) --target=$@ --sourcedir=$(srcdir) --generate --c-name _jdbc 
--manual-register $<
+
+CLEANFILES = $(resources)
 
 $(jni_headers): $(jdbcprov_classes)
        $(JAVAH) -classpath . -d $(builddir) -force `basename $@ | sed -e 's/\.h$$//'`
@@ -101,7 +104,8 @@ clean-local:
 xmldir   = $(datadir)/libgda-5.0
 xml_in_files = \
        jdbc_specs_dsn.xml.in \
-       jdbc_specs_create_table.xml.in 
+       jdbc_specs_create_table.xml.in \
+       jdbc_specs_com.microsoft.sqlserver.jdbc.SQLServerDriver_dsn.xml.in
 
 @INTLTOOL_XML_RULE@
 
diff --git a/providers/jdbc/gda-jdbc-provider.c b/providers/jdbc/gda-jdbc-provider.c
index 1ae5360..8875f7d 100644
--- a/providers/jdbc/gda-jdbc-provider.c
+++ b/providers/jdbc/gda-jdbc-provider.c
@@ -40,6 +40,7 @@
 #include "gda-jdbc-util.h"
 #include "jni-wrapper.h"
 #include "jni-globals.h"
+#include "jdbc-resources.h"
 
 #define _GDA_PSTMT(x) ((GdaPStmt*)(x))
 
@@ -336,6 +337,121 @@ gda_jdbc_provider_get_version (G_GNUC_UNUSED GdaServerProvider *provider)
        return PACKAGE_VERSION;
 }
 
+/*
+ * make_url_from_params:
+ *
+ * Creates the URL to pass to the JDBC driver to open a connection. It uses the
+ * jdbc_mappings.xml file
+ *
+ * Returns: a new string, or %NULL if not enough information found to create the connection URL
+ */
+static gchar *
+make_url_from_params (GdaServerProvider *provider, GdaConnection *cnc,
+                     GdaQuarkList *params, G_GNUC_UNUSED GdaQuarkList *auth)
+{
+       GBytes *data;
+       const gchar *xmlstr;
+       gsize data_size = 0;
+       _jdbc_register_resource ();
+       data = g_resources_lookup_data ("/jdbc/jdbc-mappings.xml", G_RESOURCE_LOOKUP_FLAGS_NONE, NULL);
+       g_assert (data);
+       xmlstr = g_bytes_get_data (data, &data_size);
+
+       xmlDocPtr doc;
+       doc = xmlParseMemory (xmlstr, data_size);
+       g_bytes_unref (data);
+       _jdbc_unregister_resource ();
+
+        if (!doc)
+               return NULL;
+
+       xmlNodePtr root, node;
+       GString *url = NULL;
+       root = xmlDocGetRootElement (doc);
+       if (strcmp ((gchar*) root->name, "jdbc-mappings"))
+               goto out;
+
+       for (node = root->children; node; node = node->next) {
+                if (strcmp ((gchar *) node->name, "driver"))
+                        continue;
+               xmlChar *prop;
+               prop = xmlGetProp (node, BAD_CAST "name");
+               if (!prop)
+                       continue;
+               if (!strcmp ((gchar*) prop, gda_server_provider_get_name (provider))) {
+                       xmlFree (prop);
+                       break;
+               }
+               xmlFree (prop);
+        }
+       if (!node)
+               goto out;
+
+       url = g_string_new ("");
+       for (node = node->children; node; node = node->next) {
+                if (!strcmp ((gchar *) node->name, "prefix")) {
+                       xmlChar *contents;
+                       contents = xmlNodeGetContent (node);
+                       if (contents && *contents)
+                               g_string_append (url, (gchar*) contents);
+               }
+               else if (!strcmp ((gchar *) node->name, "part")) {
+                       xmlChar *prop;
+                       const gchar *cvarvalue = NULL;
+                       gchar *varvalue = NULL;
+                       gboolean opt = FALSE;
+                       prop = xmlGetProp (node, BAD_CAST "variable");
+                       if (prop) {
+                               cvarvalue = gda_quark_list_find (params, (gchar*) prop);
+                               xmlFree (prop);
+                       }
+                       prop = xmlGetProp (node, BAD_CAST "optional");
+                       if (prop) {
+                               if ((*prop == 't') || (*prop == 'T'))
+                                       opt = TRUE;
+                               xmlFree (prop);
+                       }
+
+                       prop = xmlGetProp (node, BAD_CAST "if");
+                       if (prop) {
+                               if (!strcmp ((gchar*) prop, "CncReadOnly")) {
+                                       if (gda_connection_get_options (cnc) & 
GDA_CONNECTION_OPTIONS_READ_ONLY) {
+                                               xmlFree (prop);
+                                               prop = xmlGetProp (node, BAD_CAST "value");
+                                               if (prop)
+                                                       varvalue = g_strdup ((gchar*) prop);
+                                       }
+                               }
+                               if (prop)
+                                       xmlFree (prop);
+                       }
+
+                       if (cvarvalue || varvalue) {
+                               prop = xmlGetProp (node, BAD_CAST "prefix");
+                               if (prop) {
+                                       g_string_append (url, (gchar*) prop);
+                                       xmlFree (prop);
+                               }
+                               g_string_append (url, varvalue ? varvalue : cvarvalue);
+                               g_free (varvalue);
+                       }
+                       else if (!varvalue && !cvarvalue && !opt) {
+                               /* missing parameter */
+                               g_string_free (url, TRUE);
+                               url = NULL;
+                               goto out;
+                       }
+               }
+        }
+
+ out:
+       xmlFreeDoc (doc);
+       if (url)
+               return g_string_free (url, FALSE);
+       else
+               return NULL;
+}
+
 /* 
  * Open connection request
  *
@@ -365,12 +481,17 @@ gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
        }
 
        /* Check for connection parameters */
-       const gchar *url;
-       url = gda_quark_list_find (params, "URL");
+       gchar *url;
+       url = make_url_from_params (provider, cnc, params, auth);
        if (!url) {
-               gda_connection_add_event_string (cnc,
-                                                _("The connection string must contain the URL value"));
-               return FALSE;
+               const gchar *cstr;
+               cstr = gda_quark_list_find (params, "URL");
+               if (!cstr) {
+                       gda_connection_add_event_string (cnc,
+                                                        _("The connection string must contain the URL 
value"));
+                       return FALSE;
+               }
+               url = g_strdup (cstr);
        }
 
        /* Check for username / password */
@@ -397,10 +518,14 @@ gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
                                                 error && error->message ? error->message : _("No detail"));
                if (error)
                        g_error_free (error);
+               g_free (url);
                return FALSE;
        }
 
        jstr = (*env)->NewStringUTF (env, url);
+       /*g_print ("URL = [%s] USERNAME = [%s] PASSWORD = [%s]\n", url, username, password);*/
+       g_free (url);
+       url = NULL;
        if (username)
                jstr1 = (*env)->NewStringUTF (env, username);
        else
@@ -409,6 +534,7 @@ gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *c
                jstr2 = (*env)->NewStringUTF (env, password);
        else
                jstr2 = NULL;
+
        obj_value = jni_wrapper_method_call (env, GdaJProvider__openConnection, 
                                             jprov->jprov_obj, &error_code, &sql_state, &error,
                                             jstr, jstr1, jstr2);
diff --git a/providers/jdbc/jdbc-mappings.xml b/providers/jdbc/jdbc-mappings.xml
new file mode 100644
index 0000000..0cf60cd
--- /dev/null
+++ b/providers/jdbc/jdbc-mappings.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<jdbc-mappings>
+  <driver name="com.microsoft.sqlserver.jdbc.SQLServerDriver">
+    <prefix>jdbc:sqlserver://</prefix>
+    <part variable="HOST" optional="true"/>
+    <part variable="INSTANCE" optional="true" prefix="/"/>
+    <part variable="PORT" optional="true" prefix=":"/>
+    <!-- properties, see http://msdn.microsoft.com/en-us/library/ms378988.aspx -->
+    <part variable="DB_NAME" optional="true" prefix=";database="/>
+    <part variable="applicationIntent" optional="true" prefix=";applicationIntent=" value="ReadOnly" 
if="CncReadOnly"/>
+  </driver>
+</jdbc-mappings>
diff --git a/providers/jdbc/jdbc.gresource.xml b/providers/jdbc/jdbc.gresource.xml
new file mode 100644
index 0000000..511f0a7
--- /dev/null
+++ b/providers/jdbc/jdbc.gresource.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+  <gresource prefix="/jdbc">
+    <file compressed="true">jdbc-mappings.xml</file>
+  </gresource>
+</gresources>
diff --git a/providers/jdbc/jdbc_specs_com.microsoft.sqlserver.jdbc.SQLServerDriver_dsn.xml.in 
b/providers/jdbc/jdbc_specs_com.microsoft.sqlserver.jdbc.SQLServerDriver_dsn.xml.in
new file mode 100644
index 0000000..8a2d1ed
--- /dev/null
+++ b/providers/jdbc/jdbc_specs_com.microsoft.sqlserver.jdbc.SQLServerDriver_dsn.xml.in
@@ -0,0 +1,9 @@
+<?xml version="1.0"?>
+<data-set-spec>
+  <parameters>
+    <parameter id="DB_NAME" _name="Database name" _descr="The name of a database to connect to" 
gdatype="gchararray"/>
+    <parameter id="INSTANCE" _name="Instance" _descr="The instance to connect to, if not specified, a 
connection to the default instance is made" gdatype="gchararray"/>
+    <parameter id="HOST" _name="Database server" _descr="Host on which the database server is running or 
leave this field empty" gdatype="gchararray"/>
+    <parameter id="PORT" _name="Port" _descr="Database server port, 1433 by default" gdatype="gint"/>
+  </parameters>
+</data-set-spec>
diff --git a/providers/jdbc/jdbc_specs_dsn.xml.in b/providers/jdbc/jdbc_specs_dsn.xml.in
index fdcd4c8..2fb267c 100644
--- a/providers/jdbc/jdbc_specs_dsn.xml.in
+++ b/providers/jdbc/jdbc_specs_dsn.xml.in
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <data-set-spec>
   <parameters>
-    <parameter id="URL" _name="Connection URL" _descr="" gdatype="gchararray" nullok="FALSE"/>
+    <parameter id="URL" _name="Connection URL" _descr="Connection string required by the JDBC driver, refer 
to the used JDBC driver for its contents and format" gdatype="gchararray" nullok="FALSE"/>
   </parameters>
 </data-set-spec>
diff --git a/providers/jdbc/libmain.c b/providers/jdbc/libmain.c
index f333a7e..cef2c0b 100644
--- a/providers/jdbc/libmain.c
+++ b/providers/jdbc/libmain.c
@@ -295,12 +295,16 @@ plugin_get_sub_description (const gchar *name)
 }
 
 EXPORT gchar *
-plugin_get_sub_dsn_spec (G_GNUC_UNUSED const gchar *name)
+plugin_get_sub_dsn_spec (const gchar *name)
 {
-       gchar *ret, *dir;
+       gchar *ret, *dir, *tmp;
 
        dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
-       ret = gda_server_provider_load_file_contents (module_path, dir, "jdbc_specs_dsn.xml");
+       tmp = g_strdup_printf ("jdbc_specs_%s_dsn.xml", name);
+       ret = gda_server_provider_load_file_contents (module_path, dir, tmp);
+       g_free (tmp);
+       if (!ret)
+               ret = gda_server_provider_load_file_contents (module_path, dir, "jdbc_specs_dsn.xml");
        g_free (dir);
        return ret;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]