libgda r3258 - in trunk: . doc/C libgda libgda/sqlite/virtual po providers providers/jdbc providers/jdbc/doc providers/mdb providers/postgres tests/data-models tools



Author: vivien
Date: Sat Nov 29 14:48:16 2008
New Revision: 3258
URL: http://svn.gnome.org/viewvc/libgda?rev=3258&view=rev

Log:
2008-11-29  Vivien Malerba <malerba gnome-db org>

	* libgda/gda-config.c: shared libraries corresponding to providers' implementations
	can now implement more than one provider type (used by the JDBC provider which
	implements a provider per JDBC driver found)
	* providers/postgres/gda-postgres-recordset.c: comments corrections
	* libgda/gda-data-select.c: code indentation
	* libgda/gda-quark-list.c: shorter code which corrects potentially double free
	problem
	* tools/gda-sql.c:
	* providers/postgres/gda-postgres-blob-op.c:
	* libgda/dir-blob-op.c:
	* libgda/gda-value.c:
	* libgda/sqlite/virtual/gda-vprovider-data-model.c: minor corrections
	* configure.in:
	* getsp.class: new JAVA detection
	* po/POTFILES.in:
	* providers/Makefile.am
	* providers/jdbc: new provider which wraps JDBC, giving access to many
	databases: pure JAVA databases such as H2, Derby, HSQLDB (used by
	OpenOffice.org's Base component) or any other database with a JDBC driver,
	see the providers/jdbc/doc/index.html file for more information
	* tests/data-models/check_virtual.c: set up test environment
	* libgda/gda-data-select.h: added gda_data_select_get_connection() which
	is already implemented and documented (Carlos Savoretti)
	* libgda/gda-meta-struct.c: set the GDA_ATTRIBUTE_DESCRIPTION attribute for
	table's columns (Carlos Savoretti)
	* providers/mdb/libmain.c: correctly use binreloc to detect provider's ressources
	location
	* doc/C: doc. update
	* po/: ran "make update-po"


Added:
   trunk/getsp.class   (contents, props changed)
   trunk/providers/jdbc/   (props changed)
   trunk/providers/jdbc/GdaInputStream.c
   trunk/providers/jdbc/GdaJBlobOp.c
   trunk/providers/jdbc/GdaJColumnInfos.c
   trunk/providers/jdbc/GdaJConnection.c
   trunk/providers/jdbc/GdaJMeta.c
   trunk/providers/jdbc/GdaJPStmt.c
   trunk/providers/jdbc/GdaJProvider.c
   trunk/providers/jdbc/GdaJResultSet.c
   trunk/providers/jdbc/GdaJResultSetInfos.c
   trunk/providers/jdbc/GdaJValue.c
   trunk/providers/jdbc/MANIFEST.MF
   trunk/providers/jdbc/Makefile.am
   trunk/providers/jdbc/doc/
   trunk/providers/jdbc/doc/index.html
   trunk/providers/jdbc/doc/structure.dia   (contents, props changed)
   trunk/providers/jdbc/doc/structure.png   (contents, props changed)
   trunk/providers/jdbc/gda-jdbc-blob-op.c
   trunk/providers/jdbc/gda-jdbc-blob-op.h
   trunk/providers/jdbc/gda-jdbc-ddl.c
   trunk/providers/jdbc/gda-jdbc-ddl.h
   trunk/providers/jdbc/gda-jdbc-meta.c
   trunk/providers/jdbc/gda-jdbc-meta.h
   trunk/providers/jdbc/gda-jdbc-provider.c
   trunk/providers/jdbc/gda-jdbc-provider.h
   trunk/providers/jdbc/gda-jdbc-pstmt.c
   trunk/providers/jdbc/gda-jdbc-pstmt.h
   trunk/providers/jdbc/gda-jdbc-recordset.c
   trunk/providers/jdbc/gda-jdbc-recordset.h
   trunk/providers/jdbc/gda-jdbc-test.c
   trunk/providers/jdbc/gda-jdbc-util.c
   trunk/providers/jdbc/gda-jdbc-util.h
   trunk/providers/jdbc/gda-jdbc.h
   trunk/providers/jdbc/gda-list-jdbc-providers.c
   trunk/providers/jdbc/h2.java
   trunk/providers/jdbc/jdbc_specs_create_table.xml.in
   trunk/providers/jdbc/jdbc_specs_dsn.xml.in
   trunk/providers/jdbc/jni-globals.h
   trunk/providers/jdbc/jni-wrapper.c
   trunk/providers/jdbc/jni-wrapper.h
   trunk/providers/jdbc/libgda-jdbc-4.0.pc.in
   trunk/providers/jdbc/libmain.c
   trunk/providers/jdbc/meta.java
   trunk/providers/jdbc/provider.java
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/doc/C/information_schema.svg
   trunk/doc/C/libgda-4.0-docs.sgml
   trunk/doc/C/limitations.xml
   trunk/doc/C/stmt-compound.svg
   trunk/doc/C/stmt-insert1.svg
   trunk/doc/C/stmt-insert2.svg
   trunk/doc/C/stmt-select.svg
   trunk/doc/C/stmt-unknown.svg
   trunk/doc/C/stmt-update.svg
   trunk/libgda/dir-blob-op.c
   trunk/libgda/gda-config.c
   trunk/libgda/gda-data-select.c
   trunk/libgda/gda-data-select.h
   trunk/libgda/gda-meta-struct.c
   trunk/libgda/gda-quark-list.c
   trunk/libgda/gda-value.c
   trunk/libgda/sqlite/virtual/gda-vprovider-data-model.c
   trunk/po/POTFILES.in
   trunk/po/ar.po
   trunk/po/az.po
   trunk/po/ca.po
   trunk/po/cs.po
   trunk/po/da.po
   trunk/po/de.po
   trunk/po/dz.po
   trunk/po/el.po
   trunk/po/en_CA.po
   trunk/po/en_GB.po
   trunk/po/es.po
   trunk/po/eu.po
   trunk/po/fa.po
   trunk/po/fi.po
   trunk/po/fr.po
   trunk/po/ga.po
   trunk/po/gl.po
   trunk/po/hr.po
   trunk/po/hu.po
   trunk/po/it.po
   trunk/po/ja.po
   trunk/po/ko.po
   trunk/po/lt.po
   trunk/po/mk.po
   trunk/po/ml.po
   trunk/po/ms.po
   trunk/po/nb.po
   trunk/po/ne.po
   trunk/po/nl.po
   trunk/po/oc.po
   trunk/po/pa.po
   trunk/po/pl.po
   trunk/po/pt.po
   trunk/po/pt_BR.po
   trunk/po/ru.po
   trunk/po/rw.po
   trunk/po/sk.po
   trunk/po/sl.po
   trunk/po/sq.po
   trunk/po/sr.po
   trunk/po/sr Latn po
   trunk/po/sv.po
   trunk/po/tr.po
   trunk/po/uk.po
   trunk/po/vi.po
   trunk/po/zh_CN.po
   trunk/po/zh_HK.po
   trunk/po/zh_TW.po
   trunk/providers/Makefile.am
   trunk/providers/mdb/libmain.c
   trunk/providers/postgres/gda-postgres-blob-op.c
   trunk/providers/postgres/gda-postgres-recordset.c
   trunk/tests/data-models/check_virtual.c
   trunk/tools/gda-sql.c

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Sat Nov 29 14:48:16 2008
@@ -137,7 +137,7 @@
 dnl linklibext is the shared link library extension, which varies by platform
 
 EXPORT_SYM_REGEX='-export-symbols-regex "^(gda_|fnYM49765777344607__gda).*"'
-EXPORT_PROV_SYM_REGEX='-export-symbols-regex "^(plugin_).*"'
+EXPORT_PROV_SYM_REGEX='-export-symbols-regex "^(plugin_|Java_).*"'
 AC_MSG_CHECKING([for platform])
 platform_win32=no
 platform_carbon=no
@@ -1122,6 +1122,208 @@
 	AM_CONDITIONAL(HAVE_SQLITE, test x"$have_sqlite" = "xyes")
 fi
 
+dnl Test for JAVA and JDBC
+
+## RUN_JAVA(variable for the result, parameters)
+## ----------
+## runs the java interpreter ${JAVA_PROG} with specified parameters and
+## saves the output to the supplied variable. The exit value is ignored.
+AC_DEFUN([RUN_JAVA],
+[
+  acx_java_result=
+  if test -z "${JAVA_PROG}"; then
+    echo "$as_me:$LINENO: JAVA_PROG is not set, cannot run java $2" >&AS_MESSAGE_LOG_FD
+  else
+    echo "$as_me:$LINENO: running ${JAVA_PROG} $2" >&AS_MESSAGE_LOG_FD
+    acx_java_result=`${JAVA_PROG} $2 2>&AS_MESSAGE_LOG_FD`
+    echo "$as_me:$LINENO: output: '$acx_java_result'" >&AS_MESSAGE_LOG_FD
+  fi
+  $1=$acx_java_result
+])
+
+try_java=true
+AC_ARG_WITH(java,
+[  --with-java=<directory>     use JAVA library in <directory>],[
+if test $withval = no
+then
+	try_java=false
+elif test $withval = yes
+then
+	if test -z "${JAVA_HOME}" ; then
+	  JAVA_PATH=${PATH}
+	else
+  	  JAVA_PATH=${JAVA_HOME}:${JAVA_HOME}/bin:${PATH}
+	fi
+	JAVA_PATH=${JAVA_PATH}:/usr/java/bin:/usr/jdk/bin:/usr/lib/java/bin:/usr/lib/jdk/bin:/usr/local/java/bin:/usr/local/jdk/bin:/usr/local/lib/java/bin:/usr/local/lib/jdk/bin
+else
+	JAVA_PATH=$withval
+fi
+], [
+if test -z "${JAVA_HOME}" ; then
+	  JAVA_PATH=${PATH}
+	else
+  	  JAVA_PATH=${JAVA_HOME}:${JAVA_HOME}/bin:${PATH}
+	fi
+	JAVA_PATH=${JAVA_PATH}:/usr/java/bin:/usr/jdk/bin:/usr/lib/java/bin:/usr/lib/jdk/bin:/usr/local/java/bin:/usr/local/jdk/bin:/usr/local/lib/java/bin:/usr/local/lib/jdk/bin
+])
+
+save_CFLAGS="$CFLAGS"
+save_LIBS="$LIBS"
+save_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
+have_java=no
+if test $try_java = true
+then
+	## FIXME: we may want to check for jikes, kaffe and others...
+	AC_PATH_PROGS(JAVA_PROG,java,,${JAVA_PATH})
+	AC_PATH_PROGS(JAVAC,javac,,${JAVA_PATH})
+	AC_PATH_PROGS(JAVAH,javah,,${JAVA_PATH})
+	AC_PATH_PROGS(JAR,jar,,${JAVA_PATH})
+
+	have_all_java=yes
+	if test -z "$JAVA_PROG"; then have_all_java=no; fi
+	if test -z "$JAVAC"; then have_all_java=no; fi
+	if test -z "$JAVAH"; then have_all_java=no; fi
+	if test -z "$JAR"; then have_all_java=no; fi
+	if test ${have_all_java} = no; then
+		AC_MSG_WARN([one or more Java tools are missing (JRE is not sufficient)])
+    	   	try_java=false
+	fi
+fi
+
+if test $try_java = true
+then
+	AC_MSG_CHECKING([whether Java interpreter works])
+	acx_java_works=no
+	if test -n "${JAVA_PROG}" ; then
+	  RUN_JAVA(acx_jc_result,[-classpath . getsp -test])
+	  if test "${acx_jc_result}" = "Test1234OK"; then
+	    acx_java_works=yes
+	  fi
+	  acx_jc_result=
+	fi
+
+	if test ${acx_java_works} = yes; then
+	  AC_MSG_RESULT([yes])
+
+	  AC_MSG_CHECKING([for Java environment])
+	  ## retrieve JAVA_HOME from Java itself if not set
+	  if test -z "${JAVA_HOME}" ; then
+	    RUN_JAVA(JAVA_HOME,[-classpath . getsp java.home])
+	  fi
+
+	  ## the availability of JAVA_HOME will tell us whether it's supported
+	  if test -z "${JAVA_HOME}" ; then
+	    if test x$acx_java_env_msg != xyes; then
+	      AC_MSG_RESULT([not found])
+	    fi
+	  else
+	    AC_MSG_RESULT([in ${JAVA_HOME}])
+
+	    case "${host_os}" in
+	      darwin*)
+	        JAVA_LIBS="-framework JavaVM"
+	        JAVA_LD_PATH=
+	        ;;
+	      *)
+	        RUN_JAVA(JAVA_LIBS, [-classpath . getsp -libs])
+	        JAVA_LIBS="${JAVA_LIBS} -ljvm"
+	        RUN_JAVA(JAVA_LD_PATH, [-classpath . getsp java.library.path])
+	        ;;
+	    esac
+	    ## note that we actually don't test JAVA_LIBS - we hope that the detection
+	    ## was correct. We should also test the functionality for javac.
+	  fi
+	else
+	  AC_MSG_RESULT([no])
+	  AC_MSG_WARN([Java not found. Please install JDK 1.4 or later, make sure that the binaries are on the PATH and re-try. If that doesn't work, set JAVA_HOME correspondingly.])
+	  try_java=false
+	fi
+fi
+
+JNI_H=
+AC_ARG_WITH(jni,[  --with-jni=<directory>     use JNI headers in <directory>],[JNI_H=$withval])
+
+if test $try_java = true
+then
+	if test x$JNI_H = x
+	then
+	AC_CHECK_FILE(${JAVA_HOME}/include/jni.h,
+	 [JNI_H="${JAVA_HOME}/include"],
+	 [AC_CHECK_FILE(${JAVA_HOME}/jni.h,
+	  [JNI_H="${JAVA_HOME}"],
+	  [AC_CHECK_FILE(${JAVA_HOME}/../include/jni.h,
+	   [JNI_H="${JAVA_HOME}/../include"],
+	   [AC_MSG_ERROR([jni headers not found. Please make sure you have a proper JDK installed.])
+	  ])
+	 ])
+	])
+
+	JAVA_CFLAGS="-I${JNI_H}"
+	#: ${JAVA_CFLAGS=-D_REENTRANT}
+
+	# Sun's JDK needs jni_md.h in in addition to jni.h and unfortunately it's stored somewhere else ...
+	# this should be become more general at some point - so far we're checking linux and solaris only
+	# (well, those are presumably the only platforms supported by Sun's JDK and others don't need this
+	# at least as of now - 01/2004)
+	jac_found_md=no
+	for mddir in . linux solaris ppc irix alpha aix hp-ux genunix cygwin win32 freebsd; do
+	AC_CHECK_FILE(${JNI_H}/$mddir/jni_md.h,[JAVA_CFLAGS="${JAVA_CFLAGS} -I${JNI_H}/$mddir" jac_found_md=yes])
+	if test ${jac_found_md} = yes; then break; fi
+	done
+
+	LIBS="${LIBS} ${JAVA_LIBS}"
+	CFLAGS="${CFLAGS} ${JAVA_CFLAGS} ${JAVA_CFLAGS}"
+
+	AC_MSG_CHECKING([whether JNI programs can be compiled])
+	AC_LINK_IFELSE([
+	#include <jni.h>
+	int main(void) {
+	    jobject o;
+	    return 0;
+	}
+	      ],[AC_MSG_RESULT(yes)],
+	      [AC_MSG_ERROR([Cannot compile a simple JNI program. See config.log for details.])])
+
+	LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${JAVA_LD_PATH}
+	export LD_LIBRARY_PATH
+
+	AC_MSG_CHECKING([whether JNI programs can be run])
+	AC_RUN_IFELSE([
+	#include <jni.h>
+	int main(void) {
+	    jobject o;
+	    return 0;
+	}
+	      ],[AC_MSG_RESULT(yes)],
+	      [AC_MSG_ERROR([Cannot run a simple JNI program - probably your jvm library is in non-standard location or JVM is unsupported. See config.log for details.])])
+
+	AC_MSG_CHECKING([JNI data types])
+	AC_RUN_IFELSE([AC_LANG_SOURCE([[
+	#include <jni.h>
+	int main(void) {
+	  return (sizeof(int)==sizeof(jint) && sizeof(long)==sizeof(long) && sizeof(jbyte)==sizeof(char) && sizeof(jshort)==sizeof(short) && sizeof(jfloat)==sizeof(float) && sizeof(jdouble)==sizeof(double))?0:1;
+}
+	      ]])],[AC_MSG_RESULT([ok])],[AC_MSG_ERROR([One or more JNI types differ from the corresponding native type. You may need to use non-standard compiler flags or a different compiler in order to fix this.])],[])
+	else
+		JAVA_CFLAGS="-I${JNI_H}"
+		for mddir in . linux solaris ppc irix alpha aix hp-ux genunix cygwin win32 freebsd; do
+		    if test -e ${JNI_H}/$mddir/jni_md.h
+		    then
+			JAVA_CFLAGS="${JAVA_CFLAGS} -I${JNI_H}/$mddir"
+			break
+		    fi
+		done
+	fi
+	
+	have_java=yes
+	AC_DEFINE(HAVE_JAVA, 1, [Have JAVA])
+	AC_SUBST(JAVA_LD_PATH)
+fi
+AM_CONDITIONAL(JAVA, test x$have_java = xyes)
+CFLAGS="$save_CFLAGS"
+LIBS="$save_LIBS"
+export LD_LIBRARY_PATH="$save_LD_LIBRARY_PATH"
+
 dnl **************************
 dnl Check for readline/history
 dnl **************************
@@ -1195,6 +1397,8 @@
 AC_SUBST(CAMEL_CFLAGS)
 AC_SUBST(XBASE_LIBS)
 AC_SUBST(XBASE_CFLAGS)
+AC_SUBST(JAVA_LIBS)
+AC_SUBST(JAVA_CFLAGS)
 
 dnl
 dnl Check if lib should be build with the debug mode
@@ -1254,6 +1458,8 @@
 providers/postgres/libgda-postgres-4.0.pc
 providers/sqlite/Makefile
 providers/sqlite/libgda-sqlite-4.0.pc
+providers/jdbc/Makefile
+providers/jdbc/libgda-jdbc-4.0.pc
 providers/skel-implementation/Makefile
 providers/skel-implementation/capi/Makefile
 providers/skel-implementation/capi/libgda-capi-4.0.pc
@@ -1302,6 +1508,7 @@
 dnl echo "      Sybase = `if test x$sybasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      xBase (dBase, Clipper, FoxPro) = `if test x$xbasedir != x; then echo yes; else echo no; fi`"
 dnl echo "      LDAP = `if test x$ldapdir != x; then echo yes; else echo no; fi`"
+echo "      JDBC = `if test x$have_java = xyes; then echo yes; else echo no; fi`"
 if test x"$br_cv_binreloc" != "xyes" -a x"$platform_win32" != "xyes"
 then
        echo "   Binreloc support is disabled: Libgda will not be relocatable. To enable binreloc support re-run with --enable-binreloc (see http://autopackage.org/docs/binreloc for more information)"

Modified: trunk/doc/C/information_schema.svg
==============================================================================
--- trunk/doc/C/information_schema.svg	(original)
+++ trunk/doc/C/information_schema.svg	Sat Nov 29 14:48:16 2008
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user: -->
 <!-- Title: G Pages: 1 -->
 <svg
    xmlns:dc="http://purl.org/dc/elements/1.1/";

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	Sat Nov 29 14:48:16 2008
@@ -867,7 +867,7 @@
 	    SQL identifiers (database object's names) are case insitive, but it is still possible to specify
 	    that an SQL identifier be case sensitive by putting it between double quotes. &LIBGDA; has chosen
 	    the convention that case insitive SQL identifiers should all be in lower case in the meta data's tables
-	    whereas case sensitive SQL identifiers can soncain some upper case ASCII characters.
+	    whereas case sensitive SQL identifiers can contain some upper case ASCII characters.
 	  </para>
 	  <para>
 	    This convention must be respected by database providers' implementations or the 

Modified: trunk/doc/C/limitations.xml
==============================================================================
--- trunk/doc/C/limitations.xml	(original)
+++ trunk/doc/C/limitations.xml	Sat Nov 29 14:48:16 2008
@@ -132,5 +132,37 @@
       </para>
     </sect2>
   </sect1>
+
+
+  <sect1 id="limitations_jdbc"><title>For JDBC based providers</title>
+    <para>
+      The following limitations apply to databases accessed via Libgda through a JDBC driver. When loading
+      the database providers, &LIBGDA; creates a JDBC provider per JDBC driver found (to work at all it
+      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 class="directory">$HOME/.libgda</filename> directory</para></listitem>
+	</orderedlist>
+      </para>
+    </sect2>
+
+    <sect2><title>Last inserted row's values</title>
+      <para>
+	TODO.
+      </para>
+    </sect2>
+
+    <sect2><title>Multi threaded environment</title>
+      <para>
+	No specific limitation.
+      </para>
+    </sect2>
+  </sect1>
   
 </chapter>

Modified: trunk/doc/C/stmt-compound.svg
==============================================================================
--- trunk/doc/C/stmt-compound.svg	(original)
+++ trunk/doc/C/stmt-compound.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="6.85in" height="19.34in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Modified: trunk/doc/C/stmt-insert1.svg
==============================================================================
--- trunk/doc/C/stmt-insert1.svg	(original)
+++ trunk/doc/C/stmt-insert1.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="11.51in" height="19.28in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Modified: trunk/doc/C/stmt-insert2.svg
==============================================================================
--- trunk/doc/C/stmt-insert2.svg	(original)
+++ trunk/doc/C/stmt-insert2.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="10.48in" height="12.73in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Modified: trunk/doc/C/stmt-select.svg
==============================================================================
--- trunk/doc/C/stmt-select.svg	(original)
+++ trunk/doc/C/stmt-select.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="10.76in" height="11.98in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Modified: trunk/doc/C/stmt-unknown.svg
==============================================================================
--- trunk/doc/C/stmt-unknown.svg	(original)
+++ trunk/doc/C/stmt-unknown.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="3.81in" height="9.01in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Modified: trunk/doc/C/stmt-update.svg
==============================================================================
--- trunk/doc/C/stmt-update.svg	(original)
+++ trunk/doc/C/stmt-update.svg	Sat Nov 29 14:48:16 2008
@@ -4,7 +4,7 @@
  <!ATTLIST svg xmlns:xlink CDATA #FIXED "http://www.w3.org/1999/xlink";>
 ]>
 <!-- Generated by Graphviz version 2.12 (Mon Apr 23 09:57:53 UTC 2007)
-     For user: (vmalerba) MALERBA Vivien DSNA&#45;DTI SIM ATM M204 p5713 -->
+     For user:  -->
 <!-- Title: G Pages: 1 -->
 <svg width="9.01in" height="9.73in"
  xmlns="http://www.w3.org/2000/svg"; xmlns:xlink="http://www.w3.org/1999/xlink";>

Added: trunk/getsp.class
==============================================================================
Binary file. No diff available.

Modified: trunk/libgda/dir-blob-op.c
==============================================================================
--- trunk/libgda/dir-blob-op.c	(original)
+++ trunk/libgda/dir-blob-op.c	Sat Nov 29 14:48:16 2008
@@ -194,11 +194,9 @@
 		return -1;
 	
 	/* go to offset */
-	if (offset > 0) {
-		if (fseek (file, offset, SEEK_SET) != 0) {
-			fclose (file);
-			return -1;
-		}
+	if (fseek (file, offset, SEEK_SET) != 0) {
+		fclose (file);
+		return -1;
 	}
 	
 	bin = (GdaBinary *) blob;
@@ -244,20 +242,22 @@
 
 	if (blob->op && (blob->op != op)) {
 		/* use data through blob->op */
-		#define buf_size 16384
+		//#define buf_size 262144
+                #define buf_size 16000
 		gint nread = 0;
 		GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
 		tmpblob->op = blob->op;
 
 		nbwritten = 0;
 
-		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, 0, buf_size);
 		     nread > 0;
 		     nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
 			GdaBinary *bin = (GdaBinary *) tmpblob;
 			glong tmp_written;
-			tmp_written = fwrite ((char *) (bin->data), 1, bin->binary_length, file);
-			if (tmp_written <= 0) {
+			tmp_written = fwrite ((char *) (bin->data), sizeof (guchar), bin->binary_length, file);
+			if (tmp_written < bin->binary_length) {
+				/* error writing stream */
 				gda_blob_free ((gpointer) tmpblob);
 				return -1;
 			}

Modified: trunk/libgda/gda-config.c
==============================================================================
--- trunk/libgda/gda-config.c	(original)
+++ trunk/libgda/gda-config.c	Sat Nov 29 14:48:16 2008
@@ -1075,6 +1075,7 @@
 {
 	InternalProvider *ip;
 	GdaServerProvider  *(*plugin_create_provider) (void);
+	GdaServerProvider  *(*plugin_create_sub_provider) (const gchar *provider_name);
 
 	g_return_val_if_fail (provider_name, NULL);
 	GDA_CONFIG_LOCK ();
@@ -1093,13 +1094,14 @@
 	/* need to actually create the provider object */
 	g_assert (ip->handle);
 	g_module_symbol (ip->handle, "plugin_create_provider", (gpointer) &plugin_create_provider);
-	if (!plugin_create_provider) {
-		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR,
-			     _("Can't instantiate provider '%s'"), provider_name);
-		GDA_CONFIG_UNLOCK ();
-		return NULL;
+	if (plugin_create_provider)
+		ip->instance = plugin_create_provider ();
+	else {
+		g_module_symbol (ip->handle, "plugin_create_sub_provider", (gpointer) &plugin_create_sub_provider);
+		if (plugin_create_sub_provider)
+			ip->instance = plugin_create_sub_provider (provider_name);
 	}
-	ip->instance = plugin_create_provider ();
+	
 	if (!ip->instance) {
 		g_set_error (error, GDA_CONFIG_ERROR, GDA_CONFIG_PROVIDER_CREATION_ERROR,
 			     _("Can't instantiate provider '%s'"), provider_name);
@@ -1164,7 +1166,10 @@
 		gda_data_model_set_value_at (model, 0, row, value, NULL);
 		gda_value_free (value);
 
-		value = gda_value_new_from_string (info->description, G_TYPE_STRING);
+		if (info->description) 
+			value = gda_value_new_from_string (info->description, G_TYPE_STRING);
+		else
+			value = gda_value_new_null ();
 		gda_data_model_set_value_at (model, 1, row, value, NULL);
 		gda_value_free (value);
 
@@ -1235,6 +1240,78 @@
 	}
 }
 
+static InternalProvider *
+create_internal_provider (GModule *handle, const gchar *path,
+			  const gchar *prov_name, const gchar *prov_descr,
+			  const gchar *dsn_spec, const gchar *auth_spec)
+{
+	InternalProvider *ip;
+	GdaProviderInfo *info;
+
+	ip = g_new0 (InternalProvider, 1);
+	ip->handle = handle;
+	info = (GdaProviderInfo*) ip;
+	info->location = g_strdup (path);
+
+	info->id = g_strdup (prov_name);
+	info->description = g_strdup (prov_descr);
+
+	/* DSN parameters */
+	info->dsn_params = NULL;
+	if (dsn_spec) {
+		GError *error = NULL;
+		info->dsn_params = gda_set_new_from_spec_string (dsn_spec, &error);
+		if (!info->dsn_params) {
+			g_warning ("Invalid format for provider '%s' DSN spec : %s",
+				   info->id,
+				   error ? error->message : "Unknown error");
+			if (error)
+				g_error_free (error);
+		}
+		if (!info->dsn_params) {
+			/* there may be traces of the provider installed but some parts are missing,
+			   forget about that provider... */
+			internal_provider_free (ip);
+			return NULL;
+		}
+	}
+	else
+		g_warning ("Provider '%s' does not provide a DSN spec", info->id);
+
+	/* Authentication parameters */
+	info->auth_params = NULL;
+	if (auth_spec) {
+		GError *error = NULL;
+
+		info->auth_params = gda_set_new_from_spec_string (auth_spec, &error);
+		if (!info->auth_params) {
+			g_warning ("Invalid format for provider '%s' AUTH spec : %s",
+				   info->id,
+				   error ? error->message : "Unknown error");
+			if (error)
+				g_error_free (error);
+		}
+
+		if (!info->auth_params) {
+			/* there may be traces of the provider installed but some parts are missing,
+			   forget about that provider... */
+			internal_provider_free (ip);
+			return NULL;
+		}
+	}
+	else {
+		/* default to username/password */
+		GdaHolder *h;
+		info->auth_params = gda_set_new_inline (2, "USERNAME", G_TYPE_STRING, NULL,
+							"PASSWORD", G_TYPE_STRING, NULL);
+		h = gda_set_get_holder (info->auth_params, "USERNAME");
+		g_object_set (G_OBJECT (h), "name", _("Username"), NULL);
+		h = gda_set_get_holder (info->auth_params, "PASSWORD");
+		g_object_set (G_OBJECT (h), "name", _("Password"), NULL);
+	}
+	return ip;
+}
+
 static void 
 load_providers_from_dir (const gchar *dirname, gboolean recurs)
 {
@@ -1252,17 +1329,25 @@
 		g_error_free (err);
 		return;
 	}
-
+	
 	while ((name = g_dir_read_name (dir))) {
-		InternalProvider *ip;
-		GdaProviderInfo *info;
 		GModule *handle;
 		gchar *path;
+
+		/* initialization method */
 		void (*plugin_init) (const gchar *);
+
+		/* methods for shared libraries which provide only one type of provider */
 		const gchar * (* plugin_get_name) (void);
 		const gchar * (* plugin_get_description) (void);
 		gchar * (* plugin_get_dsn_spec) (void);
 		gchar * (* plugin_get_auth_spec) (void);
+		
+		/* methods for shared libraries which provide several types of providers (ODBC, JDBC, ...) */
+		const gchar ** (* plugin_get_sub_names) (void);
+		const gchar * (* plugin_get_sub_description) (const gchar *name);
+		gchar * (* plugin_get_sub_dsn_spec) (const gchar *name);
+		gchar * (* plugin_get_sub_auth_spec) (const gchar *name);
 
 		if (recurs) {
 			gchar *cname;
@@ -1290,105 +1375,72 @@
 			continue;
 		}
 
-		if (g_module_symbol (handle, "plugin_init", (gpointer *) &plugin_init))
+		if (g_module_symbol (handle, "plugin_init", (gpointer *) &plugin_init)) {
 			plugin_init (dirname);
+		}
 		else {
 			g_module_close (handle);
 			continue;
 		}
-		g_module_symbol (handle, "plugin_get_name", (gpointer *) &plugin_get_name);
-		g_module_symbol (handle, "plugin_get_description", (gpointer *) &plugin_get_description);
-		g_module_symbol (handle, "plugin_get_dsn_spec", (gpointer *) &plugin_get_dsn_spec);
-		g_module_symbol (handle, "plugin_get_auth_spec", (gpointer *) &plugin_get_auth_spec);
-
-		ip = g_new0 (InternalProvider, 1);
-		ip->handle = handle;
-		info = (GdaProviderInfo*) ip;
-		info->location = path;
-
-		if (plugin_get_name != NULL)
-			info->id = g_strdup (plugin_get_name ());
-		else
-			info->id = g_strdup (name);
-
-		if (plugin_get_description != NULL)
-			info->description = g_strdup (plugin_get_description ());
-		else
-			info->description = NULL;
-
-		/* DSN parameters */
-		info->dsn_params = NULL;
-		if (plugin_get_dsn_spec) {
-			GError *error = NULL;
-			gchar *dsn_spec;
-
-			dsn_spec = plugin_get_dsn_spec ();
-			if (dsn_spec) {
-				info->dsn_params = gda_set_new_from_spec_string (dsn_spec, &error);
-				if (!info->dsn_params) {
-					g_warning ("Invalid format for provider '%s' DSN spec : %s",
-						   info->id,
-						   error ? error->message : "Unknown error");
-					if (error)
-						g_error_free (error);
-				}
-				g_free (dsn_spec);
-			}
-			if (!info->dsn_params) {
-				/* there may be traces of the provider installed but some parts are missing,
-				   forget about that provider... */
-				internal_provider_free (ip);
-				ip = NULL;
-				g_module_close (handle);
-				continue;
-			}
-		}
-		else
-			g_warning ("Provider '%s' does not provide a DSN spec", info->id);
-
-		/* Authentication parameters */
-		info->auth_params = NULL;
-		if (plugin_get_auth_spec) {
-			GError *error = NULL;
-			gchar *auth_spec;
-
-			auth_spec = plugin_get_auth_spec ();
-			if (auth_spec) {
-				info->auth_params = gda_set_new_from_spec_string (auth_spec, &error);
-				if (!info->auth_params) {
-					g_warning ("Invalid format for provider '%s' AUTH spec : %s",
-						   info->id,
-						   error ? error->message : "Unknown error");
-					if (error)
-						g_error_free (error);
+		g_module_symbol (handle, "plugin_get_name",
+				 (gpointer *) &plugin_get_name);
+		g_module_symbol (handle, "plugin_get_description",
+				 (gpointer *) &plugin_get_description);
+		g_module_symbol (handle, "plugin_get_dsn_spec",
+				 (gpointer *) &plugin_get_dsn_spec);
+		g_module_symbol (handle, "plugin_get_auth_spec",
+				 (gpointer *) &plugin_get_auth_spec);
+		g_module_symbol (handle, "plugin_get_sub_names",
+				 (gpointer *) &plugin_get_sub_names);
+		g_module_symbol (handle, "plugin_get_sub_description",
+				 (gpointer *) &plugin_get_sub_description);
+		g_module_symbol (handle, "plugin_get_sub_dsn_spec",
+				 (gpointer *) &plugin_get_sub_dsn_spec);
+		g_module_symbol (handle, "plugin_get_sub_auth_spec",
+				 (gpointer *) &plugin_get_sub_auth_spec);
+
+		if (plugin_get_sub_names) {
+			const gchar **subnames = plugin_get_sub_names ();
+			const gchar **ptr;
+			gboolean module_used = FALSE;
+			for (ptr = subnames; ptr && *ptr; ptr++) {
+				InternalProvider *ip;
+								
+				ip = create_internal_provider (handle, path, *ptr,
+							       plugin_get_sub_description ? 
+							       plugin_get_sub_description (*ptr) : NULL,
+							       plugin_get_sub_dsn_spec ? 
+							       plugin_get_sub_dsn_spec (*ptr) : NULL,
+							       plugin_get_sub_auth_spec ?
+							       plugin_get_sub_auth_spec (*ptr) : NULL);
+				if (ip) {
+					unique_instance->priv->prov_list =
+						g_slist_prepend (unique_instance->priv->prov_list, ip);
+					module_used = TRUE;
+#ifdef GDA_DEBUG_NO
+					g_print ("Loaded '%s' sub-provider\n", ((GdaProviderInfo*) ip)->id);
+#endif
 				}
-				g_free (auth_spec);
 			}
-			if (!info->auth_params) {
-				/* there may be traces of the provider installed but some parts are missing,
-				   forget about that provider... */
-				internal_provider_free (ip);
-				ip = NULL;
+			if (!module_used)
 				g_module_close (handle);
-				continue;
-			}
 		}
 		else {
-			/* default to username/password */
-			GdaHolder *h;
-			info->auth_params = gda_set_new_inline (2, "USERNAME", G_TYPE_STRING, NULL,
-								"PASSWORD", G_TYPE_STRING, NULL);
-			h = gda_set_get_holder (info->auth_params, "USERNAME");
-			g_object_set (G_OBJECT (h), "name", _("Username"), NULL);
-			h = gda_set_get_holder (info->auth_params, "PASSWORD");
-			g_object_set (G_OBJECT (h), "name", _("Password"), NULL);
-		}
-
-		if (ip) {
-			unique_instance->priv->prov_list = g_slist_prepend (unique_instance->priv->prov_list, ip);
+			InternalProvider *ip;
+			ip = create_internal_provider (handle, path,
+						       plugin_get_name ? plugin_get_name () : name,
+						       plugin_get_description ? plugin_get_description () : NULL,
+						       plugin_get_dsn_spec ? plugin_get_dsn_spec () : NULL,
+						       plugin_get_auth_spec ? plugin_get_auth_spec () : NULL);
+			if (ip) {
+				unique_instance->priv->prov_list =
+					g_slist_prepend (unique_instance->priv->prov_list, ip);
 #ifdef GDA_DEBUG_NO
-			g_print ("Loaded '%s' provider\n", info->id);
+				g_print ("Loaded '%s' provider\n", ((GdaProviderInfo*) ip)->id);
 #endif
+			}
+			else
+				g_module_close (handle);
 		}
 	}
 
@@ -1396,6 +1448,8 @@
 	g_dir_close (dir);
 }
 
+
+
 /* sorting function */
 static gint
 data_source_info_compare (GdaDsnInfo *infoa, GdaDsnInfo *infob)

Modified: trunk/libgda/gda-data-select.c
==============================================================================
--- trunk/libgda/gda-data-select.c	(original)
+++ trunk/libgda/gda-data-select.c	Sat Nov 29 14:48:16 2008
@@ -787,7 +787,8 @@
 	if (g_hash_table_lookup (model->priv->index, GINT_TO_POINTER (rownum + 1))) 
 		g_error ("INTERNAL error: row %d already exists, aborting", rownum);
 
-	g_hash_table_insert (model->priv->index, GINT_TO_POINTER (rownum + 1), GINT_TO_POINTER (model->priv->rows->len + 1));
+	g_hash_table_insert (model->priv->index, GINT_TO_POINTER (rownum + 1),
+			     GINT_TO_POINTER (model->priv->rows->len + 1));
 	g_array_append_val (model->priv->rows, row);
 	model->nb_stored_rows = model->priv->rows->len;
 }

Modified: trunk/libgda/gda-data-select.h
==============================================================================
--- trunk/libgda/gda-data-select.h	(original)
+++ trunk/libgda/gda-data-select.h	Sat Nov 29 14:48:16 2008
@@ -100,6 +100,7 @@
 gboolean       gda_data_select_compute_modification_statements (GdaDataSelect *model, GError **error);
 
 gboolean       gda_data_select_compute_columns_attributes      (GdaDataSelect *model, GError **error);
+GdaConnection *gda_data_select_get_connection                  (GdaDataSelect *model);
 
 G_END_DECLS
 

Modified: trunk/libgda/gda-meta-struct.c
==============================================================================
--- trunk/libgda/gda-meta-struct.c	(original)
+++ trunk/libgda/gda-meta-struct.c	Sat Nov 29 14:48:16 2008
@@ -611,7 +611,7 @@
 	}
 	case GDA_META_DB_TABLE: {
 		/* columns */
-		gchar *sql = "SELECT c.column_name, c.data_type, c.gtype, c.is_nullable, t.table_short_name, t.table_full_name, c.column_default, t.table_owner, c.array_spec, c.extra FROM _columns as c NATURAL JOIN _tables as t WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY ordinal_position";
+		gchar *sql = "SELECT c.column_name, c.data_type, c.gtype, c.is_nullable, t.table_short_name, t.table_full_name, c.column_default, t.table_owner, c.array_spec, c.extra, c.column_comments FROM _columns as c NATURAL JOIN _tables as t WHERE table_catalog = ##tc::string AND table_schema = ##ts::string AND table_name = ##tname::string ORDER BY ordinal_position";
 		GdaMetaTable *mt;
 		GdaDataModel *model;
 		gint i, nrows;
@@ -625,7 +625,7 @@
 		if (nrows < 1) {
 			g_object_unref (model);
 			g_set_error (error, GDA_META_STRUCT_ERROR, GDA_META_STRUCT_UNKNOWN_OBJECT_ERROR,
-				     _("Table %s.%s.%s not found in meta store object"), 
+				     _("Table %s.%s.%s not found (or missing columns information)"), 
 				     g_value_get_string (icatalog), g_value_get_string (ischema), 
 				     g_value_get_string (iname));
 			goto onerror;
@@ -707,6 +707,13 @@
 				gda_value_free (true_value);
 				g_strfreev (array);
 			}
+
+			cvalue = gda_data_model_get_value_at (model, 10, i, error);
+			if (!cvalue) goto onerror;
+			if (!gda_value_is_null (cvalue))
+				gda_attributes_manager_set (att_mgr, tcol, GDA_ATTRIBUTE_DESCRIPTION, 
+							    cvalue);
+
 		}
 		mt->columns = g_slist_reverse (mt->columns);
 		g_object_unref (model);
@@ -1963,6 +1970,7 @@
 	}
 
  next:
+	model = NULL;
 	{
 		/* treat the case where name is in fact <schema>.<name> */
 		gchar *obj_schema;

Modified: trunk/libgda/gda-quark-list.c
==============================================================================
--- trunk/libgda/gda-quark-list.c	(original)
+++ trunk/libgda/gda-quark-list.c	Sat Nov 29 14:48:16 2008
@@ -48,13 +48,6 @@
  */
 
 static void
-free_hash_pair (gpointer key, gpointer value, gpointer user_data)
-{
-	g_free (key);
-	g_free (value);
-}
-
-static void
 copy_hash_pair (gpointer key, gpointer value, gpointer user_data)
 {
 	g_hash_table_insert ((GHashTable *) user_data,
@@ -78,7 +71,7 @@
 	GdaQuarkList *qlist;
 
 	qlist = g_new0 (GdaQuarkList, 1);
-	qlist->hash_table = g_hash_table_new (g_str_hash, g_str_equal);
+	qlist->hash_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
 	return qlist;
 }
@@ -121,7 +114,7 @@
 {
 	g_return_if_fail (qlist != NULL);
 	
-	g_hash_table_foreach_remove (qlist->hash_table, (GHRFunc) free_hash_pair, NULL);
+	g_hash_table_remove_all (qlist->hash_table);
 }
 
 /**
@@ -135,7 +128,6 @@
 {
 	g_return_if_fail (qlist != NULL);
 
-	gda_quark_list_clear (qlist);
 	g_hash_table_destroy (qlist->hash_table);
 
 	g_free (qlist);
@@ -206,9 +198,12 @@
 				gchar *value = pair[1];
 				gda_rfc1738_decode (name);
 				gda_rfc1738_decode (value);
-				g_hash_table_insert (qlist->hash_table, (gpointer) name, (gpointer) value);
+				g_hash_table_insert (qlist->hash_table, 
+						     (gpointer) name, (gpointer) value);
 				g_free (pair);
 			}
+			else
+				g_strfreev (pair);
 			n++;
 		}
 		g_strfreev (arr);
@@ -253,12 +248,7 @@
 	g_return_if_fail (qlist != NULL);
 	g_return_if_fail (name != NULL);
 
-	if (g_hash_table_lookup_extended (qlist->hash_table, name,
-					  &orig_key, &orig_value)) {
-		g_hash_table_remove (qlist->hash_table, name);
-		g_free (orig_key);
-		g_free (orig_value);
-	}
+	g_hash_table_remove (qlist->hash_table, name);
 }
 
 /**

Modified: trunk/libgda/gda-value.c
==============================================================================
--- trunk/libgda/gda-value.c	(original)
+++ trunk/libgda/gda-value.c	Sat Nov 29 14:48:16 2008
@@ -2658,5 +2658,8 @@
 gboolean
 gda_string_to_blob (const gchar *str, GdaBlob *blob)
 {
-	return gda_string_to_binary (str, (GdaBinary*) blob);
+	gboolean retval;
+	retval = gda_string_to_binary (str, (GdaBinary*) blob);
+	blob->op = NULL;
+	return retval;
 }

Modified: trunk/libgda/sqlite/virtual/gda-vprovider-data-model.c
==============================================================================
--- trunk/libgda/sqlite/virtual/gda-vprovider-data-model.c	(original)
+++ trunk/libgda/sqlite/virtual/gda-vprovider-data-model.c	Sat Nov 29 14:48:16 2008
@@ -270,7 +270,7 @@
 		gda_quark_list_add_from_string (m_params, "_IS_VIRTUAL=TRUE;LOAD_GDA_FUNCTIONS=TRUE", TRUE);
 	}
 	else
-		params = gda_quark_list_new_from_string ("_IS_VIRTUAL=TRUE;LOAD_GDA_FUNCTIONS=TRUE");
+		m_params = gda_quark_list_new_from_string ("_IS_VIRTUAL=TRUE;LOAD_GDA_FUNCTIONS=TRUE");
 
 	if (! GDA_SERVER_PROVIDER_CLASS (parent_class)->open_connection (GDA_SERVER_PROVIDER (provider), cnc, m_params,
 									 auth, NULL, NULL, NULL)) {
@@ -376,6 +376,7 @@
 			/* no random access => use a wrapper */
 			GdaDataModel *wrapper;
 			wrapper = gda_data_access_wrapper_new (td->spec->data_model);
+			g_assert (wrapper);
 		}
 
 		ncols = gda_data_model_get_n_columns (wrapper);

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Sat Nov 29 14:48:16 2008
@@ -63,6 +63,15 @@
 providers/bdb/bdb_specs_dsn.xml.in
 providers/bdb/gda-bdb-provider.c
 providers/bdb/libmain.c
+providers/jdbc/GdaInputStream.c
+providers/jdbc/GdaJValue.c
+providers/jdbc/gda-jdbc-ddl.c
+providers/jdbc/gda-jdbc-provider.c
+providers/jdbc/gda-jdbc-recordset.c
+providers/jdbc/gda-jdbc-util.c
+providers/jdbc/jdbc_specs_create_table.xml.in
+providers/jdbc/jdbc_specs_dsn.xml.in
+providers/jdbc/libmain.c
 providers/mdb/gda-mdb-provider.c
 providers/mdb/libmain.c
 providers/mdb/mdb_specs_dsn.xml.in

Modified: trunk/providers/Makefile.am
==============================================================================
--- trunk/providers/Makefile.am	(original)
+++ trunk/providers/Makefile.am	Sat Nov 29 14:48:16 2008
@@ -50,13 +50,18 @@
 GDA_LDAP_SERVER=ldap
 endif
 
+if JAVA
+GDA_JAVA_SERVER=jdbc
+endif
+
 SUBDIRS = \
 	sqlite \
 	skel-implementation \
 	$(GDA_BDB_SERVER) \
 	$(GDA_MDB_SERVER) \
 	$(GDA_POSTGRES_SERVER) \
-	$(GDA_MYSQL_SERVER)
+	$(GDA_MYSQL_SERVER) \
+	$(GDA_JAVA_SERVER)
 #	$(GDA_FREETDS_SERVER) \
 #	$(GDA_IBMDB2_SERVER) \
 #	$(GDA_FIREBIRD_SERVER) \

Added: trunk/providers/jdbc/GdaInputStream.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaInputStream.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,161 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaInputStream.h"
+#include "jni-wrapper.h"
+#include <libgda/libgda.h>
+#include <libgda/gda-blob-op.h>
+#include <glib/gi18n-lib.h>
+
+jclass GdaInputStream__class = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaInputStream_initIDs (JNIEnv *env, jclass klass)
+{
+	GdaInputStream__class = (*env)->NewGlobalRef (env, klass);
+}
+
+JNIEXPORT jintArray
+JNICALL Java_GdaInputStream_readData (JNIEnv *jenv, jobject obj,
+				      jlong gda_blob_pointer, jlong offset, jlong size)
+{
+	GdaBlob *blob = (GdaBlob*) gda_blob_pointer;
+	jintArray jdata;
+	if (!blob) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	guchar *raw_data;
+	jint *data;
+	GdaBlob *nblob = NULL;
+	gint real_size;
+	if (blob->op) {
+		nblob = g_new0 (GdaBlob, 1);
+		gda_blob_set_op (nblob, blob->op);
+		real_size =  gda_blob_op_read (nblob->op, nblob, offset, size);
+		if (real_size < 0) {
+			/* throw an exception */
+			jclass cls;
+			cls = (*jenv)->FindClass (jenv, "java/sql/SQLException");
+			if (!cls) {
+				/* Unable to find the exception class */
+				return NULL;
+			}
+			(*jenv)->ThrowNew (jenv, cls, _("Can't read BLOB"));
+			return NULL;
+		}
+		raw_data = ((GdaBinary*) nblob)->data;
+	}
+	else {
+		GdaBinary *bin = (GdaBinary *) blob;
+		if (offset + size > bin->binary_length)
+			real_size = bin->binary_length - offset;
+		else
+			real_size = size;
+		raw_data = bin->data + offset;
+	}
+
+	/* convert bin->data to a jintArray */
+	int i;
+	data = g_new (jint, real_size);
+	for (i = 0; i < real_size; i++) 
+		data[i] = (jint) (raw_data[i]);
+
+	jdata = (*jenv)->NewIntArray (jenv, real_size);
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		jdata = NULL;
+		goto out;
+	}
+	
+	(*jenv)->SetIntArrayRegion (jenv, jdata, 0, real_size, data);
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		jdata = NULL;
+		(*jenv)->DeleteLocalRef (jenv, jdata);
+		goto out;
+	}
+
+ out:
+	g_free (data);
+	if (nblob)
+		gda_blob_free ((gpointer) nblob);
+
+	return jdata;
+}
+
+JNIEXPORT jbyteArray JNICALL
+Java_GdaInputStream_readByteData (JNIEnv *jenv, jobject obj,
+				      jlong gda_blob_pointer, jlong offset, jlong size)
+{
+	GdaBlob *blob = (GdaBlob*) gda_blob_pointer;
+	jbyteArray jdata;
+	if (!blob) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	guchar *raw_data;
+	jint *data;
+	GdaBlob *nblob = NULL;
+	gint real_size;
+	if (blob->op) {
+		nblob = g_new0 (GdaBlob, 1);
+		gda_blob_set_op (nblob, blob->op);
+		real_size =  gda_blob_op_read (nblob->op, nblob, offset, size);
+		if (real_size < 0) {
+			/* throw an exception */
+			jclass cls;
+			cls = (*jenv)->FindClass (jenv, "java/sql/SQLException");
+			if (!cls) {
+				/* Unable to find the exception class */
+				return NULL;
+			}
+			(*jenv)->ThrowNew (jenv, cls, _("Can't read BLOB"));
+			return NULL;
+		}
+		raw_data = ((GdaBinary*) nblob)->data;
+	}
+	else {
+		GdaBinary *bin = (GdaBinary *) blob;
+		if (offset + size > bin->binary_length)
+			real_size = bin->binary_length - offset;
+		else
+			real_size = size;
+		raw_data = bin->data + offset;
+	}
+
+	/* convert bin->data to a jintArray */
+	jdata = (*jenv)->NewByteArray (jenv, real_size);
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		jdata = NULL;
+		goto out;
+	}
+	
+	(*jenv)->SetByteArrayRegion (jenv, jdata, 0, real_size, raw_data);
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		jdata = NULL;
+		(*jenv)->DeleteLocalRef (jenv, jdata);
+		goto out;
+	}
+
+ out:
+	if (nblob)
+		gda_blob_free ((gpointer) nblob);
+
+	return jdata;
+}

Added: trunk/providers/jdbc/GdaJBlobOp.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJBlobOp.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,37 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJBlobOp.h"
+#include "jni-wrapper.h"
+
+JniWrapperMethod *GdaJBlobOp__read = NULL;
+JniWrapperMethod *GdaJBlobOp__write = NULL;
+JniWrapperMethod *GdaJBlobOp__length = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJBlobOp_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"read", "(JI)[B", FALSE, &GdaJBlobOp__read},
+		{"write", "(J[B)I", FALSE, &GdaJBlobOp__write},
+		{"length", "()J", FALSE, &GdaJBlobOp__length},
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJBlobOp", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJColumnInfos.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJColumnInfos.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,37 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJColumnInfos.h"
+#include "jni-wrapper.h"
+
+JniWrapperField *GdaJColumnInfos__col_name = NULL;
+JniWrapperField *GdaJColumnInfos__col_descr = NULL;
+JniWrapperField *GdaJColumnInfos__col_type = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJColumnInfos_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperField **symbol;
+	} FieldSignature;
+
+	FieldSignature fields[] = {
+		{"col_name", "Ljava/lang/String;", FALSE, &GdaJColumnInfos__col_name},
+		{"col_descr", "Ljava/lang/String;", FALSE, &GdaJColumnInfos__col_descr},
+		{"col_type", "I", FALSE, &GdaJColumnInfos__col_type},
+	};
+
+	for (i = 0; i < sizeof (fields) / sizeof (FieldSignature); i++) {
+		FieldSignature *m = & (fields [i]);
+		*(m->symbol) = jni_wrapper_field_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find field: %s.%s", "GdaJColumnInfos", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJConnection.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJConnection.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,56 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJConnection.h"
+#include "jni-wrapper.h"
+
+JniWrapperMethod *GdaJConnection__close = NULL;
+JniWrapperMethod *GdaJConnection__getServerVersion = NULL;
+JniWrapperMethod *GdaJConnection__prepareStatement = NULL;
+JniWrapperMethod *GdaJConnection__executeDirectSQL = NULL;
+
+JniWrapperMethod *GdaJConnection__begin = NULL;
+JniWrapperMethod *GdaJConnection__rollback = NULL;
+JniWrapperMethod *GdaJConnection__commit = NULL;
+JniWrapperMethod *GdaJConnection__addSavepoint = NULL;
+JniWrapperMethod *GdaJConnection__rollbackSavepoint = NULL;
+JniWrapperMethod *GdaJConnection__releaseSavepoint = NULL;
+
+JniWrapperMethod *GdaJConnection__getJMeta = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJConnection_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"close", "()V", FALSE, &GdaJConnection__close},
+		{"getServerVersion", "()Ljava/lang/String;", FALSE, &GdaJConnection__getServerVersion},
+		{"prepareStatement", "(Ljava/lang/String;)LGdaJPStmt;", FALSE, &GdaJConnection__prepareStatement},
+		{"executeDirectSQL", "(Ljava/lang/String;)LGdaJResultSet;", FALSE, &GdaJConnection__executeDirectSQL},
+		{"begin", "()V", FALSE, &GdaJConnection__begin},
+		{"rollback", "()V", FALSE, &GdaJConnection__rollback},
+		{"commit", "()V", FALSE, &GdaJConnection__commit},
+		{"addSavepoint", "(Ljava/lang/String;)V", FALSE, &GdaJConnection__addSavepoint},
+		{"rollbackSavepoint", "(Ljava/lang/String;)V", FALSE, &GdaJConnection__rollbackSavepoint},
+		{"releaseSavepoint", "(Ljava/lang/String;)V", FALSE, &GdaJConnection__releaseSavepoint},
+
+		{"getJMeta", "()LGdaJMeta;", FALSE, &GdaJConnection__getJMeta}
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJConnection", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJMeta.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJMeta.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,39 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJMeta.h"
+#include "jni-wrapper.h"
+
+JniWrapperMethod *GdaJMeta__getCatalog = NULL;
+JniWrapperMethod *GdaJMeta__getSchemas = NULL;
+JniWrapperMethod *GdaJMeta__getTables = NULL;
+JniWrapperMethod *GdaJMeta__getViews = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJMeta_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"getCatalog", "()Ljava/lang/String;", FALSE, &GdaJMeta__getCatalog},
+		{"getSchemas", "(Ljava/lang/String;Ljava/lang/String;)LGdaJResultSet;", FALSE, &GdaJMeta__getSchemas},
+		{"getTables", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)LGdaJResultSet;", FALSE, &GdaJMeta__getTables},
+		{"getViews", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)LGdaJResultSet;", FALSE, &GdaJMeta__getViews},
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJMeta", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJPStmt.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJPStmt.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,43 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJPStmt.h"
+#include "jni-wrapper.h"
+
+JniWrapperMethod *GdaJPStmt__clearParameters = NULL;
+JniWrapperMethod *GdaJPStmt__execute = NULL;
+JniWrapperMethod *GdaJPStmt__getResultSet = NULL;
+JniWrapperMethod *GdaJPStmt__getImpactedRows = NULL;
+JniWrapperMethod *GdaJPStmt__declareParamTypes = NULL;
+JniWrapperMethod *GdaJPStmt__setParameterValue = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJPStmt_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"clearParameters", "()V", FALSE, &GdaJPStmt__clearParameters},
+		{"execute", "()Z", FALSE, &GdaJPStmt__execute},
+		{"getResultSet", "()LGdaJResultSet;", FALSE, &GdaJPStmt__getResultSet},
+		{"getImpactedRows", "()I", FALSE, &GdaJPStmt__getImpactedRows},
+		{"declareParamTypes", "(J[B)V", FALSE, &GdaJPStmt__declareParamTypes},
+		{"setParameterValue", "(IJ)V", FALSE, &GdaJPStmt__setParameterValue}
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJPStmt", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJProvider.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJProvider.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,39 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJProvider.h"
+#include "jni-wrapper.h"
+
+jclass GdaJProvider_class = NULL;
+JniWrapperMethod *GdaJProvider__getDrivers = NULL;
+JniWrapperMethod *GdaJProvider__openConnection = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJProvider_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"getDrivers", "()Ljava/lang/String;", TRUE, &GdaJProvider__getDrivers},
+		{"openConnection", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)LGdaJConnection;", FALSE, &GdaJProvider__openConnection}
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJProvider", m->name);
+	}
+
+	GdaJProvider_class = (*env)->NewGlobalRef (env, klass);
+	g_assert (GdaJProvider_class);
+}

Added: trunk/providers/jdbc/GdaJResultSet.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJResultSet.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,37 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJResultSet.h"
+#include "jni-wrapper.h"
+
+JniWrapperMethod *GdaJResultSet__getInfos = NULL;
+JniWrapperMethod *GdaJResultSet__declareColumnTypes = NULL;
+JniWrapperMethod *GdaJResultSet__fillNextRow = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJResultSet_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"getInfos", "()LGdaJResultSetInfos;", FALSE, &GdaJResultSet__getInfos},
+		{"declareColumnTypes" , "(J[B)V", FALSE, &GdaJResultSet__declareColumnTypes},
+		{"fillNextRow", "(J)Z", FALSE, &GdaJResultSet__fillNextRow},
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJResultSet", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJResultSetInfos.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJResultSetInfos.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,54 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJResultSetInfos.h"
+#include "jni-wrapper.h"
+
+JniWrapperField *GdaJResultSetInfos__ncols = NULL;
+JniWrapperMethod *GdaJResultSetInfos__describeColumn = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJResultSetInfos_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperField **symbol;
+	} FieldSignature;
+
+	FieldSignature fields[] = {
+		{"ncols", "I", FALSE, &GdaJResultSetInfos__ncols}
+	};
+
+	/* fields */
+	for (i = 0; i < sizeof (fields) / sizeof (FieldSignature); i++) {
+		FieldSignature *m = & (fields [i]);
+		*(m->symbol) = jni_wrapper_field_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find field: %s.%s", "GdaJResultSetInfos", m->name);
+	}
+
+	/* methods */
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"describeColumn", "(I)LGdaJColumnInfos;", FALSE, &GdaJResultSetInfos__describeColumn},
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJResultSetInfos", m->name);
+	}
+}

Added: trunk/providers/jdbc/GdaJValue.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/GdaJValue.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,495 @@
+/*
+ * This file implements the JNI calls from the JAVA VM to the native
+ * C code
+ * and also stores Class and Method IDs
+ */
+
+#include "GdaJBlobOp.h"
+#include "jni-wrapper.h"
+#include "jni-globals.h"
+#include <libgda/libgda.h>
+#include <glib/gi18n-lib.h>
+#include "gda-jdbc-blob-op.h"
+
+
+static JniWrapperMethod *GdaJValue__createDate = NULL;
+static JniWrapperMethod *GdaJValue__createTime = NULL;
+static JniWrapperMethod *GdaJValue__createTimestamp = NULL;
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_initIDs (JNIEnv *env, jclass klass)
+{
+	gint i;
+	typedef struct {
+		const gchar       *name;
+		const gchar       *sig;
+		gboolean           is_static;
+		JniWrapperMethod **symbol;
+	} MethodSignature;
+
+	MethodSignature methods[] = {
+		{"createDate", "(III)Ljava/sql/Date;", TRUE, &GdaJValue__createDate},
+		{"createTime", "(III)Ljava/sql/Time;", TRUE, &GdaJValue__createTime},
+		{"createTimestamp", "(IIIIII)Ljava/sql/Timestamp;", TRUE, &GdaJValue__createTimestamp},
+	};
+
+	for (i = 0; i < sizeof (methods) / sizeof (MethodSignature); i++) {
+		MethodSignature *m = & (methods [i]);
+		*(m->symbol) = jni_wrapper_method_create (env, klass, m->name, m->sig, m->is_static, NULL);
+		if (!*(m->symbol))
+			g_error ("Can't find method: %s.%s", "GdaJValue", m->name);
+	}
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCString (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jstring str)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	gchar *tmp;
+	gint len;
+
+	len = (*jenv)->GetStringUTFLength (jenv, str);
+	tmp = g_new (gchar, len + 1);
+	(*jenv)->GetStringUTFRegion (jenv, str, 0, len, tmp);
+	g_value_init (value, G_TYPE_STRING);
+	g_value_take_string (value, tmp);
+}
+
+JNIEXPORT jstring
+JNICALL Java_GdaJValue_getCString (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const gchar *str;
+	
+	str = g_value_get_string ((GValue *) c_pointer);
+	return (*jenv)->NewStringUTF (jenv, str);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCInt (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jint i)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_INT);
+	g_value_set_int (value, i);
+}
+
+JNIEXPORT jint
+JNICALL Java_GdaJValue_getCInt (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jint) g_value_get_int ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCChar (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jbyte b)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_CHAR);
+	g_value_set_char (value, b);
+}
+
+JNIEXPORT jbyte
+JNICALL Java_GdaJValue_getCChar (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jbyte) g_value_get_char ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCDouble (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jdouble d)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_DOUBLE);
+	g_value_set_double (value, d);
+}
+
+JNIEXPORT jdouble
+JNICALL Java_GdaJValue_getCDouble (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jdouble) g_value_get_double ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCFloat (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jfloat f)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_FLOAT);
+	g_value_set_float (value, f);
+}
+
+JNIEXPORT jfloat
+JNICALL Java_GdaJValue_getCFloat (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jfloat) g_value_get_float ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCBoolean (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jboolean b)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_BOOLEAN);
+	g_value_set_boolean (value, b);
+}
+
+JNIEXPORT jboolean
+JNICALL Java_GdaJValue_getCBoolean (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jboolean) g_value_get_boolean ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCDate (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jint year, jint month, jint day)
+{
+	GDate *date;
+
+	date = g_date_new_dmy (day, month, year);
+	if (g_date_valid (date)) {
+		GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+		g_value_init (value, G_TYPE_DATE);
+		g_value_take_boxed (value, date);
+	}
+	else {
+		g_date_free (date);
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return;
+		}
+		gchar *tmp = g_strdup_printf (_("Invalid date: year %d, month %d and day %d"), year, month, day);
+		(*jenv)->ThrowNew (jenv, cls, tmp);
+		g_free (tmp);
+	}
+}
+
+JNIEXPORT jobject JNICALL
+Java_GdaJValue_getCDate (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GDate *date;
+	jobject jobj;
+
+	date = g_value_get_boxed ((GValue *) c_pointer);
+	if (!date || ! g_date_valid (date)) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	jobj = (*jenv)->CallObjectMethod (jenv, obj, GdaJValue__createDate->mid, 
+					  g_date_get_year (date), g_date_get_month (date) - 1, g_date_get_day (date));
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+	else
+		return jobj;
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCTime (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jint hour, jint min, jint sec)
+{
+	GdaTime *tim;
+	GValue *value;
+
+	tim = g_new0 (GdaTime, 1);
+	tim->hour = hour;
+	tim->minute = min;
+	tim->second = sec;
+
+	value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, GDA_TYPE_TIME);
+	g_value_take_boxed (value, tim);
+}
+
+JNIEXPORT jobject
+JNICALL Java_GdaJValue_getCTime (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GdaTime *tim;
+	jobject jobj;
+
+	tim = g_value_get_boxed ((GValue *) c_pointer);
+	if (!tim) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	jobj = (*jenv)->CallObjectMethod (jenv, obj, GdaJValue__createTime->mid, 
+					  tim->hour, tim->minute, tim->second);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+	else
+		return jobj;
+}
+
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCTimestamp (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jint year, jint month, jint day,
+				      jint hour, jint min, jint sec)
+{
+	GdaTimestamp *ts;
+	GValue *value;
+
+	ts = g_new0 (GdaTimestamp, 1);
+	ts->year = year;
+	ts->month = month;
+	ts->day = day;
+	ts->hour = hour;
+	ts->minute = min;
+	ts->second = sec;
+
+	value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, GDA_TYPE_TIMESTAMP);
+	g_value_take_boxed (value, ts);
+}
+
+JNIEXPORT jobject
+JNICALL Java_GdaJValue_getCTimestamp (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GdaTimestamp *ts;
+	jobject jobj;
+
+	ts = g_value_get_boxed ((GValue *) c_pointer);
+	if (!ts) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	jobj = (*jenv)->CallObjectMethod (jenv, obj, GdaJValue__createTimestamp->mid, 
+					  ts->year, ts->month, ts->day,
+					  ts->hour, ts->minute, ts->second);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+	else
+		return jobj;
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCBinary (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jbyteArray bytes)
+{
+	jint len;
+	GdaBinary *bin;
+	GValue *value;
+	
+	len = (*jenv)->GetArrayLength (jenv, bytes);
+	
+	bin = g_new0 (GdaBinary, 1);
+	bin->binary_length = len;
+	bin->data = g_new (guchar, len);
+	(*jenv)->GetByteArrayRegion(jenv, bytes, 0, len, (jbyte *) bin->data);
+
+	value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, GDA_TYPE_BINARY);
+	g_value_take_boxed (value, bin);
+}
+
+JNIEXPORT jbyteArray
+JNICALL Java_GdaJValue_getCBinary (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GdaBinary *bin;
+	jbyteArray jbytes;
+
+	bin = g_value_get_boxed ((GValue *) c_pointer);
+	if (!bin) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	jbytes = (*jenv)->NewByteArray (jenv, bin->binary_length);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+
+	(*jenv)->SetByteArrayRegion (jenv, jbytes, 0, bin->binary_length, (jbyte*) bin->data);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+
+	return jbytes;
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCBlob (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jlong cnc_c_pointer, jobject blobop)
+{
+	GdaBlob *blob;
+	GValue *value;
+
+	blob = g_new0 (GdaBlob, 1);
+	blob->op = gda_jdbc_blob_op_new_with_jblob (GDA_CONNECTION ((gpointer) cnc_c_pointer), jenv, blobop);
+
+	value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, GDA_TYPE_BLOB);
+	g_value_take_boxed (value, blob);
+}
+
+JNIEXPORT jobject
+JNICALL Java_GdaJValue_getCBlob (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GdaBlob *blob;
+
+	blob = g_value_get_boxed ((GValue *) c_pointer);
+	if (!blob) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	/* create a GdaInputStream */
+	if (blob->op) {
+		jobject retobj;
+		jmethodID mid;
+		mid = (*jenv)->GetMethodID (jenv, GdaInputStream__class, "<init>", "(JJ)V");
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+
+		glong size = gda_blob_op_get_length (blob->op);
+		if (size < 0) {
+			/* throw an exception */
+			jclass cls;
+			cls = (*jenv)->FindClass (jenv, "java/sql/SQLException");
+			if (!cls) {
+				/* Unable to find the exception class */
+				return NULL;
+			}
+			(*jenv)->ThrowNew (jenv, cls, _("Can't get BLOB's size"));
+			return NULL;
+		}
+		retobj = (*jenv)->NewObject (jenv, GdaInputStream__class, mid, (jlong) blob,
+					     (jlong) size);
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+		return retobj;
+	}
+	else {
+		jobject retobj;
+		jmethodID mid;
+		jbyteArray jbytes;
+		GdaBinary *bin = (GdaBinary *) blob;
+
+		mid = (*jenv)->GetMethodID (jenv, GdaInputStream__class, "<init>", "([B)V");
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+
+		jbytes = (*jenv)->NewByteArray (jenv, bin->binary_length);
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+		
+		(*jenv)->SetByteArrayRegion (jenv, jbytes, 0, bin->binary_length, (jbyte *) bin->data);
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+		
+		retobj = (*jenv)->NewObject (jenv, GdaInputStream__class, mid, jbytes);
+		if ((*jenv)->ExceptionCheck (jenv))
+			return NULL;
+		return retobj;
+	}
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCLong (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jlong l)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_INT64);
+	g_value_set_int64 (value, l);
+}
+
+JNIEXPORT jshort
+JNICALL Java_GdaJValue_getCLong (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jlong) g_value_get_int64 ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCShort (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jshort s)
+{
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	g_value_init (value, G_TYPE_INT64);
+	gda_value_set_short (value, s);
+}
+
+JNIEXPORT jshort
+JNICALL Java_GdaJValue_getCShort (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	return (jshort) gda_value_get_short ((GValue *) c_pointer);
+}
+
+JNIEXPORT void
+JNICALL Java_GdaJValue_setCNumeric (JNIEnv *jenv, jobject obj, jlong c_pointer, jint col, jstring str, 
+				    jint precision, jint scale)
+{
+	GdaNumeric *num;
+	GValue *value = gda_row_get_value (GDA_ROW ((gpointer) c_pointer), col);
+	gchar *tmp;
+	gint len;
+
+	len = (*jenv)->GetStringUTFLength (jenv, str);
+	tmp = g_new (gchar, len + 1);
+	(*jenv)->GetStringUTFRegion (jenv, str, 0, len, tmp);
+	num = g_new0 (GdaNumeric, 1);
+	num->number = tmp;
+	num->precision = precision;
+	num->width = scale;
+	g_value_init (value, GDA_TYPE_NUMERIC);
+	g_value_take_boxed (value, num);
+}
+
+JNIEXPORT jobject
+JNICALL Java_GdaJValue_getCNumeric (JNIEnv *jenv, jobject obj, jlong c_pointer)
+{
+	const GdaNumeric *num;
+	num = gda_value_get_numeric ((GValue *) c_pointer);
+	if (!num) {
+		jclass cls;
+		cls = (*jenv)->FindClass (jenv, "java/lang/IllegalArgumentException");
+		if (!cls) {
+			/* Unable to find the exception class */
+			return NULL;
+		}
+		(*jenv)->ThrowNew (jenv, cls, _("Invalid argument: NULL"));
+		return NULL;
+	}
+
+	jobject retobj;
+	jmethodID mid;
+	jstring string;
+	jclass cls;
+
+	cls = (*jenv)->FindClass (jenv, "java/math/BigDecimal");
+	if (!cls) {
+		/* Unable to find the BigDecimal class */
+		return NULL;
+	}
+	
+	mid = (*jenv)->GetStaticMethodID (jenv, cls, "<init>", "(Ljava/lang/String;)V");
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+
+	string = (*jenv)->NewStringUTF (jenv, num->number);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+
+	retobj = (*jenv)->NewObject (jenv, GdaInputStream__class, mid, string);
+	if ((*jenv)->ExceptionCheck (jenv))
+		return NULL;
+	return retobj;
+}

Added: trunk/providers/jdbc/MANIFEST.MF
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/MANIFEST.MF	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,2 @@
+Manifest-Version: 1.0
+Main-Class: GdaJProvider

Added: trunk/providers/jdbc/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/Makefile.am	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,127 @@
+providerdir=$(libdir)/libgda-$(GDA_ABI_MAJOR_VERSION).$(GDA_ABI_MINOR_VERSION)/providers
+provider_LTLIBRARIES = libgda-jdbc.la
+noinst_PROGRAMS = gda-jdbc-test
+bin_PROGRAMS = gda-list-jdbc-providers-4.0
+
+#Rem: JDBC_CFLAGS and JDBC_LIBS are the compile and link flags necessary to use the
+# C API. It is specific to the API and should be computed in the configure.in script.
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir) \
+	-I$(top_srcdir)/libgda \
+	-I$(top_builddir) \
+	$(LIBGDA_CFLAGS) $(JAVA_CFLAGS) \
+	-DJVM_PATH=\""$(JAVA_LD_PATH)"\" \
+	-DTOP_BUILD_DIR=\""$(top_builddir)"\"
+
+jni_sources = \
+	GdaJConnection.c \
+	GdaJMeta.c \
+	GdaJProvider.c \
+	GdaJPStmt.c \
+	GdaJResultSet.c \
+	GdaJResultSetInfos.c \
+	GdaJColumnInfos.c \
+	GdaJBlobOp.c \
+	GdaJValue.c \
+	GdaInputStream.c
+
+jni_headers = $(jni_sources:.c=.h) 
+jni_classes = $(jni_sources:.c=.class) 
+
+$(jni_sources): $(jni_headers)
+
+libgda_jdbc_la_SOURCES = \
+	gda-jdbc-blob-op.c \
+	gda-jdbc-blob-op.h \
+	gda-jdbc-ddl.c \
+	gda-jdbc-ddl.h \
+	gda-jdbc-provider.c \
+	gda-jdbc-provider.h \
+	gda-jdbc-pstmt.h \
+	gda-jdbc-pstmt.c \
+	gda-jdbc-meta.c \
+	gda-jdbc-meta.h \
+	gda-jdbc-recordset.c \
+	gda-jdbc-recordset.h \
+	gda-jdbc-util.c \
+	gda-jdbc-util.h \
+	gda-jdbc.h \
+	libmain.c \
+	jni-globals.h \
+	jni-wrapper.h \
+	jni-wrapper.c \
+	$(jni_sources) \
+	$(jni_headers)
+
+
+libgda_jdbc_la_LDFLAGS = -export-dynamic -module -avoid-version $(NO_UNDEFINED) $(LIBTOOL_PROV_EXPORT_OPTIONS)
+libgda_jdbc_la_LIBADD = \
+	$(top_builddir)/libgda/libgda-4.0.la \
+	$(LIBGDA_LIBS)
+# rem: don't link with JAVA_LIBS because we don't want the dependency on it
+# (JVM runtime will be loaded when running)
+
+# rem: if on Windows, then we need to add these flags because we don't want the exported symbols's names
+# to be mangled with @8 for example
+if PLATFORM_WIN32
+libgda_jdbc_la_LDFLAGS += -Wl,--kill-at
+endif
+
+
+$(jni_headers): $(jdbcprov_classes)
+	$(JAVAH) -classpath . -force `echo $@ | sed -e 's/\.h$$//'`
+
+jdbcprov_jar = gdaprovider-4.0.jar
+jdbcprov_sources = \
+	provider.java \
+	meta.java \
+	h2.java
+jdbcprov_classes = GdaJConnection.class
+
+jdbcprovdir = $(providerdir)
+jdbcprov_DATA = $(jdbcprov_jar)
+
+GdaJConnection.class: $(jdbcprov_sources)
+	$(JAVAC) -cp . -Xlint:unchecked -Xlint:deprecation -d $(top_builddir)/providers/jdbc $^
+
+$(jdbcprov_jar): $(jdbcprov_classes)
+	$(JAR) cfm $(jdbcprov_jar) $(top_srcdir)/providers/jdbc/MANIFEST.MF *.class
+
+clean-local:
+	rm -rf $(jdbcprov_jar)
+	rm -f $(jni_headers)
+	rm -f *.class
+
+xmldir   = $(datadir)/libgda-4.0
+xml_in_files = \
+	jdbc_specs_dsn.xml.in \
+	jdbc_specs_create_table.xml.in 
+
+ INTLTOOL_XML_RULE@
+
+xml_DATA = $(xml_in_files:.xml.in=.xml) 
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libgda-jdbc-4.0.pc
+
+doc_files = \
+	doc/structure.dia
+
+EXTRA_DIST = $(xml_in_files) libgda-jdbc-4.0.pc.in \
+	$(jdbcprov_sources) \
+	$(doc_files)
+DISTCLEANFILES = $(xml_DATA)
+
+
+
+gda_jdbc_test_SOURCES = gda-jdbc-test.c
+gda_jdbc_test_LDADD = \
+        $(LIBGDA_LIBS) \
+        $(top_builddir)/libgda/libgda-4.0.la
+
+
+gda_list_jdbc_providers_4_0_SOURCES = gda-list-jdbc-providers.c
+gda_list_jdbc_providers_4_0_LDADD = \
+        $(LIBGDA_LIBS) \
+        $(top_builddir)/libgda/libgda-4.0.la
\ No newline at end of file

Added: trunk/providers/jdbc/doc/index.html
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/doc/index.html	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,90 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>JDBC provider's description</title>
+</head>
+<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
+<div>
+  <h1>Introduction</h1>
+  <p>
+    This notice briefly explains the structure of the JDBC provider as it is more complicated than
+    the usual database providers.
+  </p>
+  <p>
+    The JDBC provider uses the Java Native Interface (JNI) to run a Java Virtual Machine (JVM) which
+    itself is responsible for accessing the database using the JDBC API (java.sql.* classes) and
+    a JDBC driver.
+  </p>
+  <p>
+    For each available JDBC driver, the JDBC provider will create a specific provider named after
+    the JDBC driver name. For example the <link href="http://www.h2database.com";>H2 database</link> driver
+    being named "org.h2.Driver", the corresponding GDA provider will also be named "org.h2.Driver".
+  </p>
+  <p>
+    The <b>gda-list-jdbc-providers-4.0</b> program can be used to list all the useable JDBC drivers
+    found:<br/>
+    <pre>
+[]> gda-list-jdbc-providers-4.0
+Useable JDBC drivers:
+org.h2.Driver
+sun.jdbc.odbc.JdbcOdbcDriver
+    </pre>
+    Using the GDA SQL console, the list of database providers is then:<br/>
+    <pre>
+gda> .lp
+                                         Installed providers list
+Provider                     | Description                                                                  
+-----------------------------+------------------------------------------------------------------------------
+SQLite                       | Provider for SQLite databases                                                
+PostgreSQL                   | Provider for PostgreSQL databases                                            
+Berkeley-DB                  | Provider for Berkeley databases                                              
+MySQL                        | Provider for MySQL databases                                                 
+org.h2.Driver                | Provider to access databases using JDBC's org.h2.Driver driver               
+sun.jdbc.odbc.JdbcOdbcDriver | Provider to access databases using JDBC's sun.jdbc.odbc.JdbcOdbcDriver driver
+MSAccess                     | Provider for Microsoft Access files                                          
+(7 rows)
+    </pre>
+  </p>
+  <p>
+    Currently the only named parameter to define a DSN or to open a connection is the connection's URL as
+    defined by the JDBC driver, for example "URL=jdbc:h2:/path/to/h2file" for the H2 database. Opening a
+    connection using the GDA SQL console can be done as:
+    <pre>
+      []> gda-sql-4.0 org.h2.Driver://URL=jdbc:h2:/path/to/h2file
+    </pre>
+  </p>
+</div>
+
+<div>
+  <h1>Provider's structure</h1>
+  <p>
+    The following figure illustrates the provider's structure: the provider's corresponding shared
+    library is the "libgda-jdbc.so" file (or "libgda-jdbc.dll" for Windows). This shared library
+    does not depend on the Java's virtual machine library ("libjvm.dll") but this library is loaded
+    when the provider is initialized.
+  </p>
+  <p>
+    Once the Java's virtual machine library is loaded, the JAVA code specific to the JDBC provider
+    (the "gdaprovider-4.0.jar" file) and the various JDBC drivers (as .jar files) are loaded by the JVM.
+  </p>
+  <p>
+    The JAVA code specific to the JDBC provider (the "*.java" files) implements some classes
+    instantiated and used by the C code through JNI. This code itself uses some native C methods
+    through JNI which are implemented by the "Gda*.c" files (the "Gda*.h" files being generated
+    by JNI tools).
+  </p>
+  <p>
+    <img src="structure.png"/>
+  </p>
+  <p>
+    The "jni-globals.h" file declares all the JAVA object identifiers used by the C code which are
+    initialized when the corresponding JAVA classes are loaded by the JVM (in the "*initIDs()" methods).
+  </p>
+  <p>
+    The "jni-wrapper.h" and "jni-wrapper.c" files implement some small utility library to wrap some
+    common (but not all) calls to JNI.
+  </p>
+</div>
+</body>
+</html>

Added: trunk/providers/jdbc/doc/structure.dia
==============================================================================
Binary file. No diff available.

Added: trunk/providers/jdbc/doc/structure.png
==============================================================================
Binary file. No diff available.

Added: trunk/providers/jdbc/gda-jdbc-blob-op.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-blob-op.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,351 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <libgda/libgda.h>
+#include "gda-jdbc.h"
+#include "gda-jdbc-util.h"
+#include "gda-jdbc-blob-op.h"
+#include "jni-globals.h"
+
+struct _GdaJdbcBlobOpPrivate {
+	GdaConnection *cnc;
+	GValue        *blob_obj; /* JAVA GdaJBlobOp object */
+};
+
+static void gda_jdbc_blob_op_class_init (GdaJdbcBlobOpClass *klass);
+static void gda_jdbc_blob_op_init       (GdaJdbcBlobOp *blob,
+					 GdaJdbcBlobOpClass *klass);
+static void gda_jdbc_blob_op_finalize   (GObject *object);
+
+static glong gda_jdbc_blob_op_get_length (GdaBlobOp *op);
+static glong gda_jdbc_blob_op_read       (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size);
+static glong gda_jdbc_blob_op_write      (GdaBlobOp *op, GdaBlob *blob, glong offset);
+
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and finalize
+ */
+GType
+gda_jdbc_blob_op_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static const GTypeInfo info = {
+			sizeof (GdaJdbcBlobOpClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_jdbc_blob_op_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaJdbcBlobOp),
+			0,
+			(GInstanceInitFunc) gda_jdbc_blob_op_init
+		};
+		g_static_mutex_lock (&registering);
+		if (type == 0)
+			type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaJdbcBlobOp", &info, 0);
+		g_static_mutex_unlock (&registering);
+	}
+	return type;
+}
+
+static void
+gda_jdbc_blob_op_init (GdaJdbcBlobOp *op,
+			   GdaJdbcBlobOpClass *klass)
+{
+	g_return_if_fail (GDA_IS_JDBC_BLOB_OP (op));
+
+	op->priv = g_new0 (GdaJdbcBlobOpPrivate, 1);
+	op->priv->blob_obj = NULL;
+}
+
+static void
+gda_jdbc_blob_op_class_init (GdaJdbcBlobOpClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->finalize = gda_jdbc_blob_op_finalize;
+	blob_class->get_length = gda_jdbc_blob_op_get_length;
+	blob_class->read = gda_jdbc_blob_op_read;
+	blob_class->write = gda_jdbc_blob_op_write;
+}
+
+static void
+gda_jdbc_blob_op_finalize (GObject * object)
+{
+	GdaJdbcBlobOp *bop = (GdaJdbcBlobOp *) object;
+
+	g_return_if_fail (GDA_IS_JDBC_BLOB_OP (bop));
+
+	/* free specific information */
+	if (bop->priv->blob_obj)
+		gda_value_free (bop->priv->blob_obj);
+	g_free (bop->priv);
+	bop->priv = NULL;
+
+	parent_class->finalize (object);
+}
+
+/**
+ * gda_jdbc_blob_op_new_with_jblob
+ *
+ * Steals @blob_op.
+ */
+GdaBlobOp *
+gda_jdbc_blob_op_new_with_jblob (GdaConnection *cnc, JNIEnv *jenv, jobject blob_obj)
+{
+	GdaJdbcBlobOp *bop;
+	JavaVM *jvm;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (blob_obj, NULL);
+
+	if ((*jenv)->GetJavaVM (jenv, &jvm))
+		g_error ("Could not attach JAVA virtual machine's current thread");
+
+	bop = g_object_new (GDA_TYPE_JDBC_BLOB_OP, NULL);
+	bop->priv->cnc = cnc;
+	bop->priv->blob_obj = gda_value_new_jni_object (jvm, jenv, blob_obj);
+	
+	return GDA_BLOB_OP (bop);
+}
+
+/*
+ * Get length request
+ */
+static glong
+gda_jdbc_blob_op_get_length (GdaBlobOp *op)
+{
+	GdaJdbcBlobOp *bop;
+	GValue *jexec_res;
+	gint error_code;
+	gchar *sql_state;
+	glong retval;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	GError *error = NULL;
+
+	g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1);
+	bop = GDA_JDBC_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
+
+	/* fetch JNIEnv */
+	jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
+	if (!jenv)
+		return -1;
+
+	/* get length */
+	jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__length,
+					     bop->priv->blob_obj, &error_code, &sql_state, &error);
+	if (!jexec_res) {
+		_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+		return -1;
+	}
+
+	_gda_jdbc_release_jenv (jni_detach);
+
+	retval = g_value_get_int64 (jexec_res);
+	gda_value_free (jexec_res);
+	return retval;
+}
+
+/*
+ * Blob read request
+ */
+static glong
+gda_jdbc_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size)
+{
+	GdaJdbcBlobOp *bop;
+	GdaBinary *bin;
+	gint error_code;
+	gchar *sql_state;
+	GValue *jexec_res;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	GError *error = NULL;
+	jbyteArray bytes;
+
+	g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1);
+	bop = GDA_JDBC_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
+	if (offset >= G_MAXINT)
+		return -1;
+	g_return_val_if_fail (blob, -1);
+	
+	/* fetch JNIEnv */
+	jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
+	if (!jenv)
+		return -1;
+
+	/* get data */
+	jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__read,
+					     bop->priv->blob_obj, &error_code, &sql_state, &error, 
+					     (jlong) offset, (jint) size);
+	if (!jexec_res) {
+		_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+		return -1;
+	}
+
+	/* copy data */
+	bin = (GdaBinary *) blob;
+	if (bin->data) 
+		g_free (bin->data);
+	bytes = (jbyteArray) gda_value_get_jni_object (jexec_res);
+	bin->binary_length = (*jenv)->GetArrayLength (jenv, bytes);
+	bin->data = g_new (guchar, bin->binary_length);
+	(*jenv)->GetByteArrayRegion(jenv, bytes, 0, bin->binary_length, (jbyte *) bin->data);
+
+	_gda_jdbc_release_jenv (jni_detach);
+	gda_value_free (jexec_res);
+
+	return bin->binary_length;
+}
+
+/*
+ * Blob write request
+ */
+static glong
+gda_jdbc_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset)
+{
+	GdaJdbcBlobOp *bop;
+	GdaBinary *bin;
+	gint error_code;
+	gchar *sql_state;
+	GValue *jexec_res;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	GError *error = NULL;
+	jbyteArray bytes;
+	glong nbwritten;
+
+	g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1);
+	bop = GDA_JDBC_BLOB_OP (op);
+	g_return_val_if_fail (bop->priv, -1);
+	g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1);
+	g_return_val_if_fail (blob, -1);
+
+	/* fetch JNIEnv */
+	jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
+	if (!jenv)
+		return -1;
+
+	if (blob->op && (blob->op != op)) {
+		/* use data through blob->op */
+		#define buf_size 16384
+		gint nread = 0;
+		GdaBlob *tmpblob;
+
+		nbwritten = 0;
+		tmpblob = g_new0 (GdaBlob, 1);
+		gda_blob_set_op (tmpblob, blob->op);
+
+		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, 0, buf_size);
+		     nread > 0;
+		     nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
+			GdaBinary *bin = (GdaBinary *) tmpblob;
+			glong tmp_written;
+
+			bytes = (*jenv)->NewByteArray (jenv, nread);
+			if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+				_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+				_gda_jdbc_release_jenv (jni_detach);
+				gda_blob_free ((gpointer) tmpblob);
+				return -1;
+			}
+
+			(*jenv)->SetByteArrayRegion (jenv, bytes, 0, nread, (jbyte*) bin->data);
+			if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+				_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+				(*jenv)->DeleteLocalRef (jenv, bytes);
+				_gda_jdbc_release_jenv (jni_detach);
+				gda_blob_free ((gpointer) tmpblob);
+				return -1;
+			}
+			
+			/* write data */
+			jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__write,
+							     bop->priv->blob_obj, &error_code, 
+							     &sql_state, &error, (jlong) offset, bytes);
+			(*jenv)->DeleteLocalRef (jenv, bytes);
+			if (!jexec_res) {
+				_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+				_gda_jdbc_release_jenv (jni_detach);
+				gda_blob_free ((gpointer) tmpblob);
+				return -1;
+			}
+
+			tmp_written = g_value_get_int64 (jexec_res);
+			gda_value_free (jexec_res);
+
+			g_assert (tmp_written == nread);
+
+			nbwritten += tmp_written;
+			if (nread < buf_size)
+				/* nothing more to read */
+				break;
+		}
+		gda_blob_free ((gpointer) tmpblob);
+	}
+	else {
+		/* prepare data to be written using bin->data and bin->binary_length */
+		bin = (GdaBinary *) blob;
+		bytes = (*jenv)->NewByteArray (jenv, bin->binary_length);
+		if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+			_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+			_gda_jdbc_release_jenv (jni_detach);
+			return -1;
+		}
+		
+		(*jenv)->SetByteArrayRegion (jenv, bytes, 0, bin->binary_length, (jbyte*) bin->data);
+		if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+			_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+			(*jenv)->DeleteLocalRef (jenv, bytes);
+			_gda_jdbc_release_jenv (jni_detach);
+			return -1;
+		}
+		
+		/* write data */
+		jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__write,
+						     bop->priv->blob_obj, &error_code, &sql_state, &error, 
+						     (jlong) offset, bytes);
+		(*jenv)->DeleteLocalRef (jenv, bytes);
+		if (!jexec_res) {
+			_gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error);
+			return -1;
+		}
+		nbwritten = g_value_get_int64 (jexec_res);
+		gda_value_free (jexec_res);
+	}
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return nbwritten;
+}

Added: trunk/providers/jdbc/gda-jdbc-blob-op.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-blob-op.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,55 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_JDBC_BLOB_OP_H__
+#define __GDA_JDBC_BLOB_OP_H__
+
+#include <libgda/gda-blob-op.h>
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_JDBC_BLOB_OP            (gda_jdbc_blob_op_get_type())
+#define GDA_JDBC_BLOB_OP(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_JDBC_BLOB_OP, GdaJdbcBlobOp))
+#define GDA_JDBC_BLOB_OP_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_JDBC_BLOB_OP, GdaJdbcBlobOpClass))
+#define GDA_IS_JDBC_BLOB_OP(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_JDBC_BLOB_OP))
+#define GDA_IS_JDBC_BLOB_OP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_JDBC_BLOB_OP))
+
+typedef struct _GdaJdbcBlobOp        GdaJdbcBlobOp;
+typedef struct _GdaJdbcBlobOpClass   GdaJdbcBlobOpClass;
+typedef struct _GdaJdbcBlobOpPrivate GdaJdbcBlobOpPrivate;
+
+struct _GdaJdbcBlobOp {
+	GdaBlobOp             parent;
+	GdaJdbcBlobOpPrivate *priv;
+};
+
+struct _GdaJdbcBlobOpClass {
+	GdaBlobOpClass        parent_class;
+};
+
+GType         gda_jdbc_blob_op_get_type       (void) G_GNUC_CONST;
+GdaBlobOp    *gda_jdbc_blob_op_new_with_jblob (GdaConnection *cnc, JNIEnv *jenv, jobject blob_obj);
+
+G_END_DECLS
+
+#endif
+

Added: trunk/providers/jdbc/gda-jdbc-ddl.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-ddl.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,144 @@
+/* GDA Jdbc Provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      TO_ADD: your name and email
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include <libgda/libgda.h>
+#include "gda-jdbc-ddl.h"
+
+gchar *
+gda_jdbc_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
+			      GdaServerOperation *op, GError **error)
+{
+	GString *string;
+	const GValue *value;
+	gboolean allok = TRUE;
+	gboolean hasfields = FALSE;
+	gint nrows;
+	gint i;
+	gboolean first;
+	GSList *pkfields = NULL; /* list of GValue* composing the pkey */
+	gint nbpkfields = 0;
+	gchar *sql = NULL;
+
+	/* CREATE TABLE */
+	string = g_string_new ("CREATE TABLE ");
+
+	value = gda_server_operation_get_value_at (op, "/TABLE_DEF_P/TABLE_NAME");
+	g_assert (value && G_VALUE_HOLDS (value, G_TYPE_STRING));
+	g_string_append (string, g_value_get_string (value));
+	g_string_append (string, " (");
+		
+	/* FIELDS */
+	if (allok) {
+		GdaServerOperationNode *node;
+
+		node = gda_server_operation_get_node_info (op, "/FIELDS_A");
+		g_assert (node);
+
+		/* finding if there is a composed primary key */
+		nrows = gda_data_model_get_n_rows (node->model);
+		for (i = 0; i < nrows; i++) {
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i);
+			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+				pkfields = g_slist_append (pkfields,
+							   (GValue *) gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NAME/%d", i));
+		}
+		nbpkfields = g_slist_length (pkfields);
+
+		/* manually defined fields */
+		first = TRUE;
+		for (i = 0; i < nrows; i++) {
+			hasfields = TRUE;
+			if (first) 
+				first = FALSE;
+			else
+				g_string_append (string, ", ");
+				
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NAME/%d", i);
+			g_string_append (string, g_value_get_string (value));
+			g_string_append_c (string, ' ');
+				
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_TYPE/%d", i);
+			g_string_append (string, g_value_get_string (value));
+				
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_DEFAULT/%d", i);
+			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+				const gchar *str = g_value_get_string (value);
+				if (str && *str) {
+					g_string_append (string, " DEFAULT ");
+					g_string_append (string, str);
+				}
+			}
+				
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_NNUL/%d", i);
+			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+				g_string_append (string, " NOT NULL");
+
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_UNIQUE/%d", i);
+			if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+				g_string_append (string, " UNIQUE");
+				
+			if (nbpkfields == 1) {
+				value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_PKEY/%d", i);
+				if (value && G_VALUE_HOLDS (value, G_TYPE_BOOLEAN) && g_value_get_boolean (value))
+					g_string_append (string, " PRIMARY KEY");
+			}
+				
+			value = gda_server_operation_get_value_at (op, "/FIELDS_A/@COLUMN_CHECK/%d", i);
+			if (value && G_VALUE_HOLDS (value, G_TYPE_STRING)) {
+				const gchar *str = g_value_get_string (value);
+				if (str && *str) {
+					g_string_append (string, " CHECK (");
+					g_string_append (string, str);
+					g_string_append_c (string, ')');
+				}
+			}
+		}
+	}
+
+	/* composed primary key */
+	if (nbpkfields > 1) {
+		GSList *list = pkfields;
+
+		g_string_append (string, ", PRIMARY KEY (");
+		while (list) {
+			if (list != pkfields)
+				g_string_append (string, ", ");
+			g_string_append (string, g_value_get_string ((GValue*) list->data));
+			list = list->next;
+		}
+		g_string_append_c (string, ')');
+	}
+
+	g_string_append (string, ")");
+
+	if (!hasfields) {
+		allok = FALSE;
+		g_set_error (error, 0, 0, _("Table to create must have at least one row"));
+	}
+	g_slist_free (pkfields);
+
+	sql = string->str;
+	g_string_free (string, FALSE);
+
+	return sql;
+}

Added: trunk/providers/jdbc/gda-jdbc-ddl.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-ddl.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,34 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      TO_ADD: your name and email
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_JDBC_DDL_H__
+#define __GDA_JDBC_DDL_H__
+
+#include <libgda/gda-server-provider.h>
+
+G_BEGIN_DECLS
+
+gchar *gda_jdbc_render_CREATE_TABLE (GdaServerProvider *provider, GdaConnection *cnc, 
+				     GdaServerOperation *op, GError **error);
+G_END_DECLS
+
+#endif
+

Added: trunk/providers/jdbc/gda-jdbc-meta.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-meta.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,661 @@
+/* GDA jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include "gda-jdbc.h"
+#include "gda-jdbc-meta.h"
+#include "gda-jdbc-provider.h"
+#include <libgda/gda-meta-store.h>
+#include <libgda/sql-parser/gda-sql-parser.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/gda-connection-private.h>
+#include <libgda/gda-data-model-array.h>
+#include <libgda/gda-set.h>
+#include <libgda/gda-holder.h>
+#include "jni-globals.h"
+#include "gda-jdbc-util.h"
+#include "gda-jdbc-recordset.h"
+
+/*
+ * Meta initialization
+ */
+void
+_gda_jdbc_provider_meta_init (GdaServerProvider *provider)
+{
+}
+
+static gboolean
+init_meta_obj (GdaConnection *cnc, JNIEnv *jenv, JdbcConnectionData *cdata, GError **error)
+{
+	GError *lerror = NULL;
+	static GStaticMutex init_mutex = G_STATIC_MUTEX_INIT;
+
+	g_static_mutex_lock (&init_mutex);
+
+	if (cdata->jmeta_obj)
+		return TRUE;
+	cdata->jmeta_obj = jni_wrapper_method_call (jenv, GdaJConnection__getJMeta,
+						    cdata->jcnc_obj, NULL, NULL, &lerror);
+	g_static_mutex_unlock (&init_mutex);
+	if (!cdata->jmeta_obj) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, 0, NULL, lerror);
+		
+		return FALSE;
+	}
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__info (GdaServerProvider *prov, GdaConnection *cnc, 
+		      GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GdaDataModel *model = NULL;
+	gboolean retval = FALSE;
+	gint error_code;
+	gchar *sql_state;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	/* Get private data */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (! cdata->jmeta_obj && !init_meta_obj (cnc, jenv, cdata, error))
+		goto out;
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJMeta__getCatalog,
+					     cdata->jmeta_obj, &error_code, &sql_state, &lerror);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		goto out;
+	}
+
+	model = gda_data_model_array_new_with_g_types (1, G_TYPE_STRING);
+	GList *values;
+	gint res;
+	values = g_list_prepend (NULL, jexec_res);
+	res = gda_data_model_append_values (model, values, error);
+	gda_value_free (jexec_res);
+	g_list_free (values);
+	if (res == -1)
+		goto out;
+
+	retval = gda_meta_store_modify_with_context (store, context, model, error);
+
+ out:
+	if (model)
+		g_object_unref (model);
+	_gda_jdbc_release_jenv (jni_detach);
+		
+	return retval;
+}
+
+gboolean
+_gda_jdbc_meta__btypes (GdaServerProvider *prov, GdaConnection *cnc, 
+			GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__udt (GdaServerProvider *prov, GdaConnection *cnc, 
+		     GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_udt (GdaServerProvider *prov, GdaConnection *cnc, 
+		    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+		    const GValue *udt_catalog, const GValue *udt_schema)
+{
+	GdaDataModel *model;
+	gboolean retval = TRUE;
+
+	TO_IMPLEMENT;
+	/* fill in @model, with something like:
+	 * model = gda_connection_statement_execute_select (cnc, internal_stmt[I_STMT_UDT], i_set, error);
+	 */
+	if (!model)
+		return FALSE;
+	retval = gda_meta_store_modify_with_context (store, context, model, error);
+	g_object_unref (model);
+
+	return retval;
+}
+
+
+gboolean
+_gda_jdbc_meta__udt_cols (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;	
+}
+
+gboolean
+_gda_jdbc_meta_udt_cols (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			 const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;	
+}
+
+gboolean
+_gda_jdbc_meta__enums (GdaServerProvider *prov, GdaConnection *cnc, 
+		       GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;	
+}
+
+gboolean
+_gda_jdbc_meta_enums (GdaServerProvider *prov, GdaConnection *cnc, 
+		      GdaMetaStore *store, GdaMetaContext *context, GError **error,
+		      const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+
+gboolean
+_gda_jdbc_meta__domains (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_domains (GdaServerProvider *prov, GdaConnection *cnc, 
+			GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			const GValue *domain_catalog, const GValue *domain_schema)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, 
+				 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, 
+				GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				const GValue *domain_catalog, const GValue *domain_schema, 
+				const GValue *domain_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__el_types (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_el_types (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			 const GValue *specific_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__collations (GdaServerProvider *prov, GdaConnection *cnc, 
+			    GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_collations (GdaServerProvider *prov, GdaConnection *cnc, 
+			   GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			   const GValue *collation_catalog, const GValue *collation_schema, 
+			   const GValue *collation_name_n)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__character_sets (GdaServerProvider *prov, GdaConnection *cnc, 
+				GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_character_sets (GdaServerProvider *prov, GdaConnection *cnc, 
+			       GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			       const GValue *chset_catalog, const GValue *chset_schema, 
+			       const GValue *chset_name_n)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__schemata (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	return _gda_jdbc_meta_schemata (prov, cnc, store, context, error, NULL, NULL);
+}
+
+gboolean
+_gda_jdbc_meta_schemata (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+			 const GValue *catalog_name, const GValue *schema_name_n)
+{
+	JdbcConnectionData *cdata;
+	GdaDataModel *model = NULL;
+	gboolean retval = FALSE;
+	gint error_code;
+	gchar *sql_state;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	jstring catalog = NULL, schema = NULL;
+
+	/* Get private data */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (! cdata->jmeta_obj && !init_meta_obj (cnc, jenv, cdata, error))
+		goto out;
+
+	if (catalog_name) {
+		catalog = (*jenv)->NewStringUTF (jenv, g_value_get_string (catalog_name));
+		if ((*jenv)->ExceptionCheck (jenv))
+			goto out;
+	}
+
+	if (schema_name_n) {
+		schema = (*jenv)->NewStringUTF (jenv, g_value_get_string (schema_name_n));
+		if ((*jenv)->ExceptionCheck (jenv))
+			goto out;
+	}
+
+	/* get data from JDBC */
+	jexec_res = jni_wrapper_method_call (jenv, GdaJMeta__getSchemas,
+					     cdata->jmeta_obj, &error_code, &sql_state, &lerror,
+					     catalog, schema);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	model = (GdaDataModel *) gda_jdbc_recordset_new (cnc, NULL, NULL, jenv,
+							 jexec_res, GDA_DATA_MODEL_ACCESS_RANDOM, NULL);
+	if (!model)
+		goto out;
+
+	gda_data_model_dump (model, stdout);
+	retval = gda_meta_store_modify_with_context (store, context, model, error);
+
+ out:
+	if (catalog)
+		(*jenv)-> DeleteLocalRef (jenv, catalog);
+	if (schema)
+		(*jenv)-> DeleteLocalRef (jenv, schema);
+	if (model)
+		g_object_unref (model);
+	_gda_jdbc_release_jenv (jni_detach);
+		
+	return retval;
+}
+
+gboolean
+_gda_jdbc_meta__tables_views (GdaServerProvider *prov, GdaConnection *cnc, 
+			      GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	return _gda_jdbc_meta_tables_views (prov, cnc, store, context, error, NULL, NULL, NULL);
+}
+
+gboolean
+_gda_jdbc_meta_tables_views (GdaServerProvider *prov, GdaConnection *cnc, 
+			     GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			     const GValue *table_catalog, const GValue *table_schema, 
+			     const GValue *table_name_n)
+{
+	JdbcConnectionData *cdata;
+	GdaDataModel *model = NULL;
+	gboolean retval = FALSE;
+	gint error_code;
+	gchar *sql_state;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	jstring catalog = NULL, schema = NULL, name = NULL;
+
+	/* Get private data */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (! cdata->jmeta_obj && !init_meta_obj (cnc, jenv, cdata, error))
+		goto out;
+
+	if (table_catalog) {
+		catalog = (*jenv)->NewStringUTF (jenv, g_value_get_string (table_catalog));
+		if ((*jenv)->ExceptionCheck (jenv))
+			goto out;
+	}
+
+	if (table_schema) {
+		schema = (*jenv)->NewStringUTF (jenv, g_value_get_string (table_schema));
+		if ((*jenv)->ExceptionCheck (jenv))
+			goto out;
+	}
+
+	if (table_name_n) {
+		name = (*jenv)->NewStringUTF (jenv, g_value_get_string (table_name_n));
+		if ((*jenv)->ExceptionCheck (jenv))
+			goto out;
+	}
+
+	/* get data from JDBC: Tables */
+	jexec_res = jni_wrapper_method_call (jenv, GdaJMeta__getTables,
+					     cdata->jmeta_obj, &error_code, &sql_state, &lerror,
+					     catalog, schema, name);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	model = (GdaDataModel *) gda_jdbc_recordset_new (cnc, NULL, NULL, jenv,
+							 jexec_res, GDA_DATA_MODEL_ACCESS_RANDOM, NULL);
+	if (!model)
+		goto out;
+
+	GdaMetaContext c2;
+	c2 = *context; /* copy contents, just because we need to modify @context->table_name */
+	c2.table_name = "_tables";
+	retval = gda_meta_store_modify_with_context (store, &c2, model, error);
+	if (!retval)
+		goto out;
+
+	g_object_unref (model);
+	
+	/* get data from JDBC: Views */
+	jexec_res = jni_wrapper_method_call (jenv, GdaJMeta__getViews,
+					     cdata->jmeta_obj, &error_code, &sql_state, &lerror,
+					     catalog, schema, name);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	model = (GdaDataModel *) gda_jdbc_recordset_new (cnc, NULL, NULL, jenv,
+							 jexec_res, GDA_DATA_MODEL_ACCESS_RANDOM, NULL);
+	if (!model)
+		goto out;
+
+	c2.table_name = "_views";
+	retval = gda_meta_store_modify_with_context (store, &c2, model, error);
+
+ out:
+	if (catalog)
+		(*jenv)-> DeleteLocalRef (jenv, catalog);
+	if (schema)
+		(*jenv)-> DeleteLocalRef (jenv, schema);
+	if (name)
+		(*jenv)-> DeleteLocalRef (jenv, name);
+	if (model)
+		g_object_unref (model);
+	_gda_jdbc_release_jenv (jni_detach);
+		
+	return retval;
+}
+
+gboolean
+_gda_jdbc_meta__columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			const GValue *table_catalog, const GValue *table_schema, 
+			const GValue *table_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__view_cols (GdaServerProvider *prov, GdaConnection *cnc, 
+			   GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_view_cols (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			  const GValue *view_catalog, const GValue *view_schema, 
+			  const GValue *view_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
+				 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
+				GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+				const GValue *table_catalog, const GValue *table_schema, 
+				const GValue *table_name, const GValue *constraint_name_n)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
+				 GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
+				GdaMetaStore *store, GdaMetaContext *context, GError **error,
+				const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, 
+				const GValue *constraint_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__key_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			     GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_key_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			    const GValue *table_catalog, const GValue *table_schema, 
+			    const GValue *table_name, const GValue *constraint_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__check_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			       GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_check_columns (GdaServerProvider *prov, GdaConnection *cnc, 
+			      GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			      const GValue *table_catalog, const GValue *table_schema, 
+			      const GValue *table_name, const GValue *constraint_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__triggers (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_triggers (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			 const GValue *table_catalog, const GValue *table_schema, 
+			 const GValue *table_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__routines (GdaServerProvider *prov, GdaConnection *cnc, 
+			  GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_routines (GdaServerProvider *prov, GdaConnection *cnc, 
+			 GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			 const GValue *routine_catalog, const GValue *routine_schema, 
+			 const GValue *routine_name_n)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__routine_col (GdaServerProvider *prov, GdaConnection *cnc, 
+			     GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_routine_col (GdaServerProvider *prov, GdaConnection *cnc, 
+			    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			    const GValue *rout_catalog, const GValue *rout_schema, 
+			    const GValue *rout_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta__routine_par (GdaServerProvider *prov, GdaConnection *cnc, 
+			     GdaMetaStore *store, GdaMetaContext *context, GError **error)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}
+
+gboolean
+_gda_jdbc_meta_routine_par (GdaServerProvider *prov, GdaConnection *cnc, 
+			    GdaMetaStore *store, GdaMetaContext *context, GError **error,
+			    const GValue *rout_catalog, const GValue *rout_schema, 
+			    const GValue *rout_name)
+{
+	TO_IMPLEMENT;
+	return TRUE;
+}

Added: trunk/providers/jdbc/gda-jdbc-meta.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-meta.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,197 @@
+/* GDA jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_JDBC_META_H__
+#define __GDA_JDBC_META_H__
+
+#include <libgda/gda-server-provider.h>
+
+G_BEGIN_DECLS
+
+void     _gda_jdbc_provider_meta_init    (GdaServerProvider *provider);
+
+/* _information_schema_catalog_name */
+gboolean _gda_jdbc_meta__info            (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+
+/* _builtin_data_types */
+gboolean _gda_jdbc_meta__btypes          (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+
+/* _udt */
+gboolean _gda_jdbc_meta__udt             (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_udt              (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *udt_catalog, const GValue *udt_schema);
+
+/* _udt_columns */
+gboolean _gda_jdbc_meta__udt_cols        (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_udt_cols         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+
+/* _enums */
+gboolean _gda_jdbc_meta__enums           (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_enums            (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *udt_catalog, const GValue *udt_schema, const GValue *udt_name);
+
+/* _domains */
+gboolean _gda_jdbc_meta__domains         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_domains          (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *domain_catalog, const GValue *domain_schema);
+
+/* _domain_constraints */
+gboolean _gda_jdbc_meta__constraints_dom (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_constraints_dom  (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *domain_catalog, const GValue *domain_schema, 
+					  const GValue *domain_name);
+
+/* _element_types */
+gboolean _gda_jdbc_meta__el_types        (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_el_types         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *specific_name);
+
+/* _collations */
+gboolean _gda_jdbc_meta__collations      (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_collations       (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *collation_catalog, const GValue *collation_schema, 
+					  const GValue *collation_name_n);
+
+/* _character_sets */
+gboolean _gda_jdbc_meta__character_sets  (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_character_sets   (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *chset_catalog, const GValue *chset_schema, 
+					  const GValue *chset_name_n);
+
+/* _schemata */
+gboolean _gda_jdbc_meta__schemata        (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_schemata         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					  const GValue *catalog_name, const GValue *schema_name_n);
+
+/* _tables or _views */
+gboolean _gda_jdbc_meta__tables_views    (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_tables_views     (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name_n);
+
+/* _columns */
+gboolean _gda_jdbc_meta__columns         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_columns          (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name);
+
+/* _view_column_usage */
+gboolean _gda_jdbc_meta__view_cols       (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_view_cols        (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *view_catalog, const GValue *view_schema, 
+					  const GValue *view_name);
+
+/* _table_constraints */
+gboolean _gda_jdbc_meta__constraints_tab (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_constraints_tab  (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error, 
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name, const GValue *constraint_name_n);
+
+/* _referential_constraints */
+gboolean _gda_jdbc_meta__constraints_ref (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_constraints_ref  (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, const GValue *table_name, 
+					  const GValue *constraint_name);
+
+/* _key_column_usage */
+gboolean _gda_jdbc_meta__key_columns     (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_key_columns      (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name, const GValue *constraint_name);
+
+/* _check_column_usage */
+gboolean _gda_jdbc_meta__check_columns   (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_check_columns    (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name, const GValue *constraint_name);
+
+/* _triggers */
+gboolean _gda_jdbc_meta__triggers        (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_triggers         (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *table_catalog, const GValue *table_schema, 
+					  const GValue *table_name);
+
+/* _routines */
+gboolean _gda_jdbc_meta__routines       (GdaServerProvider *prov, GdaConnection *cnc, 
+					 GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_routines        (GdaServerProvider *prov, GdaConnection *cnc, 
+					 GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					 const GValue *routine_catalog, const GValue *routine_schema, 
+					 const GValue *routine_name_n);
+
+/* _routine_columns */
+gboolean _gda_jdbc_meta__routine_col     (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_routine_col      (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *rout_catalog, const GValue *rout_schema, 
+					  const GValue *rout_name);
+
+/* _parameters */
+gboolean _gda_jdbc_meta__routine_par     (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error);
+gboolean _gda_jdbc_meta_routine_par      (GdaServerProvider *prov, GdaConnection *cnc, 
+					  GdaMetaStore *store, GdaMetaContext *context, GError **error,
+					  const GValue *rout_catalog, const GValue *rout_schema, 
+					  const GValue *rout_name);
+
+
+G_END_DECLS
+
+#endif
+

Added: trunk/providers/jdbc/gda-jdbc-provider.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-provider.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,1730 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
+#include <libgda/libgda.h>
+#include <libgda/gda-data-model-private.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include <libgda/gda-statement-extra.h>
+#include <sql-parser/gda-sql-parser.h>
+#include "gda-jdbc.h"
+#include "gda-jdbc-provider.h"
+#include "gda-jdbc-recordset.h"
+#include "gda-jdbc-ddl.h"
+#include "gda-jdbc-meta.h"
+#include "gda-jdbc-util.h"
+#include "jni-wrapper.h"
+#include "jni-globals.h"
+
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
+
+/*
+ * GObject methods
+ */
+static void gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass);
+static void gda_jdbc_provider_init       (GdaJdbcProvider *provider,
+					  GdaJdbcProviderClass *klass);
+static GObjectClass *parent_class = NULL;
+
+/*
+ * GdaServerProvider's virtual methods
+ */
+/* connection management */
+static gboolean            gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+							      GdaQuarkList *params, GdaQuarkList *auth,
+							      guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data);
+static gboolean            gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc);
+static const gchar        *gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc);
+
+/* DDL operations */
+static gboolean            gda_jdbc_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								 GdaServerOperationType type, GdaSet *options);
+static GdaServerOperation *gda_jdbc_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
+							       GdaServerOperationType type,
+							       GdaSet *options, GError **error);
+static gchar              *gda_jdbc_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
+							       GdaServerOperation *op, GError **error);
+
+static gboolean            gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
+								GdaServerOperation *op, guint *task_id, 
+								GdaServerProviderAsyncCallback async_cb, gpointer cb_data,
+								GError **error);
+/* transactions */
+static gboolean            gda_jdbc_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+								const gchar *name, GdaTransactionIsolation level, GError **error);
+static gboolean            gda_jdbc_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+								 const gchar *name, GError **error);
+static gboolean            gda_jdbc_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection * cnc,
+								   const gchar *name, GError **error);
+static gboolean            gda_jdbc_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+							    const gchar *name, GError **error);
+static gboolean            gda_jdbc_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+								 const gchar *name, GError **error);
+static gboolean            gda_jdbc_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+							       const gchar *name, GError **error);
+
+/* information retreival */
+static const gchar        *gda_jdbc_provider_get_version (GdaServerProvider *provider);
+static gboolean            gda_jdbc_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc,
+							       GdaConnectionFeature feature);
+
+static const gchar        *gda_jdbc_provider_get_name (GdaServerProvider *provider);
+
+static GdaDataHandler     *gda_jdbc_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
+							       GType g_type, const gchar *dbms_type);
+
+static const gchar*        gda_jdbc_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc,
+								    GType type);
+/* statements */
+static gchar               *gda_jdbc_provider_statement_to_sql  (GdaServerProvider *provider, GdaConnection *cnc,
+								 GdaStatement *stmt, GdaSet *params, 
+								 GdaStatementSqlFlag flags,
+								 GSList **params_used, GError **error);
+static gboolean             gda_jdbc_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+								 GdaStatement *stmt, GError **error);
+static GObject             *gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+								 GdaStatement *stmt, GdaSet *params,
+								 GdaStatementModelUsage model_usage, 
+								 GType *col_types, GdaSet **last_inserted_row, 
+								 guint *task_id, GdaServerProviderExecCallback async_cb, 
+								 gpointer cb_data, GError **error);
+
+/* distributed transactions */
+static gboolean gda_jdbc_provider_xa_start    (GdaServerProvider *provider, GdaConnection *cnc, 
+						   const GdaXaTransactionId *xid, GError **error);
+
+static gboolean gda_jdbc_provider_xa_end      (GdaServerProvider *provider, GdaConnection *cnc, 
+						   const GdaXaTransactionId *xid, GError **error);
+static gboolean gda_jdbc_provider_xa_prepare  (GdaServerProvider *provider, GdaConnection *cnc, 
+						   const GdaXaTransactionId *xid, GError **error);
+
+static gboolean gda_jdbc_provider_xa_commit   (GdaServerProvider *provider, GdaConnection *cnc, 
+						   const GdaXaTransactionId *xid, GError **error);
+static gboolean gda_jdbc_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc, 
+						   const GdaXaTransactionId *xid, GError **error);
+
+static GList   *gda_jdbc_provider_xa_recover  (GdaServerProvider *provider, GdaConnection *cnc, 
+						   GError **error);
+
+/* 
+ * private connection data destroy 
+ */
+static void gda_jdbc_free_cnc_data (JdbcConnectionData *cdata);
+
+
+/*
+ * Prepared internal statements
+ * TO_ADD: any prepared statement to be used internally by the provider should be
+ *         declared here, as constants and as SQL statements
+ */
+static GdaStatement **internal_stmt;
+
+typedef enum {
+	INTERNAL_STMT1
+} InternalStatementItem;
+
+static gchar *internal_sql[] = {
+	"SQL for INTERNAL_STMT1"
+};
+
+/*
+ * GdaJdbcProvider class implementation
+ */
+static void
+gda_jdbc_provider_class_init (GdaJdbcProviderClass *klass)
+{
+	GdaServerProviderClass *provider_class = GDA_SERVER_PROVIDER_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	provider_class->get_version = gda_jdbc_provider_get_version;
+	provider_class->get_server_version = gda_jdbc_provider_get_server_version;
+	provider_class->get_name = gda_jdbc_provider_get_name;
+	provider_class->supports_feature = gda_jdbc_provider_supports_feature;
+
+	provider_class->get_data_handler = gda_jdbc_provider_get_data_handler;
+	provider_class->get_def_dbms_type = gda_jdbc_provider_get_default_dbms_type;
+
+	provider_class->open_connection = gda_jdbc_provider_open_connection;
+	provider_class->close_connection = gda_jdbc_provider_close_connection;
+	provider_class->get_database = NULL;
+
+	provider_class->supports_operation = gda_jdbc_provider_supports_operation;
+        provider_class->create_operation = gda_jdbc_provider_create_operation;
+        provider_class->render_operation = gda_jdbc_provider_render_operation;
+        provider_class->perform_operation = gda_jdbc_provider_perform_operation;
+
+	provider_class->begin_transaction = gda_jdbc_provider_begin_transaction;
+	provider_class->commit_transaction = gda_jdbc_provider_commit_transaction;
+	provider_class->rollback_transaction = gda_jdbc_provider_rollback_transaction;
+	provider_class->add_savepoint = gda_jdbc_provider_add_savepoint;
+        provider_class->rollback_savepoint = gda_jdbc_provider_rollback_savepoint;
+        provider_class->delete_savepoint = gda_jdbc_provider_delete_savepoint;
+
+	provider_class->create_parser = NULL;
+	provider_class->statement_to_sql = gda_jdbc_provider_statement_to_sql;
+	provider_class->statement_prepare = gda_jdbc_provider_statement_prepare;
+	provider_class->statement_execute = gda_jdbc_provider_statement_execute;
+
+	provider_class->is_busy = NULL;
+	provider_class->cancel = NULL;
+	provider_class->create_connection = NULL;
+
+	memset (&(provider_class->meta_funcs), 0, sizeof (GdaServerProviderMeta));
+	provider_class->meta_funcs._info = _gda_jdbc_meta__info;
+	provider_class->meta_funcs._btypes = _gda_jdbc_meta__btypes;
+	provider_class->meta_funcs._udt = _gda_jdbc_meta__udt;
+	provider_class->meta_funcs.udt = _gda_jdbc_meta_udt;
+	provider_class->meta_funcs._udt_cols = _gda_jdbc_meta__udt_cols;
+	provider_class->meta_funcs.udt_cols = _gda_jdbc_meta_udt_cols;
+	provider_class->meta_funcs._enums = _gda_jdbc_meta__enums;
+	provider_class->meta_funcs.enums = _gda_jdbc_meta_enums;
+	provider_class->meta_funcs._domains = _gda_jdbc_meta__domains;
+	provider_class->meta_funcs.domains = _gda_jdbc_meta_domains;
+	provider_class->meta_funcs._constraints_dom = _gda_jdbc_meta__constraints_dom;
+	provider_class->meta_funcs.constraints_dom = _gda_jdbc_meta_constraints_dom;
+	provider_class->meta_funcs._el_types = _gda_jdbc_meta__el_types;
+	provider_class->meta_funcs.el_types = _gda_jdbc_meta_el_types;
+	provider_class->meta_funcs._collations = _gda_jdbc_meta__collations;
+	provider_class->meta_funcs.collations = _gda_jdbc_meta_collations;
+	provider_class->meta_funcs._character_sets = _gda_jdbc_meta__character_sets;
+	provider_class->meta_funcs.character_sets = _gda_jdbc_meta_character_sets;
+	provider_class->meta_funcs._schemata = _gda_jdbc_meta__schemata;
+	provider_class->meta_funcs.schemata = _gda_jdbc_meta_schemata;
+	provider_class->meta_funcs._tables_views = _gda_jdbc_meta__tables_views;
+	provider_class->meta_funcs.tables_views = _gda_jdbc_meta_tables_views;
+	provider_class->meta_funcs._columns = _gda_jdbc_meta__columns;
+	provider_class->meta_funcs.columns = _gda_jdbc_meta_columns;
+	provider_class->meta_funcs._view_cols = _gda_jdbc_meta__view_cols;
+	provider_class->meta_funcs.view_cols = _gda_jdbc_meta_view_cols;
+	provider_class->meta_funcs._constraints_tab = _gda_jdbc_meta__constraints_tab;
+	provider_class->meta_funcs.constraints_tab = _gda_jdbc_meta_constraints_tab;
+	provider_class->meta_funcs._constraints_ref = _gda_jdbc_meta__constraints_ref;
+	provider_class->meta_funcs.constraints_ref = _gda_jdbc_meta_constraints_ref;
+	provider_class->meta_funcs._key_columns = _gda_jdbc_meta__key_columns;
+	provider_class->meta_funcs.key_columns = _gda_jdbc_meta_key_columns;
+	provider_class->meta_funcs._check_columns = _gda_jdbc_meta__check_columns;
+	provider_class->meta_funcs.check_columns = _gda_jdbc_meta_check_columns;
+	provider_class->meta_funcs._triggers = _gda_jdbc_meta__triggers;
+	provider_class->meta_funcs.triggers = _gda_jdbc_meta_triggers;
+	provider_class->meta_funcs._routines = _gda_jdbc_meta__routines;
+	provider_class->meta_funcs.routines = _gda_jdbc_meta_routines;
+	provider_class->meta_funcs._routine_col = _gda_jdbc_meta__routine_col;
+	provider_class->meta_funcs.routine_col = _gda_jdbc_meta_routine_col;
+	provider_class->meta_funcs._routine_par = _gda_jdbc_meta__routine_par;
+	provider_class->meta_funcs.routine_par = _gda_jdbc_meta_routine_par;
+
+	/* distributed transactions: if not supported, then provider_class->xa_funcs should be set to NULL */
+	provider_class->xa_funcs = g_new0 (GdaServerProviderXa, 1);
+	provider_class->xa_funcs->xa_start = gda_jdbc_provider_xa_start;
+	provider_class->xa_funcs->xa_end = gda_jdbc_provider_xa_end;
+	provider_class->xa_funcs->xa_prepare = gda_jdbc_provider_xa_prepare;
+	provider_class->xa_funcs->xa_commit = gda_jdbc_provider_xa_commit;
+	provider_class->xa_funcs->xa_rollback = gda_jdbc_provider_xa_rollback;
+	provider_class->xa_funcs->xa_recover = gda_jdbc_provider_xa_recover;
+
+	/* not limiting to current thread */
+	provider_class->limiting_thread = NULL;
+}
+
+extern JavaVM *_jdbc_provider_java_vm;
+
+static void
+gda_jdbc_provider_init (GdaJdbcProvider *jdbc_prv, GdaJdbcProviderClass *klass)
+{
+	InternalStatementItem i;
+	GdaSqlParser *parser;
+
+	parser = gda_server_provider_internal_get_parser ((GdaServerProvider*) jdbc_prv);
+	internal_stmt = g_new0 (GdaStatement *, sizeof (internal_sql) / sizeof (gchar*));
+	for (i = INTERNAL_STMT1; i < sizeof (internal_sql) / sizeof (gchar*); i++) {
+		internal_stmt[i] = gda_sql_parser_parse_string (parser, internal_sql[i], NULL, NULL);
+		if (!internal_stmt[i]) 
+			g_error ("Could not parse internal statement: %s\n", internal_sql[i]);
+	}
+
+	/* meta data init */
+	_gda_jdbc_provider_meta_init ((GdaServerProvider*) jdbc_prv);
+
+	/* TO_ADD: any other provider's init should be added here */
+}
+
+GType
+gda_jdbc_provider_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static GTypeInfo info = {
+			sizeof (GdaJdbcProviderClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_jdbc_provider_class_init,
+			NULL, NULL,
+			sizeof (GdaJdbcProvider),
+			0,
+			(GInstanceInitFunc) gda_jdbc_provider_init
+		};
+		g_static_mutex_lock (&registering);
+		if (type == 0)
+			type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaJdbcProvider", &info, 0);
+		g_static_mutex_unlock (&registering);
+	}
+
+	return type;
+}
+
+
+/*
+ * Get provider name request
+ */
+static const gchar *
+gda_jdbc_provider_get_name (GdaServerProvider *provider)
+{
+	return GDA_JDBC_PROVIDER (provider)->jdbc_driver;
+}
+
+/* 
+ * Get provider's version, no need to change this
+ */
+static const gchar *
+gda_jdbc_provider_get_version (GdaServerProvider *provider)
+{
+	return PACKAGE_VERSION;
+}
+
+/* 
+ * Open connection request
+ *
+ * In this function, the following _must_ be done:
+ *   - check for the presence and validify of the parameters required to actually open a connection,
+ *     using @params
+ *   - open the real connection to the database using the parameters previously checked
+ *   - create a JdbcConnectionData structure and associate it to @cnc
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ */
+static gboolean
+gda_jdbc_provider_open_connection (GdaServerProvider *provider, GdaConnection *cnc,
+				   GdaQuarkList *params, GdaQuarkList *auth,
+				   guint *task_id, GdaServerProviderAsyncCallback async_cb, gpointer cb_data)
+{
+	GdaJdbcProvider *jprov;
+	g_return_val_if_fail (GDA_IS_JDBC_PROVIDER (provider), FALSE);
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	jprov = (GdaJdbcProvider*) provider;
+
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		gda_connection_add_event_string (cnc, _("Provider does not support asynchronous connection open"));
+                return FALSE;
+	}
+
+	/* Check for connection parameters */
+	const gchar *url;
+	url = gda_quark_list_find (params, "URL");
+	if (!url) {
+		gda_connection_add_event_string (cnc,
+						 _("The connection string must contain the URL value"));
+		return FALSE;
+	}
+
+	/* Check for username / password */
+	const gchar *username = NULL, *password = NULL;
+	if (auth) {
+		username = gda_quark_list_find (auth, "USERNAME");
+		password = gda_quark_list_find (auth, "PASSWORD");
+	}
+	
+	/* open the real connection to the database */
+	g_assert (jprov->jprov_obj);
+	GValue *obj_value;
+	jstring jstr, jstr1, jstr2;
+	JNIEnv *env;
+	GError *error = NULL;
+	gint error_code;
+	gchar *sql_state;
+	gboolean jni_detach;
+
+	env = _gda_jdbc_get_jenv (&jni_detach, &error);
+
+	if (!env) {
+		gda_connection_add_event_string (cnc, "%s",
+						 error && error->message ? error->message : _("No detail"));
+		if (error)
+			g_error_free (error);
+		return FALSE;
+	}
+
+	jstr = (*env)->NewStringUTF (env, url);
+	if (username)
+		jstr1 = (*env)->NewStringUTF (env, username);
+	else
+		jstr1 = NULL;
+	if (password)
+		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);
+	(*env)->DeleteLocalRef(env, jstr);
+	if (jstr1)
+		(*env)->DeleteLocalRef(env, jstr1);
+	if (jstr2)
+		(*env)->DeleteLocalRef(env, jstr2);
+
+	if (!obj_value) {
+		_gda_jdbc_make_error (cnc, error_code, sql_state, error);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	/* Create a new instance of the provider specific data associated to a connection (JdbcConnectionData),
+	 * and set its contents */
+	JdbcConnectionData *cdata;
+	cdata = g_new0 (JdbcConnectionData, 1);
+	gda_connection_internal_set_provider_data (cnc, cdata, (GDestroyNotify) gda_jdbc_free_cnc_data);
+	cdata->jcnc_obj = obj_value;
+
+	_gda_jdbc_release_jenv (jni_detach);
+	return TRUE;
+}
+
+/* 
+ * Close connection request
+ *
+ * In this function, the following _must_ be done:
+ *   - Actually close the connection to the database using @cnc's associated JdbcConnectionData structure
+ *   - Free the JdbcConnectionData structure and its contents
+ *
+ * Returns: TRUE if no error occurred, or FALSE otherwise (and an ERROR gonnection event must be added to @cnc)
+ */
+static gboolean
+gda_jdbc_provider_close_connection (GdaServerProvider *provider, GdaConnection *cnc)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	/* Close the connection using the C API */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	/* Free the JdbcConnectionData structure and its contents */
+	gda_jdbc_free_cnc_data (cdata);
+	gda_connection_internal_set_provider_data (cnc, NULL, NULL);
+
+	return TRUE;
+}
+
+/*
+ * Server version request
+ *
+ * Returns the server version as a string
+ */
+static const gchar *
+gda_jdbc_provider_get_server_version (GdaServerProvider *provider, GdaConnection *cnc)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	if (! cdata->server_version && cdata->jcnc_obj) {
+		JNIEnv *jenv;
+		gboolean jni_detach;
+		GError *error = NULL;
+
+		jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
+		if (!jenv) {
+			g_warning ("%s", error->message);
+			g_error_free (error);
+		}
+		else {
+			GValue *res;
+			res = jni_wrapper_method_call (jenv, GdaJConnection__getServerVersion,
+						       cdata->jcnc_obj, NULL, NULL, NULL);
+			if (res) {
+				cdata->server_version = g_value_dup_string (res);
+				gda_value_free (res);
+			}
+			_gda_jdbc_release_jenv (jni_detach);
+		}
+	}
+
+	return cdata->server_version;
+}
+
+/*
+ * Support operation request
+ *
+ * Tells what the implemented server operations are. To add support for an operation, the following steps are required:
+ *   - create a jdbc_specs_....xml.in file describing the required and optional parameters for the operation
+ *   - add it to the Makefile.am
+ *   - make this method return TRUE for the operation type
+ *   - implement the gda_jdbc_provider_render_operation() and gda_jdbc_provider_perform_operation() methods
+ *
+ */
+static gboolean
+gda_jdbc_provider_supports_operation (GdaServerProvider *provider, GdaConnection *cnc,
+				      GdaServerOperationType type, GdaSet *options)
+{
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	/* use native provider for help */
+	TO_IMPLEMENT;
+
+	return FALSE;
+}
+
+/*
+ * Create operation request
+ *
+ * Creates a #GdaServerOperation. The following code is generic and should only be changed
+ * if some further initialization is required, or if operation's contents is dependant on @cnc
+ */
+static GdaServerOperation *
+gda_jdbc_provider_create_operation (GdaServerProvider *provider, GdaConnection *cnc,
+				    GdaServerOperationType type, GdaSet *options, GError **error)
+{
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	/* use native provider for help */
+	TO_IMPLEMENT;
+	
+	return NULL;
+}
+
+/*
+ * Render operation request
+ */
+static gchar *
+gda_jdbc_provider_render_operation (GdaServerProvider *provider, GdaConnection *cnc,
+				    GdaServerOperation *op, GError **error)
+{
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	/* use native provider for help */
+	TO_IMPLEMENT;
+	
+	return NULL;
+}
+
+/*
+ * Perform operation request
+ */
+static gboolean
+gda_jdbc_provider_perform_operation (GdaServerProvider *provider, GdaConnection *cnc,
+				     GdaServerOperation *op, guint *task_id, 
+				     GdaServerProviderAsyncCallback async_cb, gpointer cb_data, GError **error)
+{
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+			     _("Provider does not support asynchronous server operation"));
+                return FALSE;
+	}
+
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	/* use native provider for help */
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * Begin transaction request
+ */
+static gboolean
+gda_jdbc_provider_begin_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+				     const gchar *name, GdaTransactionIsolation level,
+				     GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__begin,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Commit transaction request
+ */
+static gboolean
+gda_jdbc_provider_commit_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+				      const gchar *name, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__commit,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Rollback transaction request
+ */
+static gboolean
+gda_jdbc_provider_rollback_transaction (GdaServerProvider *provider, GdaConnection *cnc,
+					const gchar *name, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__rollback,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Add savepoint request
+ */
+static gboolean
+gda_jdbc_provider_add_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+				 const gchar *name, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+	jstring jname;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (name)
+		jname = (*jenv)->NewStringUTF (jenv, name);
+	else
+		jname = (*jenv)->NewStringUTF (jenv, "");
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__addSavepoint,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
+	(*jenv)->DeleteLocalRef (jenv, jname);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Rollback savepoint request
+ */
+static gboolean
+gda_jdbc_provider_rollback_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+				      const gchar *name, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+	jstring jname;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (name)
+		jname = (*jenv)->NewStringUTF (jenv, name);
+	else
+		jname = (*jenv)->NewStringUTF (jenv, "");
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__rollbackSavepoint,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
+	(*jenv)->DeleteLocalRef (jenv, jname);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Delete savepoint request
+ */
+static gboolean
+gda_jdbc_provider_delete_savepoint (GdaServerProvider *provider, GdaConnection *cnc,
+				    const gchar *name, GError **error)
+{
+	JdbcConnectionData *cdata;
+	GValue *jexec_res;
+	GError *lerror = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	gint error_code;
+	gchar *sql_state;
+	jstring jname;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return FALSE;
+
+	if (name)
+		jname = (*jenv)->NewStringUTF (jenv, name);
+	else
+		jname = (*jenv)->NewStringUTF (jenv, "");
+	if ((*jenv)->ExceptionCheck (jenv)) {
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__releaseSavepoint,
+					     cdata->jcnc_obj, &error_code, &sql_state, &lerror, jname);
+	(*jenv)->DeleteLocalRef (jenv, jname);
+	if (!jexec_res) {
+		if (error && lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, lerror);
+		_gda_jdbc_release_jenv (jni_detach);
+		return FALSE;
+	}
+	gda_value_free (jexec_res);
+	_gda_jdbc_release_jenv (jni_detach);
+
+	return TRUE;
+}
+
+/*
+ * Feature support request
+ */
+static gboolean
+gda_jdbc_provider_supports_feature (GdaServerProvider *provider, GdaConnection *cnc, GdaConnectionFeature feature)
+{
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	switch (feature) {
+	case GDA_CONNECTION_FEATURE_SQL :
+		return TRUE;
+	default: 
+		return FALSE;
+	}
+}
+
+/*
+ * Get data handler request
+ *
+ * This method allows one to obtain a pointer to a #GdaDataHandler object specific to @type or @dbms_type (@dbms_type
+ * must be considered only if @type is not a valid GType).
+ *
+ * A data handler allows one to convert a value between its different representations which are a human readable string,
+ * an SQL representation and a GValue.
+ *
+ * The recommended method is to create GdaDataHandler objects only when they are needed and to keep a reference to them
+ * for further usage, using the gda_server_provider_handler_declare() method.
+ *
+ * The implementation shown here does not define any specific data handler, but there should be some for at least 
+ * binary and time related types.
+ */
+static GdaDataHandler *
+gda_jdbc_provider_get_data_handler (GdaServerProvider *provider, GdaConnection *cnc,
+				    GType type, const gchar *dbms_type)
+{
+	GdaDataHandler *dh;
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	if (type == G_TYPE_INVALID) {
+		TO_IMPLEMENT; /* use @dbms_type */
+		dh = NULL;
+	}
+	/*
+	else if ((type == GDA_TYPE_BINARY) ||
+		 (type == GDA_TYPE_BLOB)) {
+		dh = gda_server_provider_handler_find (provider, cnc, type, NULL);
+                if (!dh) {
+                        dh = gda_postgres_handler_bin_new (cnc);
+                        if (dh) {
+                                gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BINARY, NULL);
+                                gda_server_provider_handler_declare (provider, dh, cnc, GDA_TYPE_BLOB, NULL);
+                                g_object_unref (dh);
+                        }
+                }
+	}
+	*/
+	else if ((type == GDA_TYPE_TIME) ||
+		 (type == GDA_TYPE_TIMESTAMP) ||
+		 (type == G_TYPE_DATE)) {
+		dh = gda_server_provider_handler_find (provider, NULL, type, NULL);
+                if (!dh) {
+                        dh = gda_handler_time_new ();
+                        gda_handler_time_set_sql_spec ((GdaHandlerTime *) dh, G_DATE_YEAR,
+						       G_DATE_MONTH, G_DATE_DAY, '-', FALSE);
+                        gda_server_provider_handler_declare (provider, dh, NULL, G_TYPE_DATE, NULL);
+                        gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIME, NULL);
+                        gda_server_provider_handler_declare (provider, dh, NULL, GDA_TYPE_TIMESTAMP, NULL);
+                        g_object_unref (dh);
+                }
+	}
+	else
+		dh = gda_server_provider_get_data_handler_default (provider, cnc, type, dbms_type);
+
+	return dh;
+}
+
+/*
+ * Get default DBMS type request
+ *
+ * This method returns the "preferred" DBMS type for GType
+ */
+static const gchar*
+gda_jdbc_provider_get_default_dbms_type (GdaServerProvider *provider, GdaConnection *cnc, GType type)
+{
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	}
+
+	TO_IMPLEMENT;
+
+	if ((type == G_TYPE_INT64) ||
+	    (type == G_TYPE_INT) ||
+	    (type == GDA_TYPE_SHORT) ||
+	    (type == GDA_TYPE_USHORT) ||
+	    (type == G_TYPE_CHAR) ||
+	    (type == G_TYPE_UCHAR) ||
+	    (type == G_TYPE_ULONG) ||
+	    (type == G_TYPE_UINT) ||
+	    (type == G_TYPE_UINT64))
+		return "integer";
+
+	if ((type == GDA_TYPE_BINARY) ||
+	    (type == GDA_TYPE_BLOB))
+		return "blob";
+
+	if (type == G_TYPE_BOOLEAN)
+		return "boolean";
+	
+	if ((type == G_TYPE_DATE) || 
+	    (type == GDA_TYPE_GEOMETRIC_POINT) ||
+	    (type == G_TYPE_OBJECT) ||
+	    (type == GDA_TYPE_LIST) ||
+	    (type == G_TYPE_STRING) ||
+	    (type == GDA_TYPE_TIME) ||
+	    (type == GDA_TYPE_TIMESTAMP) ||
+	    (type == G_TYPE_INVALID) ||
+	    (type == G_TYPE_GTYPE))
+		return "string";
+
+	if ((type == G_TYPE_DOUBLE) ||
+	    (type == GDA_TYPE_NUMERIC) ||
+	    (type == G_TYPE_FLOAT))
+		return "real";
+	
+	if (type == GDA_TYPE_TIME)
+		return "time";
+	if (type == GDA_TYPE_TIMESTAMP)
+		return "timestamp";
+	if (type == G_TYPE_DATE)
+		return "date";
+
+	return "text";
+}
+
+/*
+ * GdaStatement to SQL request
+ * 
+ * This method renders a #GdaStatement into its SQL representation.
+ *
+ * The implementation show here simply calls gda_statement_to_sql_extended() but the rendering
+ * can be specialized to the database's SQL dialect, see the implementation of gda_statement_to_sql_extended()
+ * and SQLite's specialized rendering for more details
+ */
+static gchar *
+gda_jdbc_provider_statement_to_sql (GdaServerProvider *provider, GdaConnection *cnc,
+				    GdaStatement *stmt, GdaSet *params, GdaStatementSqlFlag flags,
+				    GSList **params_used, GError **error)
+{
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+	if (cnc) {
+		g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+		g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+	}
+
+	return gda_statement_to_sql_extended (stmt, cnc, params, flags, params_used, error);
+}
+
+/*
+ * Statement prepare request
+ *
+ * This methods "converts" @stmt into a prepared statement. A prepared statement is a notion
+ * specific in its implementation details to the C API used here. If successfull, it must create
+ * a new #GdaJdbcPStmt object and declare it to @cnc.
+ */
+static gboolean
+gda_jdbc_provider_statement_prepare (GdaServerProvider *provider, GdaConnection *cnc,
+				     GdaStatement *stmt, GError **error)
+{
+	GdaJdbcPStmt *ps;
+	JdbcConnectionData *cdata;
+	gboolean retval = FALSE;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), FALSE);
+
+	/* fetch prepares stmt if already done */
+	ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
+	if (ps)
+		return TRUE;
+
+	/* Get private data */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	/* render as SQL understood by JDBC */
+	GdaSet *params = NULL;
+	gchar *sql;
+	GSList *used_params = NULL;
+	if (! gda_statement_get_parameters (stmt, &params, error))
+                return FALSE;
+        sql = gda_jdbc_provider_statement_to_sql (provider, cnc, stmt, params, GDA_STATEMENT_SQL_PARAMS_AS_UQMARK,
+						  &used_params, error);
+        if (!sql)
+		goto out;
+
+	/* prepare @stmt using the C API, creates @ps */
+	GValue *pstmt_obj;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+	jstring jsql;
+	
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv)
+		goto out;
+	
+	jsql = (*jenv)->NewStringUTF (jenv, sql);
+	pstmt_obj = jni_wrapper_method_call (jenv, GdaJConnection__prepareStatement,
+					     cdata->jcnc_obj, NULL, NULL, error, jsql);
+	(*jenv)->DeleteLocalRef (jenv, jsql);
+	if (!pstmt_obj) 
+		goto out;
+
+	/* make a list of the parameter names used in the statement */
+	GSList *param_ids = NULL;
+        if (used_params) {
+                GSList *list;
+		jbyte *ctypes;
+		gint i, nparams;
+
+		nparams = g_slist_length (used_params);
+		ctypes = g_new (jbyte, nparams);
+
+                for (i = 0, list = used_params;
+		     list;
+		     i++, list = list->next) {
+                        const gchar *cid;
+                        cid = gda_holder_get_id (GDA_HOLDER (list->data));
+                        if (cid) {
+                                param_ids = g_slist_append (param_ids, g_strdup (cid));
+				ctypes [i] = _gda_jdbc_gtype_to_proto_type (gda_holder_get_g_type ((GdaHolder*) list->data));
+				/* g_print ("PREPARATION: param ID: %s\n", cid);*/
+                        }
+                        else {
+                                g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_PREPARE_STMT_ERROR,
+                                             _("Unnamed parameter is not allowed in prepared statements"));
+                                g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+                                g_slist_free (param_ids);
+				g_free (ctypes);
+                                goto out;
+                        }
+                }
+
+		/* inform JDBC of the parameters' data types */
+		jbyteArray jtypes;
+		jtypes = (*jenv)->NewByteArray (jenv, nparams);
+		if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
+			g_free (ctypes);
+			g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+			g_slist_free (param_ids);
+			goto out;
+		}
+		
+		(*jenv)->SetByteArrayRegion (jenv, jtypes, 0, nparams, ctypes);
+		if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
+			g_free (ctypes);
+			(*jenv)->DeleteLocalRef (jenv, jtypes);
+			g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+			g_slist_free (param_ids);
+			goto out;
+		}
+		
+		GValue *jexec_res;
+		jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__declareParamTypes,
+						     pstmt_obj, NULL, NULL, error, (jlong) cnc, jtypes);
+		(*jenv)->DeleteLocalRef (jenv, jtypes);
+		g_free (ctypes);
+		
+		if (!jexec_res) {
+			g_slist_foreach (param_ids, (GFunc) g_free, NULL);
+			g_slist_free (param_ids);
+			goto out;
+		}
+		gda_value_free (jexec_res);
+        }
+
+	/* create a prepared statement object */
+	ps = gda_jdbc_pstmt_new (pstmt_obj);
+	gda_pstmt_set_gda_statement (_GDA_PSTMT (ps), stmt);
+        _GDA_PSTMT (ps)->param_ids = param_ids;
+        _GDA_PSTMT (ps)->sql = sql;
+
+	gda_connection_add_prepared_statement (cnc, stmt, (GdaPStmt *) ps);
+	g_object_unref (ps);
+	retval = TRUE;
+
+ out:
+	if (used_params)
+                g_slist_free (used_params);
+        if (params)
+                g_object_unref (params);
+	if (jenv)
+		_gda_jdbc_release_jenv (jni_detach);
+
+	return retval;
+}
+
+/*
+ * Execute statement request
+ *
+ * Executes a statement. This method should do the following:
+ *    - try to prepare the statement if not yet done
+ *    - optionnally reset the prepared statement
+ *    - bind the variables's values (which are in @params)
+ *    - add a connection event to log the execution
+ *    - execute the prepared statement
+ *
+ * If @stmt is an INSERT statement and @last_inserted_row is not NULL then additional actions must be taken to return the
+ * actual inserted row
+ */
+static GObject *
+gda_jdbc_provider_statement_execute (GdaServerProvider *provider, GdaConnection *cnc,
+				     GdaStatement *stmt, GdaSet *params,
+				     GdaStatementModelUsage model_usage, 
+				     GType *col_types, GdaSet **last_inserted_row, 
+				     guint *task_id, 
+				     GdaServerProviderExecCallback async_cb, gpointer cb_data, GError **error)
+{
+	GdaJdbcPStmt *ps;
+	JdbcConnectionData *cdata;
+	gboolean allow_noparam;
+        gboolean empty_rs = FALSE; /* TRUE when @allow_noparam is TRUE and there is a problem with @params
+                                      => resulting data model will be empty (0 row) */
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+	g_return_val_if_fail (GDA_IS_STATEMENT (stmt), NULL);
+
+	/* If asynchronous connection opening is not supported, then exit now */
+	if (async_cb) {
+		g_set_error (error, GDA_SERVER_PROVIDER_ERROR, GDA_SERVER_PROVIDER_METHOD_NON_IMPLEMENTED_ERROR,
+			     _("Provider does not support asynchronous statement execution"));
+                return NULL;
+	}
+
+	if (! (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS) &&
+            ! (model_usage & GDA_STATEMENT_MODEL_CURSOR_FORWARD))
+                model_usage |= GDA_STATEMENT_MODEL_RANDOM_ACCESS;
+	
+        allow_noparam = (model_usage & GDA_STATEMENT_MODEL_ALLOW_NOPARAM) &&
+                (gda_statement_get_statement_type (stmt) == GDA_SQL_STATEMENT_SELECT);
+	
+        if (last_inserted_row)
+                *last_inserted_row = NULL;
+
+	/* Get private data */
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return NULL;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, error);
+	if (!jenv) 
+		return NULL;
+
+	/* get/create new prepared statement */
+	ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
+	if (!ps) {
+		if (!gda_jdbc_provider_statement_prepare (provider, cnc, stmt, NULL)) {
+			/* this case can appear for example if some variables are used in places
+			 * where the C API cannot allow them (for example if the variable is the table name
+			 * in a SELECT statement). The action here is to get the actual SQL code for @stmt,
+			 * and use that SQL instead of @stmt to create another GdaJdbcPStmt object.
+			 */
+			gchar *sql;
+			jstring jsql;
+			GValue *pstmt_obj;
+
+                        sql = gda_jdbc_provider_statement_to_sql (provider, cnc, stmt, params, 0, NULL, error);
+                        if (!sql) {
+				_gda_jdbc_release_jenv (jni_detach);
+                                return NULL;
+			}
+			
+			jsql = (*jenv)->NewStringUTF (jenv, sql);
+			pstmt_obj = jni_wrapper_method_call (jenv, GdaJConnection__prepareStatement,
+							     cdata->jcnc_obj, NULL, NULL, error, jsql);
+			(*jenv)->DeleteLocalRef (jenv, jsql);
+                        g_free (sql);
+
+                        if (!pstmt_obj) {
+				_gda_jdbc_release_jenv (jni_detach);
+                                return NULL;
+			}
+
+			ps = gda_jdbc_pstmt_new (pstmt_obj);
+		}
+		else {
+			ps = (GdaJdbcPStmt *) gda_connection_get_prepared_statement (cnc, stmt);
+			g_object_ref (ps);
+		}
+	}
+	else
+		g_object_ref (ps);
+	g_assert (ps);
+
+	/* reset the prepared statement's parameters */
+	GValue *jexec_res;
+	jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__clearParameters,
+					     ps->pstmt_obj, NULL, NULL, error);
+	if (!jexec_res) {
+		g_object_unref (ps);
+		_gda_jdbc_release_jenv (jni_detach);
+		return NULL;
+	}
+	gda_value_free (jexec_res);
+
+	/* bind statement's parameters */
+	GSList *list;
+	GdaConnectionEvent *event = NULL;
+	int i;
+	for (i = 0, list = _GDA_PSTMT (ps)->param_ids; list; list = list->next, i++) {
+		const gchar *pname = (gchar *) list->data;
+		GdaHolder *h;
+		GError *lerror = NULL;
+
+		/* find requested parameter */
+		if (!params) {
+			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			gda_connection_event_set_description (event, _("Missing parameter(s) to execute query"));
+			g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+				     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR,
+				     _("Missing parameter(s) to execute query"));
+			break;
+		}
+
+		h = gda_set_get_holder (params, pname);
+		if (!h) {
+			gchar *tmp = gda_alphanum_to_text (g_strdup (pname + 1));
+			if (tmp) {
+				h = gda_set_get_holder (params, tmp);
+				g_free (tmp);
+			}
+		}
+		if (!h) {
+			if (! allow_noparam) {
+				gchar *str;
+				str = g_strdup_printf (_("Missing parameter '%s' to execute query"), pname);
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, str);
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
+				g_free (str);
+				break;
+			}
+			else {
+                                /* bind param to NULL */
+				jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
+								     ps->pstmt_obj, NULL, NULL, &lerror, i, 0);
+				if (!jexec_res) {
+					event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+					if (lerror)
+						gda_connection_event_set_description (event,
+						lerror->message ? lerror->message : _("No detail"));
+					g_propagate_error (error, lerror);
+					break;
+				}
+				gda_value_free (jexec_res);
+                                empty_rs = TRUE;
+                                continue;
+                        }
+
+		}
+		if (!gda_holder_is_valid (h)) {
+			if (! allow_noparam) {
+				gchar *str;
+				str = g_strdup_printf (_("Parameter '%s' is invalid"), pname);
+				event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+				gda_connection_event_set_description (event, str);
+				g_set_error (error, GDA_SERVER_PROVIDER_ERROR,
+					     GDA_SERVER_PROVIDER_MISSING_PARAM_ERROR, "%s", str);
+				g_free (str);
+				break;
+			}
+			else {
+                                /* bind param to NULL */
+				jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
+								     ps->pstmt_obj, NULL, NULL, &lerror, i, 0);
+				if (!jexec_res) {
+					event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+					if (lerror)
+						gda_connection_event_set_description (event,
+						lerror->message ? lerror->message : _("No detail"));
+					g_propagate_error (error, lerror);
+					break;
+				}
+				gda_value_free (jexec_res);
+                                empty_rs = TRUE;
+                                continue;
+                        }
+		}
+
+		/* actual binding using the C API, for parameter at position @i */
+		const GValue *value = gda_holder_get_value (h);
+		jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__setParameterValue,
+						     ps->pstmt_obj, NULL, NULL, &lerror, i, 
+						     (G_VALUE_TYPE (value) == GDA_TYPE_NULL) ? (glong) 0 : (glong) value);
+		if (!jexec_res) {
+			event = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+			if (lerror)
+				gda_connection_event_set_description (event,
+								      lerror->message ? lerror->message : _("No detail"));
+
+			g_propagate_error (error, lerror);
+			break;
+		}
+		gda_value_free (jexec_res);
+	}
+		
+	if (event) {
+		gda_connection_add_event (cnc, event);
+		g_object_unref (ps);
+		_gda_jdbc_release_jenv (jni_detach);
+		return NULL;
+	}
+	
+	/* add a connection event for the execution */
+	event = gda_connection_event_new (GDA_CONNECTION_EVENT_COMMAND);
+        gda_connection_event_set_description (event, _GDA_PSTMT (ps)->sql);
+        gda_connection_add_event (cnc, event);
+
+	if (empty_rs) {
+		/* There are some missing parameters, so the SQL can't be executed but we still want
+		 * to execute something to get the columns correctly. A possibility is to actually
+		 * execute another SQL which is the code shown here.
+		 *
+		 * To adapt depending on the C API and its features */
+		GdaStatement *estmt;
+                gchar *esql;
+		jstring jsql;
+                estmt = gda_select_alter_select_for_empty (stmt, error);
+                if (!estmt) {
+			g_object_unref (ps);
+			_gda_jdbc_release_jenv (jni_detach);
+                        return NULL;
+		}
+                esql = gda_statement_to_sql (estmt, NULL, error);
+                g_object_unref (estmt);
+                if (!esql) {
+			g_object_unref (ps);
+			_gda_jdbc_release_jenv (jni_detach);
+                        return NULL;
+		}
+
+		/* Execute the 'esql' SQL code */
+		jsql = (*jenv)->NewStringUTF (jenv, esql);
+                g_free (esql);
+		jexec_res = jni_wrapper_method_call (jenv, GdaJConnection__executeDirectSQL,
+						     cdata->jcnc_obj, NULL, NULL, error, jsql);
+		(*jenv)->DeleteLocalRef (jenv, jsql);
+		if (!jexec_res) {
+			g_object_unref (ps);
+			_gda_jdbc_release_jenv (jni_detach);
+			return NULL;
+		}
+	}
+	else {
+		/* Execute the _GDA_PSTMT (ps)->sql SQL code */
+		gboolean is_rs;
+		jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__execute,
+						     ps->pstmt_obj, NULL, NULL, error);
+		if (!jexec_res) {
+			g_object_unref (ps);
+			_gda_jdbc_release_jenv (jni_detach);
+			return NULL;
+		}
+		
+		is_rs = g_value_get_boolean (jexec_res);
+		gda_value_free (jexec_res);
+		if (is_rs) {
+			jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__getResultSet,
+							     ps->pstmt_obj, NULL, NULL, error);
+			if (!jexec_res) {
+				g_object_unref (ps);
+				_gda_jdbc_release_jenv (jni_detach);
+				return NULL;
+			}
+		}
+		else {
+			jexec_res = jni_wrapper_method_call (jenv, GdaJPStmt__getImpactedRows,
+							     ps->pstmt_obj, NULL, NULL, error);
+			if (!jexec_res) {
+				g_object_unref (ps);
+				_gda_jdbc_release_jenv (jni_detach);
+				return NULL;
+			}
+		}
+	}
+	
+	if (G_VALUE_TYPE (jexec_res) == GDA_TYPE_JNI_OBJECT) {
+		/* Note: at this point jexec_res must contain a GdaJResultSet JAVA object */
+		GObject *data_model;
+		GdaDataModelAccessFlags flags;
+
+		if (model_usage & GDA_STATEMENT_MODEL_RANDOM_ACCESS)
+			flags = GDA_DATA_MODEL_ACCESS_RANDOM;
+		else
+			flags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+
+                data_model = (GObject *) gda_jdbc_recordset_new (cnc, ps, params, jenv, jexec_res, flags, col_types);
+		gda_connection_internal_statement_executed (cnc, stmt, params, NULL); /* required: help @cnc keep some stats */
+
+		g_object_unref (ps);
+		_gda_jdbc_release_jenv (jni_detach);
+		return data_model;
+        }
+	else {
+		GdaSet *set = NULL;
+		
+		/*
+		gchar *str;
+		GdaConnectionEvent *event;
+
+		event = gda_connection_event_new (GDA_CONNECTION_EVENT_NOTICE);
+		str = g_strdup (PQcmdStatus (pg_res));
+		gda_connection_event_set_description (event, str);
+		g_free (str);
+		gda_connection_add_event (cnc, event);
+		*/
+
+		set = gda_set_new_inline (1, "IMPACTED_ROWS", G_TYPE_INT, g_value_get_int (jexec_res));
+		gda_value_free (jexec_res);
+		
+		/*
+		if ((PQoidValue (pg_res) != InvalidOid) && last_inserted_row)
+			*last_inserted_row = make_last_inserted_set (cnc, stmt, PQoidValue (pg_res));
+			*/
+		gda_connection_internal_statement_executed (cnc, stmt, params, event); /* required: help @cnc keep some stats */
+		g_object_unref (ps);
+		_gda_jdbc_release_jenv (jni_detach);
+		return (GObject*) set;
+	}
+}
+
+/*
+ * starts a distributed transaction: put the XA transaction in the ACTIVE state
+ */
+static gboolean
+gda_jdbc_provider_xa_start (GdaServerProvider *provider, GdaConnection *cnc, 
+				const GdaXaTransactionId *xid, GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	/* 
+	 * see Sun's Java Transaction API:
+	 * http://java.sun.com/javaee/technologies/jta/index.jsp
+	 */
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * put the XA transaction in the IDLE state: the connection won't accept any more modifications.
+ * This state is required by some database providers before actually going to the PREPARED state
+ */
+static gboolean
+gda_jdbc_provider_xa_end (GdaServerProvider *provider, GdaConnection *cnc, 
+			      const GdaXaTransactionId *xid, GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * prepares the distributed transaction: put the XA transaction in the PREPARED state
+ */
+static gboolean
+gda_jdbc_provider_xa_prepare (GdaServerProvider *provider, GdaConnection *cnc, 
+				  const GdaXaTransactionId *xid, GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * commits the distributed transaction: actually write the prepared data to the database and
+ * terminates the XA transaction
+ */
+static gboolean
+gda_jdbc_provider_xa_commit (GdaServerProvider *provider, GdaConnection *cnc, 
+				 const GdaXaTransactionId *xid, GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * Rolls back an XA transaction, possible only if in the ACTIVE, IDLE or PREPARED state
+ */
+static gboolean
+gda_jdbc_provider_xa_rollback (GdaServerProvider *provider, GdaConnection *cnc, 
+				   const GdaXaTransactionId *xid, GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), FALSE);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, FALSE);
+	g_return_val_if_fail (xid, FALSE);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return FALSE;
+
+	TO_IMPLEMENT;
+	return FALSE;
+}
+
+/*
+ * Lists all XA transactions that are in the PREPARED state
+ *
+ * Returns: a list of GdaXaTransactionId structures, which will be freed by the caller
+ */
+static GList *
+gda_jdbc_provider_xa_recover (GdaServerProvider *provider, GdaConnection *cnc,
+				  GError **error)
+{
+	JdbcConnectionData *cdata;
+
+	g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	g_return_val_if_fail (gda_connection_get_provider (cnc) == provider, NULL);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata) 
+		return NULL;
+
+	TO_IMPLEMENT;
+	return NULL;
+}
+
+/*
+ * Free connection's specific data
+ */
+static void
+gda_jdbc_free_cnc_data (JdbcConnectionData *cdata)
+{
+	if (!cdata)
+		return;
+
+	g_free (cdata->server_version);
+
+	if (cdata->jcnc_obj) {
+		/* force the connection to be closed */
+		JNIEnv *jenv;
+		gboolean jni_detach;
+		GError *error = NULL;
+
+		jenv = _gda_jdbc_get_jenv (&jni_detach, &error);
+		if (!jenv) {
+			g_warning ("%s", error->message);
+			g_error_free (error);
+		}
+		else {
+			GValue *res;
+			res = jni_wrapper_method_call (jenv, GdaJConnection__close,
+						       cdata->jcnc_obj, NULL, NULL, &error);
+			if (res) {
+#ifdef GDA_DEBUG
+				g_print ("Connection closed!\n");
+#endif
+				gda_value_free (res);
+			}
+			else {
+				g_warning ("Could not propertly close JDBC connection (will be done by the garbage collector): %s",
+					   error && error->message ? error->message : "No detail");
+				if (error)
+					g_error_free (error);
+			}
+			_gda_jdbc_release_jenv (jni_detach);
+		}
+		gda_value_free (cdata->jcnc_obj);
+		cdata->jcnc_obj = NULL;
+	}
+
+	if (cdata->jmeta_obj)
+		gda_value_free (cdata->jmeta_obj);
+
+	g_free (cdata);
+}
+
+/**
+ * gda_jdbc_provider_new
+ * @jdbc_driver: the JDBC driver to use (such as "sun.jdbc.odbc.JdbcOdbcDriver")
+ * @error: a place to store errors, or %NULL
+ *
+ * Returns: a new #GdaServerProvider for that JDBC driver, or %NULL if an error occurred
+ */
+GdaServerProvider *
+gda_jdbc_provider_new (const gchar *jdbc_driver, GError **error)
+{
+	GdaServerProvider *prov;
+	g_return_val_if_fail (jdbc_driver, NULL);
+
+	if (!_jdbc_provider_java_vm) {
+		g_set_error (error, 0, 0,
+			     "No JVM runtime identified (this should not happen at this point)!");
+		return NULL;
+	}
+
+	/* create a JAVA's GdaJProvider object */
+	JNIEnv *env;
+	GValue *obj_value;
+	jstring jstr;
+	gboolean detach_jni;
+
+	env = _gda_jdbc_get_jenv (&detach_jni, error);
+	if (!env)
+		return NULL;
+
+	jstr = (*env)->NewStringUTF(env, jdbc_driver);
+	obj_value = jni_wrapper_instantiate_object (env, GdaJProvider_class, "(Ljava/lang/String;)V", error, jstr);
+	(*env)->DeleteLocalRef(env, jstr);
+	if (!obj_value) {
+		_gda_jdbc_release_jenv (detach_jni);
+		return NULL;
+	}
+		
+	prov = (GdaServerProvider*) g_object_new (GDA_TYPE_JDBC_PROVIDER, NULL);
+	GDA_JDBC_PROVIDER (prov)->jprov_obj = obj_value;
+	_gda_jdbc_release_jenv (detach_jni);
+
+	GDA_JDBC_PROVIDER (prov)->jdbc_driver = g_strdup (jdbc_driver);
+
+	return prov;
+}

Added: trunk/providers/jdbc/gda-jdbc-provider.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-provider.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,54 @@
+/* GDA jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_JDBC_PROVIDER_H__
+#define __GDA_JDBC_PROVIDER_H__
+
+#include <libgda/gda-server-provider.h>
+
+#define GDA_TYPE_JDBC_PROVIDER            (gda_jdbc_provider_get_type())
+#define GDA_JDBC_PROVIDER(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_JDBC_PROVIDER, GdaJdbcProvider))
+#define GDA_JDBC_PROVIDER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_JDBC_PROVIDER, GdaJdbcProviderClass))
+#define GDA_IS_JDBC_PROVIDER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_JDBC_PROVIDER))
+#define GDA_IS_JDBC_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_JDBC_PROVIDER))
+
+typedef struct _GdaJdbcProvider      GdaJdbcProvider;
+typedef struct _GdaJdbcProviderClass GdaJdbcProviderClass;
+
+struct _GdaJdbcProvider {
+	GdaServerProvider      provider;
+	gchar                 *jdbc_driver;
+	GValue                *jprov_obj; /* JAVA GdaJProvider object */
+};
+
+struct _GdaJdbcProviderClass {
+	GdaServerProviderClass parent_class;
+};
+
+G_BEGIN_DECLS
+
+GType              gda_jdbc_provider_get_type (void) G_GNUC_CONST;
+GdaServerProvider *gda_jdbc_provider_new (const gchar *jdbc_driver, GError **error);
+
+G_END_DECLS
+
+#endif

Added: trunk/providers/jdbc/gda-jdbc-pstmt.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-pstmt.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,111 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include "gda-jdbc-pstmt.h"
+
+static void gda_jdbc_pstmt_class_init (GdaJdbcPStmtClass *klass);
+static void gda_jdbc_pstmt_init       (GdaJdbcPStmt *pstmt, GdaJdbcPStmtClass *klass);
+static void gda_jdbc_pstmt_finalize    (GObject *object);
+
+static GObjectClass *parent_class = NULL;
+
+/**
+ * gda_jdbc_pstmt_get_type
+ *
+ * Returns: the #GType of GdaJdbcPStmt.
+ */
+GType
+gda_jdbc_pstmt_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static const GTypeInfo info = {
+			sizeof (GdaJdbcPStmtClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_jdbc_pstmt_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaJdbcPStmt),
+			0,
+			(GInstanceInitFunc) gda_jdbc_pstmt_init
+		};
+
+		g_static_mutex_lock (&registering);
+		if (type == 0)
+			type = g_type_register_static (GDA_TYPE_PSTMT, "GdaJdbcPStmt", &info, 0);
+		g_static_mutex_unlock (&registering);
+	}
+	return type;
+}
+
+static void 
+gda_jdbc_pstmt_class_init (GdaJdbcPStmtClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	parent_class = g_type_class_peek_parent (klass);
+
+	/* virtual functions */
+	object_class->finalize = gda_jdbc_pstmt_finalize;
+}
+
+static void
+gda_jdbc_pstmt_init (GdaJdbcPStmt *pstmt, GdaJdbcPStmtClass *klass)
+{
+	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+	
+	pstmt->pstmt_obj = NULL;
+}
+
+static void
+gda_jdbc_pstmt_finalize (GObject *object)
+{
+	GdaJdbcPStmt *pstmt = (GdaJdbcPStmt *) object;
+
+	g_return_if_fail (GDA_IS_PSTMT (pstmt));
+
+	/* free memory */
+	if (pstmt->pstmt_obj)
+		gda_value_free (pstmt->pstmt_obj);
+
+	/* chain to parent class */
+	parent_class->finalize (object);
+}
+
+/**
+ * gda_jdbc_pstmt_new 
+ *
+ * @pstmt_obj may be NULL for a direct SQL statement or meta data
+ */
+GdaJdbcPStmt *
+gda_jdbc_pstmt_new (GValue *pstmt_obj)
+{
+	GdaJdbcPStmt *pstmt;
+	pstmt = g_object_new (GDA_TYPE_JDBC_PSTMT, NULL);
+	pstmt->pstmt_obj = pstmt_obj;
+
+	return pstmt;
+}

Added: trunk/providers/jdbc/gda-jdbc-pstmt.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-pstmt.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,55 @@
+/* GDA Jdbc library
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_JDBC_PSTMT_H__
+#define __GDA_JDBC_PSTMT_H__
+
+#include <providers-support/gda-pstmt.h>
+#include "gda-jdbc.h"
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_JDBC_PSTMT            (gda_jdbc_pstmt_get_type())
+#define GDA_JDBC_PSTMT(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_JDBC_PSTMT, GdaJdbcPStmt))
+#define GDA_JDBC_PSTMT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_JDBC_PSTMT, GdaJdbcPStmtClass))
+#define GDA_IS_JDBC_PSTMT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE(obj, GDA_TYPE_JDBC_PSTMT))
+#define GDA_IS_JDBC_PSTMT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GDA_TYPE_JDBC_PSTMT))
+
+typedef struct _GdaJdbcPStmt        GdaJdbcPStmt;
+typedef struct _GdaJdbcPStmtClass   GdaJdbcPStmtClass;
+
+struct _GdaJdbcPStmt {
+	GdaPStmt        object;
+	GValue         *pstmt_obj; /* JAVA PreparedStatement object */
+};
+
+struct _GdaJdbcPStmtClass {
+	GdaPStmtClass  parent_class;
+};
+
+GType         gda_jdbc_pstmt_get_type  (void) G_GNUC_CONST;
+GdaJdbcPStmt *gda_jdbc_pstmt_new (GValue *pstmt_obj);
+
+
+G_END_DECLS
+
+#endif

Added: trunk/providers/jdbc/gda-jdbc-recordset.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-recordset.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,528 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdarg.h>
+#include <string.h>
+#include <glib/gi18n-lib.h>
+#include <libgda/gda-util.h>
+#include <libgda/gda-connection-private.h>
+#include "gda-jdbc.h"
+#include "gda-jdbc-recordset.h"
+#include "gda-jdbc-provider.h"
+#include "jni-wrapper.h"
+#include "jni-globals.h"
+#include "gda-jdbc-util.h"
+#include "gda-jdbc-blob-op.h"
+
+#define _GDA_PSTMT(x) ((GdaPStmt*)(x))
+
+static void gda_jdbc_recordset_class_init (GdaJdbcRecordsetClass *klass);
+static void gda_jdbc_recordset_init       (GdaJdbcRecordset *recset,
+					     GdaJdbcRecordsetClass *klass);
+static void gda_jdbc_recordset_dispose   (GObject *object);
+
+/* virtual methods */
+static gint     gda_jdbc_recordset_fetch_nb_rows (GdaDataSelect *model);
+static gboolean gda_jdbc_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
+static gboolean gda_jdbc_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error);
+
+
+struct _GdaJdbcRecordsetPrivate {
+	GdaConnection *cnc;
+	GValue        *rs_value; /* JAVA GdaJResultSet object */
+
+	gint           next_row_num;
+        GdaRow        *tmp_row; /* used in cursor mode */
+};
+static GObjectClass *parent_class = NULL;
+
+/*
+ * Object init and finalize
+ */
+static void
+gda_jdbc_recordset_init (GdaJdbcRecordset *recset,
+			 GdaJdbcRecordsetClass *klass)
+{
+	g_return_if_fail (GDA_IS_JDBC_RECORDSET (recset));
+	recset->priv = g_new0 (GdaJdbcRecordsetPrivate, 1);
+	recset->priv->cnc = NULL;
+	recset->priv->rs_value = NULL;
+}
+
+static void
+gda_jdbc_recordset_class_init (GdaJdbcRecordsetClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+	GdaDataSelectClass *pmodel_class = GDA_DATA_SELECT_CLASS (klass);
+
+	parent_class = g_type_class_peek_parent (klass);
+
+	object_class->dispose = gda_jdbc_recordset_dispose;
+	pmodel_class->fetch_nb_rows = gda_jdbc_recordset_fetch_nb_rows;
+	pmodel_class->fetch_random = gda_jdbc_recordset_fetch_random;
+	pmodel_class->fetch_next = gda_jdbc_recordset_fetch_next;
+	pmodel_class->fetch_prev = NULL;
+        pmodel_class->fetch_at = NULL;
+}
+
+static void
+gda_jdbc_recordset_dispose (GObject *object)
+{
+	GdaJdbcRecordset *recset = (GdaJdbcRecordset *) object;
+
+	g_return_if_fail (GDA_IS_JDBC_RECORDSET (recset));
+
+	if (recset->priv) {
+		if (recset->priv->cnc) 
+			g_object_unref (recset->priv->cnc);
+
+		if (recset->priv->rs_value)
+			gda_value_free (recset->priv->rs_value);
+
+		if (recset->priv->tmp_row)
+                        g_object_unref (recset->priv->tmp_row);
+
+		g_free (recset->priv);
+		recset->priv = NULL;
+	}
+
+	parent_class->dispose (object);
+}
+
+/*
+ * Public functions
+ */
+
+GType
+gda_jdbc_recordset_get_type (void)
+{
+	static GType type = 0;
+
+	if (G_UNLIKELY (type == 0)) {
+		static GStaticMutex registering = G_STATIC_MUTEX_INIT;
+		static const GTypeInfo info = {
+			sizeof (GdaJdbcRecordsetClass),
+			(GBaseInitFunc) NULL,
+			(GBaseFinalizeFunc) NULL,
+			(GClassInitFunc) gda_jdbc_recordset_class_init,
+			NULL,
+			NULL,
+			sizeof (GdaJdbcRecordset),
+			0,
+			(GInstanceInitFunc) gda_jdbc_recordset_init
+		};
+		g_static_mutex_lock (&registering);
+		if (type == 0)
+			type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaJdbcRecordset", &info, 0);
+		g_static_mutex_unlock (&registering);
+	}
+
+	return type;
+}
+
+static GType
+jdbc_type_to_g_type (gint jdbc_type)
+{
+	switch (jdbc_type) {
+	case 12: /* VARCHAR */
+		return G_TYPE_STRING;
+	case 2003: /* ARRAY */
+		return GDA_TYPE_BINARY;
+ 	case -5: /* BIGINT */
+		return G_TYPE_INT64;
+ 	case -2: /* BINARY */
+		return GDA_TYPE_BINARY;
+ 	case -7: /* BIT */
+		return G_TYPE_BOOLEAN;
+ 	case 2004: /* BLOB */
+		return GDA_TYPE_BLOB;
+ 	case 16: /* BOOLEAN */
+		return G_TYPE_BOOLEAN;
+ 	case 1: /* CHAR */
+		return G_TYPE_STRING;
+ 	case 2005: /* CLOB */
+ 	case 70: /* DATALINK */
+		return GDA_TYPE_BINARY;
+ 	case 91: /* DATE */
+		return G_TYPE_DATE;
+ 	case 3: /* DECIMAL */
+		return GDA_TYPE_NUMERIC;
+ 	case 2001: /* DISTINCT */
+		return GDA_TYPE_BINARY;
+ 	case 8: /* DOUBLE */
+		return G_TYPE_DOUBLE;
+ 	case 6: /* FLOAT */
+		return G_TYPE_FLOAT;
+ 	case 4: /* INTEGER */
+		return G_TYPE_INT;
+ 	case 2000: /* JAVA_OBJECT */
+ 	case -4: /* LONGVARBINARY */
+		return GDA_TYPE_BINARY;
+ 	case -1: /* LONGVARCHAR */
+		return G_TYPE_STRING;
+ 	case 0: /* NULL */
+		return GDA_TYPE_NULL;
+	case 2: /* NUMERIC */
+		return GDA_TYPE_NUMERIC;
+	case 1111: /* OTHER */
+		return GDA_TYPE_BINARY;
+ 	case 7: /* REAL */
+		return G_TYPE_FLOAT;
+ 	case 2006: /* REF */
+		return GDA_TYPE_BINARY;
+ 	case 5: /* SMALLINT */
+		return GDA_TYPE_SHORT;
+ 	case 2002: /* STRUCT */
+		return GDA_TYPE_BINARY;
+ 	case 92: /* TIME */
+		return GDA_TYPE_TIME;
+ 	case 93: /* TIMESTAMP */
+		return GDA_TYPE_TIMESTAMP;
+ 	case -6: /* TINYINT */
+		return G_TYPE_CHAR;
+ 	case -3: /* VARBINARY */
+		return GDA_TYPE_BINARY;
+	default:
+		return GDA_TYPE_BINARY;
+	}
+}
+
+/*
+ * the @ps struct is modified and transfered to the new data model created in
+ * this function
+ */
+GdaDataModel *
+gda_jdbc_recordset_new (GdaConnection *cnc, GdaJdbcPStmt *ps, GdaSet *exec_params,
+			JNIEnv *jenv, GValue *rs_value, GdaDataModelAccessFlags flags, GType *col_types)
+{
+	GdaJdbcRecordset *model;
+        JdbcConnectionData *cdata;
+        gint i;
+	GdaDataModelAccessFlags rflags;
+	GValue *jexec_res;
+
+	GError *error = NULL;
+	gint error_code;
+	gchar *sql_state;
+
+        g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL);
+	if (ps)
+		g_return_val_if_fail (GDA_IS_JDBC_PSTMT (ps), NULL);
+	else
+		ps = gda_jdbc_pstmt_new (NULL);
+
+	cdata = (JdbcConnectionData*) gda_connection_internal_get_provider_data (cnc);
+	if (!cdata)
+		return NULL;
+
+	/* make sure @ps reports the correct number of columns using the API*/
+	jexec_res = jni_wrapper_method_call (jenv, GdaJResultSet__getInfos,
+					     rs_value, &error_code, &sql_state, &error);
+	if (!jexec_res) {
+		_gda_jdbc_make_error (cnc, error_code, sql_state, error);
+		gda_value_free (rs_value);
+		return NULL;
+	}
+
+        if (_GDA_PSTMT (ps)->ncols < 0) {
+		GValue *jfield_v;
+		jfield_v = jni_wrapper_field_get (jenv, GdaJResultSetInfos__ncols, jexec_res, &error);
+		if (! jfield_v) {
+			gda_value_free (jexec_res);
+			gda_value_free (rs_value);
+			return NULL;
+		}
+                _GDA_PSTMT (ps)->ncols = g_value_get_int (jfield_v);
+		gda_value_free (jfield_v);
+	}
+
+        /* completing @ps if not yet done */
+        if (!_GDA_PSTMT (ps)->types && (_GDA_PSTMT (ps)->ncols > 0)) {
+		/* create prepared statement's columns */
+		GSList *list;
+		gboolean allok = TRUE;
+
+		for (i = 0; i < _GDA_PSTMT (ps)->ncols; i++)
+			_GDA_PSTMT (ps)->tmpl_columns = g_slist_prepend (_GDA_PSTMT (ps)->tmpl_columns, 
+									 gda_column_new ());
+		_GDA_PSTMT (ps)->tmpl_columns = g_slist_reverse (_GDA_PSTMT (ps)->tmpl_columns);
+
+		/* create prepared statement's types */
+		_GDA_PSTMT (ps)->types = g_new0 (GType, _GDA_PSTMT (ps)->ncols); /* all types are initialized to GDA_TYPE_NULL */
+		if (col_types) {
+			for (i = 0; ; i++) {
+				if (col_types [i] > 0) {
+					if (col_types [i] == G_TYPE_NONE)
+						break;
+					if (i >= _GDA_PSTMT (ps)->ncols)
+						g_warning (_("Column %d out of range (0-%d), ignoring its specified type"), i,
+							   _GDA_PSTMT (ps)->ncols - 1);
+					else
+						_GDA_PSTMT (ps)->types [i] = col_types [i];
+				}
+			}
+		}
+		
+		/* fill GdaColumn's data */
+		for (i = 0, list = _GDA_PSTMT (ps)->tmpl_columns; 
+		     allok && (i < GDA_PSTMT (ps)->ncols);
+		     i++, list = list->next) {
+			GdaColumn *column;
+			GValue *jcol_v;
+			GValue *jcol_a;
+
+			jcol_v = jni_wrapper_method_call (jenv, GdaJResultSetInfos__describeColumn, jexec_res, 
+							  NULL, NULL, NULL, i);
+			if (!jcol_v) {
+				allok = FALSE;
+				break;
+			}
+			column = GDA_COLUMN (list->data);
+			jcol_a = jni_wrapper_field_get (jenv, GdaJColumnInfos__col_name, jcol_v, NULL);
+			if (jcol_a) {
+				if (G_VALUE_TYPE (jcol_a) != GDA_TYPE_NULL)
+					gda_column_set_name (column, g_value_get_string (jcol_a));
+				gda_value_free (jcol_a);
+			}
+			else
+				allok = FALSE;
+			jcol_a = jni_wrapper_field_get (jenv, GdaJColumnInfos__col_descr, jcol_v, NULL);
+			if (jcol_a) {
+				if (G_VALUE_TYPE (jcol_a) != GDA_TYPE_NULL)
+					gda_column_set_description (column, g_value_get_string (jcol_a));
+				gda_value_free (jcol_a);
+			}
+			else
+				allok = FALSE;
+			jcol_a = jni_wrapper_field_get (jenv, GdaJColumnInfos__col_type, jcol_v, NULL);
+			if (jcol_a) {
+				_GDA_PSTMT (ps)->types [i] = jdbc_type_to_g_type (g_value_get_int (jcol_a));
+				gda_column_set_g_type (column, _GDA_PSTMT (ps)->types [i]);
+				gda_value_free (jcol_a);
+			}
+			else
+				allok = FALSE;
+			gda_value_free (jcol_v);
+		}
+		if (!allok) {
+			g_free (_GDA_PSTMT (ps)->types);
+			_GDA_PSTMT (ps)->types = NULL;
+			g_slist_foreach (_GDA_PSTMT (ps)->tmpl_columns, (GFunc) g_object_unref, NULL);
+			g_slist_free (_GDA_PSTMT (ps)->tmpl_columns);
+			_GDA_PSTMT (ps)->tmpl_columns = NULL;
+
+			gda_value_free (jexec_res);
+			gda_value_free (rs_value);
+			return NULL;
+		}
+        }
+	gda_value_free (jexec_res);
+
+	/* declare the requested types (and connection pointer) to the used resultset */
+	jbyte *ctypes;
+	jbyteArray jtypes;
+
+	ctypes = g_new (jbyte, GDA_PSTMT (ps)->ncols);
+	for (i = 0; i < GDA_PSTMT (ps)->ncols; i++)
+		ctypes [i] = _gda_jdbc_gtype_to_proto_type (_GDA_PSTMT (ps)->types [i]);
+
+	jtypes = (*jenv)->NewByteArray (jenv, GDA_PSTMT (ps)->ncols);
+	if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+		g_free (ctypes);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, error);
+		gda_value_free (rs_value);
+		return NULL;
+	}
+
+	(*jenv)->SetByteArrayRegion (jenv, jtypes, 0, GDA_PSTMT (ps)->ncols, ctypes);
+	if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) {
+		g_free (ctypes);
+		_gda_jdbc_make_error (cnc, error_code, sql_state, error);
+		(*jenv)->DeleteLocalRef (jenv, jtypes);
+		gda_value_free (rs_value);
+		return NULL;
+	}
+	
+	jexec_res = jni_wrapper_method_call (jenv, GdaJResultSet__declareColumnTypes,
+					     rs_value, &error_code, &sql_state, &error, (jlong) cnc, jtypes);
+	(*jenv)->DeleteLocalRef (jenv, jtypes);
+	g_free (ctypes);
+	
+	if (!jexec_res) {
+		_gda_jdbc_make_error (cnc, error_code, sql_state, error);
+		gda_value_free (rs_value);
+		return NULL;
+	}
+
+	/* determine access mode: RANDOM or CURSOR FORWARD are the only supported */
+	if (flags & GDA_DATA_MODEL_ACCESS_RANDOM)
+		rflags = GDA_DATA_MODEL_ACCESS_RANDOM;
+	else
+		rflags = GDA_DATA_MODEL_ACCESS_CURSOR_FORWARD;
+
+	/* create data model */
+        model = g_object_new (GDA_TYPE_JDBC_RECORDSET, 
+			      "prepared-stmt", ps, 
+			      "model-usage", rflags, 
+			      "exec-params", exec_params, NULL);
+        model->priv->cnc = cnc;
+	model->priv->rs_value = rs_value;
+	g_object_ref (cnc);
+
+        return GDA_DATA_MODEL (model);
+}
+
+static GdaRow *
+fetch_next_jdbc_row (GdaJdbcRecordset *model, JNIEnv *jenv, gboolean do_store, GError **error)
+{
+	GValue *jexec_res;
+	gint error_code;
+	gchar *sql_state;
+	GError *lerror = NULL;
+	gboolean row_found;
+
+	/* ask JDBC to fetch the next row and store the values */
+	GdaRow *prow = NULL;
+	GdaJdbcPStmt *ps;
+	ps = GDA_JDBC_PSTMT (GDA_DATA_SELECT (model)->prep_stmt);
+	prow = gda_row_new (_GDA_PSTMT (ps)->ncols);
+
+	jexec_res = jni_wrapper_method_call (jenv, GdaJResultSet__fillNextRow,
+					     model->priv->rs_value, &error_code, &sql_state, &lerror, (jlong) prow);
+	if (!jexec_res) {
+		if (lerror)
+			*error = g_error_copy (lerror);
+		_gda_jdbc_make_error (model->priv->cnc, error_code, sql_state, lerror);
+		return NULL;
+	}
+
+	row_found = g_value_get_boolean (jexec_res);
+	gda_value_free (jexec_res);
+	if (! row_found) {
+		GDA_DATA_SELECT (model)->advertized_nrows = model->priv->next_row_num;
+		return NULL;
+	}
+
+	if (do_store) {
+		/* insert row */
+		gda_data_select_take_row (GDA_DATA_SELECT (model), prow, model->priv->next_row_num);
+	}
+	model->priv->next_row_num ++;
+
+	return prow;
+}
+
+
+/*
+ * Get the number of rows in @model, if possible
+ */
+static gint
+gda_jdbc_recordset_fetch_nb_rows (GdaDataSelect *model)
+{
+	GdaJdbcRecordset *imodel;
+	GdaRow *prow = NULL;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	imodel = GDA_JDBC_RECORDSET (model);
+	if (model->advertized_nrows >= 0)
+		return model->advertized_nrows;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, NULL);
+	if (!jenv) 
+		return model->advertized_nrows;
+
+	for (prow = fetch_next_jdbc_row (imodel, jenv, TRUE, NULL);
+             prow;
+             prow = fetch_next_jdbc_row (imodel, jenv, TRUE, NULL));
+
+	_gda_jdbc_release_jenv (jni_detach);
+	return model->advertized_nrows;
+}
+
+/*
+ * Create a new filled #GdaRow object for the row at position @rownum.
+ *
+ * Each new #GdaRow created is "given" to the #GdaDataSelect implementation using gda_data_select_take_row ().
+ */
+static gboolean 
+gda_jdbc_recordset_fetch_random (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+	GdaJdbcRecordset *imodel;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, NULL);
+	if (!jenv)
+		return FALSE;
+
+	imodel = GDA_JDBC_RECORDSET (model);
+        for (; imodel->priv->next_row_num <= rownum; ) {
+                *prow = fetch_next_jdbc_row (imodel, jenv, TRUE, error);
+                if (!*prow) {
+                        /*if (GDA_DATA_SELECT (model)->advertized_nrows >= 0), it's not an error */
+                        if ((GDA_DATA_SELECT (model)->advertized_nrows >= 0) &&
+                            (imodel->priv->next_row_num < rownum)) {
+                                g_set_error (error, 0,
+                                             GDA_DATA_MODEL_ROW_OUT_OF_RANGE_ERROR,
+                                             _("Row %d not found"), rownum);
+                        }
+			_gda_jdbc_release_jenv (jni_detach);
+                        return FALSE;
+                }
+        }
+
+	_gda_jdbc_release_jenv (jni_detach);
+        return TRUE;
+}
+
+/*
+ * Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
+ *
+ * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
+ * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
+ */
+static gboolean 
+gda_jdbc_recordset_fetch_next (GdaDataSelect *model, GdaRow **prow, gint rownum, GError **error)
+{
+	GdaJdbcRecordset *imodel = (GdaJdbcRecordset*) model;
+	JNIEnv *jenv = NULL;
+	gboolean jni_detach;
+
+	jenv = _gda_jdbc_get_jenv (&jni_detach, NULL);
+	if (!jenv)
+		return FALSE;
+
+	if (*prow)
+                return TRUE;
+
+	if (imodel->priv->tmp_row)
+                g_object_unref (imodel->priv->tmp_row);
+
+        *prow = fetch_next_jdbc_row (imodel, jenv, FALSE, error);
+        imodel->priv->tmp_row = *prow;
+
+	_gda_jdbc_release_jenv (jni_detach);
+ 
+	return TRUE;
+}
+

Added: trunk/providers/jdbc/gda-jdbc-recordset.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-recordset.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,58 @@
+/* GDA Jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_JDBC_RECORDSET_H__
+#define __GDA_JDBC_RECORDSET_H__
+
+#include <libgda/libgda.h>
+#include <providers-support/gda-data-select-priv.h>
+#include "gda-jdbc-pstmt.h"
+
+G_BEGIN_DECLS
+
+#define GDA_TYPE_JDBC_RECORDSET            (gda_jdbc_recordset_get_type())
+#define GDA_JDBC_RECORDSET(obj)            (G_TYPE_CHECK_INSTANCE_CAST (obj, GDA_TYPE_JDBC_RECORDSET, GdaJdbcRecordset))
+#define GDA_JDBC_RECORDSET_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST (klass, GDA_TYPE_JDBC_RECORDSET, GdaJdbcRecordsetClass))
+#define GDA_IS_JDBC_RECORDSET(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GDA_TYPE_JDBC_RECORDSET))
+#define GDA_IS_JDBC_RECORDSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDA_TYPE_JDBC_RECORDSET))
+
+typedef struct _GdaJdbcRecordset        GdaJdbcRecordset;
+typedef struct _GdaJdbcRecordsetClass   GdaJdbcRecordsetClass;
+typedef struct _GdaJdbcRecordsetPrivate GdaJdbcRecordsetPrivate;
+
+struct _GdaJdbcRecordset {
+	GdaDataSelect            model;
+	GdaJdbcRecordsetPrivate *priv;
+};
+
+struct _GdaJdbcRecordsetClass {
+	GdaDataSelectClass       parent_class;
+};
+
+GType         gda_jdbc_recordset_get_type  (void) G_GNUC_CONST;
+GdaDataModel *gda_jdbc_recordset_new       (GdaConnection *cnc, GdaJdbcPStmt *ps, GdaSet *exec_params,
+					    JNIEnv *jenv, GValue *rs_value,
+					    GdaDataModelAccessFlags flags, GType *col_types);
+
+G_END_DECLS
+
+#endif

Added: trunk/providers/jdbc/gda-jdbc-test.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-test.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,204 @@
+#ifdef USING_MINGW
+#define _NO_OLDNAMES
+#endif
+#include <libgda/libgda.h>
+#include <sql-parser/gda-sql-parser.h>
+
+#define PROVNAME "org.postgresql.Driver"
+#define CNCSTRING "jdbc:postgresql:sales"
+#define USERNAME "vmalerba"
+
+#define H2_PROVNAME "org.h2.Driver"
+#define H2_CNCSTRING "jdbc:h2:h2data"
+#define H2_USERNAME "h2"
+
+static void test_generic (const gchar *prov_name, const gchar *cnc_string, const gchar *username);
+static void test_h2 (void);
+
+int
+main (int argc, char **argv)
+{
+	const gchar *prov_name, *cnc_string, *username;
+
+	/* set up test environment */
+	g_setenv ("GDA_TOP_BUILD_DIR", TOP_BUILD_DIR, 0);
+	gda_init ();
+
+	/* generic test */
+	if (argc != 1) {
+		if (argc != 4) {
+			g_print ("%s [<JDBC driver> <cnc string> <username>]\n", argv [0]);
+			return 1;
+		}
+		prov_name = argv [1];
+		cnc_string = argv [2];
+		username = argv [3];
+	}
+	else {
+		prov_name = PROVNAME;
+		cnc_string = CNCSTRING;
+		username = USERNAME;
+	}
+
+	test_generic (prov_name, cnc_string, username);
+	test_h2 ();
+	g_print ("OK\n");
+	return 0;
+}
+
+static void
+run_select (GdaConnection *cnc, const gchar *sql)
+{
+	static GdaSqlParser *parser = NULL;
+	GdaStatement *stmt;
+	GdaDataModel *model;
+	GError *error = NULL;	
+
+	if (!parser)
+		parser = gda_sql_parser_new ();
+
+	stmt = gda_sql_parser_parse_string (parser, sql, NULL, NULL);
+	model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+	if (!model) {
+		g_print ("Error executing statement: %s\n",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+	gda_data_model_dump (model, stdout);
+	g_object_unref (stmt);
+	g_object_unref (model);
+}
+
+static void
+test_h2 (void)
+{
+	GError *error = NULL;
+	GdaConnection *cnc;
+	gchar *real_auth, *tmp;
+
+	tmp = gda_rfc1738_encode (H2_USERNAME);
+	real_auth = g_strdup_printf ("USERNAME=%s", tmp);
+	g_free (tmp);
+	cnc = gda_connection_open_from_string (H2_PROVNAME, "URL=" H2_CNCSTRING, real_auth,
+					       GDA_CONNECTION_OPTIONS_NONE, &error);
+	g_free (real_auth);
+	if (!cnc) {
+		g_print ("Could open connection with the '%s' provider: %s\n", "org.h2.Driver",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+
+	run_select (cnc, "SELECT * FROM t_string");
+	run_select (cnc, "SELECT * FROM t_numbers");
+	run_select (cnc, "SELECT * FROM t_misc");
+	run_select (cnc, "SELECT * FROM t_bin");
+	run_select (cnc, "SELECT * FROM t_others");
+	
+
+	g_object_unref (cnc);
+}
+
+static void
+test_generic (const gchar *prov_name, const gchar *cnc_string, const gchar *username)
+{
+	GdaServerProvider *prov;
+	GError *error = NULL;
+	GdaConnection *cnc;
+
+
+	/* pick up provider */
+	prov = gda_config_get_provider (prov_name, &error);
+	if (!prov) {
+		g_print ("Could not get the '%s' provider: %s\n", prov_name,
+			 error && error->message ? error->message : "No detail");
+		return;
+	}
+
+	/* open connection - failure */
+	g_print ("TEST: Connection opening with failure...\n");
+	cnc = gda_connection_open_from_string (prov_name, "URL=hello", NULL,
+					       GDA_CONNECTION_OPTIONS_NONE, &error);
+	if (cnc) {
+		g_print ("Connection opening should have failed...\n");
+		exit (1);
+	}
+	g_print ("Connection opening error: %s\n",
+		 error && error->message ? error->message : "No detail");
+	if (error) {
+		g_error_free (error);
+		error = NULL;
+	}
+
+	/* open connection - success */
+	g_print ("\nTEST: Connection opening with success...\n");
+	gchar *real_cnc_string, *tmp;
+	tmp = gda_rfc1738_encode (cnc_string);
+	real_cnc_string = g_strdup_printf ("URL=%s", tmp);
+	g_free (tmp);
+
+	gchar *real_auth;
+	tmp = gda_rfc1738_encode (username);
+	real_auth = g_strdup_printf ("USERNAME=%s", tmp);
+	g_free (tmp);
+
+	g_print ("CNC STRING: %s\n", real_cnc_string);
+	cnc = gda_connection_open_from_string (prov_name, real_cnc_string, real_auth,
+					       GDA_CONNECTION_OPTIONS_NONE, &error);
+	g_free (real_cnc_string);
+	g_free (real_auth);
+	if (!cnc) {
+		g_print ("Could open connection with the '%s' provider: %s\n", prov_name,
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+	gda_connection_close (cnc);
+	if (! gda_connection_open (cnc, &error)) {
+		g_print ("Connection re-opening error: %s\n",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+
+	prov = gda_connection_get_provider (cnc);
+	g_print ("Server version: %s\n", gda_server_provider_get_server_version (prov, cnc));
+	g_print ("Server name   : %s\n", gda_server_provider_get_name (prov));
+
+	/* prepared statement */
+	GdaSqlParser *parser;
+	GdaStatement *stmt;
+	g_print ("\nTEST: prepared statement\n");
+	parser = gda_sql_parser_new ();
+	stmt = gda_sql_parser_parse_string (parser, "SELECT * FROM customers", NULL, NULL);
+	g_assert (stmt);
+	if (! gda_connection_statement_prepare (cnc, stmt, &error)) {
+		g_print ("Error preparing statement: %s\n",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+
+	g_print ("\nTEST: execute SELECT statement\n");
+	GdaDataModel *model;
+	model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+	if (!model) {
+		g_print ("Error executing statement: %s\n",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+	gda_data_model_dump (model, stdout);
+	g_object_unref (stmt);
+	g_object_unref (model);
+
+
+	g_print ("\nTEST: execute SELECT statement - 2\n");
+	stmt = gda_sql_parser_parse_string (parser, "SELECT * FROM orders", NULL, NULL);
+	model = gda_connection_statement_execute_select (cnc, stmt, NULL, &error);
+	if (!model) {
+		g_print ("Error executing statement: %s\n",
+			 error && error->message ? error->message : "No detail");
+		exit (1);
+	}
+	gda_data_model_dump (model, stdout);
+	g_object_unref (model);
+
+	g_object_unref (stmt);
+	g_object_unref (cnc);
+}

Added: trunk/providers/jdbc/gda-jdbc-util.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-util.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,142 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <glib/gi18n-lib.h>
+#include "gda-jdbc-util.h"
+
+extern JavaVM *_jdbc_provider_java_vm;
+
+/**
+ * _gda_jdbc_make_error
+ *
+ * warning: STEALS @sql_state and @error.
+ * Create a new #GdaConnectionEvent object and "adds" it to @cnc
+ *
+ * Returns: a new GdaConnectionEvent which must not be unrefed()
+ */
+GdaConnectionEvent *
+_gda_jdbc_make_error (GdaConnection *cnc, gint error_code, gchar *sql_state, GError *error)
+{
+	GdaConnectionEvent *error_ev;
+        GdaConnectionEventCode gda_code = GDA_CONNECTION_EVENT_CODE_UNKNOWN;
+        GdaTransactionStatus *trans;
+
+        error_ev = gda_connection_event_new (GDA_CONNECTION_EVENT_ERROR);
+	if (error) {
+		gda_connection_event_set_description (error_ev,
+						      error->message ? error->message : _("No detail"));
+		g_error_free (error);
+	}
+	gda_connection_event_set_sqlstate (error_ev, sql_state);
+	g_free (sql_state);
+	gda_connection_event_set_code (error_ev, error_code);	
+	gda_connection_event_set_gda_code (error_ev, gda_code);
+        gda_connection_event_set_source (error_ev, "gda-jdbc");
+        gda_connection_add_event (cnc, error_ev);
+
+        /* change the transaction status if there is a problem */
+        trans = gda_connection_get_transaction_status (cnc);
+        if (trans) {
+		/*
+                if ((PQtransactionStatus (pconn) == PQTRANS_INERROR) &&
+                    (trans->state != GDA_TRANSACTION_STATUS_STATE_FAILED))
+                        gda_connection_internal_change_transaction_state (cnc,
+                                                                          GDA_TRANSACTION_STATUS_STATE_FAILED);
+		*/
+        }
+        return error_ev;
+}
+
+/**
+ * _gda_jdbc_get_jenv
+ * @out_needs_detach: SHOULD NOT BE NULL
+ *
+ * Returns: a JNIEnv or %NULL if an error occurred
+ */
+JNIEnv *
+_gda_jdbc_get_jenv (gboolean *out_needs_detach, GError **error)
+{
+	jint atres;
+	JNIEnv *env;
+
+	*out_needs_detach = FALSE;
+	atres = (*_jdbc_provider_java_vm)->GetEnv (_jdbc_provider_java_vm, (void**) &env, JNI_VERSION_1_2);
+	if (atres == JNI_EDETACHED) {
+		if ((*_jdbc_provider_java_vm)->AttachCurrentThread (_jdbc_provider_java_vm, (void**) &env, NULL) < 0)
+			g_set_error (error, 0, 0,
+				     "Could not attach JAVA virtual machine's current thread");
+		else
+			*out_needs_detach = TRUE;
+	}
+	else if (atres == JNI_EVERSION)
+		g_set_error (error, 0, 0,
+			     "Could not attach JAVA virtual machine's current thread");
+	return env;
+}
+
+void
+_gda_jdbc_release_jenv (gboolean needs_detach)
+{
+	if (needs_detach)
+		(*_jdbc_provider_java_vm)->DetachCurrentThread (_jdbc_provider_java_vm);
+}
+
+/*
+ * converts a GType to an INT identifier used to communicate types with JDBC. The corresponding
+ * decoding method on the JAVA side is GdaJValue.proto_type_to_jvalue()
+ *
+ * Any new type added here must also be added to the GdaJValue.proto_type_to_jvalue() method
+ */
+int
+_gda_jdbc_gtype_to_proto_type (GType type)
+{
+	if (type == G_TYPE_STRING)
+		return 1;
+	else if (type == G_TYPE_INT)
+		return 2;
+	else if (type == G_TYPE_CHAR)
+		return 3;
+	else if (type == G_TYPE_DOUBLE)
+		return 4;
+	else if (type == G_TYPE_FLOAT)
+		return 5;
+	else if (type == G_TYPE_BOOLEAN)
+		return 6;
+	else if (type == G_TYPE_DATE)
+		return 7;
+	else if (type == GDA_TYPE_TIME)
+		return 8;
+	else if (type == GDA_TYPE_TIMESTAMP)
+		return 9;
+	else if (type == GDA_TYPE_BINARY)
+		return 10;
+	else if (type == GDA_TYPE_BLOB)
+		return 11;
+	else if (type == G_TYPE_INT64)
+		return 12;
+	else if (type == GDA_TYPE_SHORT)
+		return 13;
+	else if (type == GDA_TYPE_NUMERIC)
+		return 14;
+	else
+		return 0; /* GDA_TYPE_NULL */
+}

Added: trunk/providers/jdbc/gda-jdbc-util.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc-util.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,39 @@
+/* GDA postgres provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *         Vivien Malerba <malerba gnome-db org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __GDA_POSTGRES_UTIL_H__
+#define __GDA_POSTGRES_UTIL_H__
+
+#include "gda-jdbc.h"
+#include <libgda/libgda.h>
+
+G_BEGIN_DECLS
+
+GdaConnectionEvent *_gda_jdbc_make_error   (GdaConnection *cnc, gint error_code, gchar *sql_state, GError *error);
+JNIEnv             *_gda_jdbc_get_jenv     (gboolean *out_needs_detach, GError **error);
+void                _gda_jdbc_release_jenv (gboolean needs_detach);
+
+int                 _gda_jdbc_gtype_to_proto_type (GType type);
+
+G_END_DECLS
+
+#endif
+

Added: trunk/providers/jdbc/gda-jdbc.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-jdbc.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,44 @@
+/* GDA jdbc provider
+ * Copyright (C) 2008 The GNOME Foundation.
+ *
+ * AUTHORS:
+ *      Vivien Malerba <malerba gnome-db org>
+ *
+ * This Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this Library; see the file COPYING.LIB.  If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GDA_JDBC_H__
+#define __GDA_JDBC_H__
+
+/*
+ * Provider name
+ */
+#define JDBC_PROVIDER_NAME "Jdbc"
+
+/* headers necessary for the C API */
+#include <jni.h>
+#include <glib-object.h>
+
+/*
+ * Provider's specific connection data
+ */
+typedef struct {
+	gchar  *server_version;
+	GValue *jcnc_obj; /* JAVA GdaJConnection object */
+	GValue *jmeta_obj; /* JAVA GdaJMeta object */
+} JdbcConnectionData;
+
+#endif

Added: trunk/providers/jdbc/gda-list-jdbc-providers.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/gda-list-jdbc-providers.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,39 @@
+#ifdef USING_MINGW
+#define _NO_OLDNAMES
+#endif
+#include <libgda/libgda.h>
+#define SO_NAME "libgda-jdbc." G_MODULE_SUFFIX
+
+int
+main (int argc, char **argv)
+{
+	GdaDataModel *providers;
+	gint i, nrows;
+	gboolean some_found = FALSE;
+
+	/* set up test environment */
+	g_setenv ("GDA_TOP_BUILD_DIR", TOP_BUILD_DIR, 0);
+	gda_init ();
+
+	providers = gda_config_list_providers ();
+	nrows = gda_data_model_get_n_rows (providers);
+	for (i = 0; i < nrows; i++) {
+		const GValue *sovalue = gda_data_model_get_value_at (providers, 4, i, NULL);
+		g_assert (sovalue);
+		if (g_str_has_suffix (g_value_get_string (sovalue), SO_NAME)) {
+			const GValue *namevalue = gda_data_model_get_value_at (providers, 0, i, NULL);
+			g_assert (namevalue);
+			if (! some_found) {
+				some_found = TRUE;
+				g_print ("Useable JDBC drivers:\n");
+			}
+			g_print ("%s\n", g_value_get_string (namevalue));
+		}
+	}
+	g_object_unref (providers);
+
+	if (! some_found) 
+		g_print ("No useable JDBC driver\n");
+
+	return 0;
+}

Added: trunk/providers/jdbc/h2.java
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/h2.java	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,181 @@
+import java.sql.*;
+import java.util.*;
+import java.io.*;
+
+
+class org_h2_DriverMeta extends GdaJMeta {
+	public org_h2_DriverMeta (Connection cnc) throws Exception {
+		super (cnc);
+		ResultSet rs;
+		rs = cnc.getMetaData().getSchemas();
+		while (rs.next ()) {
+			if (rs.getBoolean (3))
+				schemaAddCurrent (rs.getString (1));
+		}
+	}
+
+	public String getCatalog () throws Exception {
+		return cnc.getCatalog ();
+	}
+
+	public GdaJResultSet getSchemas (String catalog, String schema) throws Exception {
+		return new org_h2_DriverMetaSchemas (this, catalog, schema);
+	}
+
+	public GdaJResultSet getTables (String catalog, String schema, String name) throws Exception {
+		return new org_h2_DriverMetaTables (this, catalog, schema, name);
+	}
+
+	public GdaJResultSet getViews (String catalog, String schema, String name) throws Exception {
+		ResultSet rs;
+		if ((catalog != null) && (schema != null)) {
+			PreparedStatement ps;
+			if (name != null) {
+				ps = cnc.prepareStatement ("SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, VIEW_DEFINITION, CHECK_OPTION, IS_UPDATABLE::boolean FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_CATALOG = ? AND TABLE_SCHEMA = ? AND TABLE_NAME = ?");
+				ps.setString (3, name);
+			}
+			else
+				ps = cnc.prepareStatement ("SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, VIEW_DEFINITION, CHECK_OPTION, IS_UPDATABLE::boolean FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_CATALOG = ? AND TABLE_SCHEMA = ?");
+			ps.setString (1, catalog);
+			ps.setString (2, schema);
+			rs = ps.executeQuery();
+		}
+		else {
+			Statement stmt = cnc.createStatement ();
+			rs = stmt.executeQuery ("SELECT TABLE_CATALOG, TABLE_SCHEMA, TABLE_NAME, VIEW_DEFINITION, CHECK_OPTION, IS_UPDATABLE::boolean FROM INFORMATION_SCHEMA.VIEWS");
+		}
+		//return new GdaJResultSet (rs);
+		return new org_h2_DriverMetaViews (rs);
+	}
+}
+
+/*
+ * Meta data for schemas
+ */
+class org_h2_DriverMetaSchemas extends GdaJMetaResultSet {
+	ResultSet rs;
+	String catalog = null;
+	String schema = null;
+
+	public org_h2_DriverMetaSchemas (GdaJMeta jm, String catalog, String schema) throws Exception {
+		super (4, jm);
+		meta_col_infos.add (new GdaJColumnInfos ("catalog_name", "catalog_name", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_name", "schema_name", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_owner", "owner", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_internal", "is internal", java.sql.Types.BOOLEAN));
+		rs = jm.md.getSchemas ();
+		this.catalog = catalog;
+		this.schema = schema;
+	}
+
+	protected void columnTypesDeclared () {
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.convert_lc = true;
+	}
+
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		if (! rs.next ())
+			return false;
+
+		GdaJValue cv;
+		
+		if (catalog != null) {
+			String s = rs.getString (2);
+			if (s != catalog)
+				return fillNextRow (c_pointer);
+		}
+		if (schema != null) {
+			String s = rs.getString (1);
+			if (s != schema)
+				return fillNextRow (c_pointer);
+		}
+
+		cv = (GdaJValue) col_values.elementAt (0);
+		cv.setCValue (rs, 1, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.setCValue (rs, 0, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.setCBoolean (c_pointer, 3, false);
+
+		return true;
+	}
+}
+
+/*
+ * Meta data for tables
+ */
+class org_h2_DriverMetaTables extends GdaJMetaTables {
+	public org_h2_DriverMetaTables (GdaJMeta jm, String catalog, String schema, String name) throws Exception {
+		super (jm);
+		rs = md.getTables (catalog, schema, name, null);
+	}
+
+	protected void columnTypesDeclared () {
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (2);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (5);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (6);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (7);
+		cv.convert_lc = true;
+	}
+
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		if (! rs.next ())
+			return false;
+
+		GdaJValue cv;
+		
+		cv = (GdaJValue) col_values.elementAt (0);
+		cv.setCValue (rs, 0, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.setCValue (rs, 1, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (2);
+		cv.setCValue (rs, 2, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.setCValue (rs, 3, c_pointer);
+		
+		cv = (GdaJValue) col_values.elementAt (5);
+		cv.setCValue (rs, 4, c_pointer);
+
+		cv = (GdaJValue) col_values.elementAt (6);
+		String ln = GdaJValue.toLower (rs.getString (2) + "." + rs.getString (3));
+		if (jm.schemaIsCurrent (rs.getString (2)))
+			cv.setCString (c_pointer, 6, GdaJValue.toLower (rs.getString (3)));
+		else
+			cv.setCString (c_pointer, 6, ln);
+		cv = (GdaJValue) col_values.elementAt (7);
+		cv.setCString (c_pointer, 7, ln);
+
+		return true;
+	}
+}
+
+/*
+ * Meta data for views
+ */
+class org_h2_DriverMetaViews extends GdaJResultSet {
+	public org_h2_DriverMetaViews (ResultSet rs) throws Exception {
+		super (rs);
+	}
+
+	protected void columnTypesDeclared () {
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.convert_lc = true;
+		cv = (GdaJValue) col_values.elementAt (2);
+		cv.convert_lc = true;
+	}
+}

Added: trunk/providers/jdbc/jdbc_specs_create_table.xml.in
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/jdbc_specs_create_table.xml.in	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,37 @@
+<?xml version="1.0"?>
+<serv_op>
+  <parameters id="TABLE_DEF_P" _name="Table's description">
+    <parameter id="TABLE_NAME" _name="Name" _descr="Table's name" gdatype="gchararray" nullok="FALSE">
+      <gda_value>table_name</gda_value>
+    </parameter>
+  </parameters>
+
+  <!-- list of fields -->
+  <gda_array id="FIELDS_A" _name="Table's columns">
+    <gda_array_field id="COLUMN_NAME" _name="Field name" gdatype="gchararray" nullok="FALSE"/>
+    <gda_array_field id="COLUMN_TYPE" _name="Data type" gdatype="gchararray" hint="datatype" nullok="FALSE"/>
+    <gda_array_field id="COLUMN_NNUL" _name="Not NULL" gdatype="gboolean"/>
+    <gda_array_field id="COLUMN_UNIQUE" _name="Unique" gdatype="gboolean"/>
+    <gda_array_field id="COLUMN_PKEY" _name="Primary key" gdatype="gboolean"/>
+    <gda_array_field id="COLUMN_DEFAULT" _name="Default" _descr="Default value" gdatype="gchararray"/>
+    <gda_array_field id="COLUMN_CHECK" _name="Check" _descr="Check constraint" gdatype="gchararray"/>
+    <gda_array_data>
+        <gda_array_row>
+            <gda_value>id</gda_value>
+            <gda_value>integer</gda_value>
+            <gda_value>TRUE</gda_value>
+            <gda_value>TRUE</gda_value>
+            <gda_value>TRUE</gda_value>
+            <gda_value></gda_value>
+            <gda_value></gda_value>
+        </gda_array_row>
+    </gda_array_data>
+  </gda_array>
+
+  <!-- other table constraints -->
+  <sequence id="TABLE_CONSTRAINTS_S" _name="Global constraints">
+    <parameter id="CONSTRAINT_STRING" name="Constraint" gdatype="gchararray">
+      <gda_value>CHECK (column &gt; 0)</gda_value>
+    </parameter>
+  </sequence>
+</serv_op>

Added: trunk/providers/jdbc/jdbc_specs_dsn.xml.in
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/jdbc_specs_dsn.xml.in	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<data-set-spec>
+  <parameters>
+    <parameter id="URL" _name="Connection URL" _descr="" gdatype="gchararray" nullok="FALSE"/>
+  </parameters>
+</data-set-spec>

Added: trunk/providers/jdbc/jni-globals.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/jni-globals.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,65 @@
+#include <jni-wrapper.h>
+
+#ifndef __JNI_GLOBALS__
+#define __JNI_GLOBALS__
+
+/* GdaJProvider */
+extern jclass GdaJProvider_class;
+extern JniWrapperMethod *GdaJProvider__getDrivers;
+extern JniWrapperMethod *GdaJProvider__openConnection;
+extern JniWrapperMethod *GdaJConnection__prepareStatement;
+
+/* GdaJConnection */
+extern JniWrapperMethod *GdaJConnection__close;
+extern JniWrapperMethod *GdaJConnection__getServerVersion;
+extern JniWrapperMethod *GdaJConnection__executeDirectSQL;
+
+extern JniWrapperMethod *GdaJConnection__begin;
+extern JniWrapperMethod *GdaJConnection__rollback;
+extern JniWrapperMethod *GdaJConnection__commit;
+extern JniWrapperMethod *GdaJConnection__addSavepoint;
+extern JniWrapperMethod *GdaJConnection__rollbackSavepoint;
+extern JniWrapperMethod *GdaJConnection__releaseSavepoint;
+extern JniWrapperMethod *GdaJConnection__getJMeta;
+
+/* GdaJPStmt */
+extern JniWrapperMethod *GdaJPStmt__clearParameters;
+extern JniWrapperMethod *GdaJPStmt__execute;
+extern JniWrapperMethod *GdaJPStmt__getResultSet;
+extern JniWrapperMethod *GdaJPStmt__getImpactedRows;
+extern JniWrapperMethod *GdaJPStmt__declareParamTypes;
+extern JniWrapperMethod *GdaJPStmt__setParameterValue;
+
+/* GdaJResultSet */
+extern JniWrapperMethod *GdaJResultSet__getInfos;
+extern JniWrapperMethod *GdaJResultSet__declareColumnTypes;
+extern JniWrapperMethod *GdaJResultSet__fillNextRow;
+
+/* GdaJResultSetInfos */
+extern JniWrapperField *GdaJResultSetInfos__ncols;
+extern JniWrapperMethod *GdaJResultSetInfos__describeColumn;
+
+/* GdaJColumnInfos */
+extern JniWrapperField *GdaJColumnInfos__col_name;
+extern JniWrapperField *GdaJColumnInfos__col_descr;
+extern JniWrapperField *GdaJColumnInfos__col_type;
+
+/* GdaJBlobOp */
+extern JniWrapperMethod *GdaJBlobOp__read;
+extern JniWrapperMethod *GdaJBlobOp__write;
+extern JniWrapperMethod *GdaJBlobOp__length;
+
+/* GdaInputStream */
+extern jclass GdaInputStream__class;
+
+/* GdaJMeta */
+extern JniWrapperMethod *GdaJMeta__getCatalog;
+extern JniWrapperMethod *GdaJMeta__getSchemas;
+extern JniWrapperMethod *GdaJMeta__getTables;
+extern JniWrapperMethod *GdaJMeta__getViews;
+
+
+/* debug features */
+extern gboolean jvm_describe_exceptions;
+
+#endif

Added: trunk/providers/jdbc/jni-wrapper.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/jni-wrapper.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,1070 @@
+#include <jni-wrapper.h>
+
+gboolean jni_wrapper_describe_exceptions = TRUE;
+
+static jclass            SQLException__class = NULL;
+static JniWrapperMethod *get_message_method = NULL;
+static JniWrapperMethod *get_error_code_method = NULL;
+static JniWrapperMethod *get_sql_state_method = NULL;
+
+#define JNI_WRAPPER_DEBUG
+#undef JNI_WRAPPER_DEBUG
+
+#ifdef G_OS_WIN32
+#define PATH_SEPARATOR ';'
+#else
+#define PATH_SEPARATOR ':'
+#endif
+
+/*
+ * Returns: @iostring if it was not NULL, or a new string if a JAR has been added, or %NULL
+ */
+static GString *
+locate_jars (GString *iostring, const gchar *path)
+{
+	if (g_str_has_suffix (path, ".jar") ||
+	    g_str_has_suffix (path, ".JAR") ||
+	    g_str_has_suffix (path, ".Jar")) {
+		if (!iostring)
+			iostring = g_string_new ("-Djava.class.path=");
+		else
+			g_string_append_c (iostring, PATH_SEPARATOR);
+		g_string_append (iostring, path);
+	}
+	else {
+		GDir *dir;
+		dir = g_dir_open (path, 0, NULL);
+		if (dir) {
+			const gchar *file;
+			for (file = g_dir_read_name (dir); file; file = g_dir_read_name (dir)) {
+				if (g_str_has_suffix (file, ".jar") ||
+				    g_str_has_suffix (file, ".JAR") ||
+				    g_str_has_suffix (file, ".Jar")) {
+					if (!iostring)
+						iostring = g_string_new ("-Djava.class.path=");
+					else
+						g_string_append_c (iostring, PATH_SEPARATOR);
+					g_string_append_printf (iostring, "%s%c%s", path,
+								G_DIR_SEPARATOR, file);
+				}
+			}
+			g_dir_close (dir);
+		}
+	}
+
+	return iostring;
+}
+
+/**
+ * jni_wrapper_create
+ * @out_jvm: a pointer to store the JVM instance (NOT %NULL)
+ * @lib_path: a path to where native libraries may be, or %NULL
+ * @class_path: extra path to add to CLASSPATH, or %NULL
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new JAVA virtual machine and the new associated JNIEnv
+ *
+ * Returns: a new #JNIEnv, or %NULL if an error occurred
+ */
+JNIEnv *
+jni_wrapper_create_vm (JavaVM **out_jvm, CreateJavaVMFunc create_func,
+		       const gchar *lib_path, const gchar *class_path, GError **error)
+{
+	*out_jvm = NULL;
+#ifndef JNI_VERSION_1_2
+	g_set_error (error, 0, 0,
+		     "Java 1.2 or more is needed");
+	return NULL;
+#else
+	GString *classpath = NULL;
+	gint nopt;
+	JavaVMOption options[4];
+	JavaVMInitArgs vm_args;
+	JavaVM *jvm;
+	JNIEnv *env;
+	long result;
+	const gchar *tmp;
+
+	if (!create_func) {
+		g_set_error (error, 0, 0,
+			     "The JNI_CreateJavaVM is not identified (as the create_func argument)");
+		return NULL;
+	}
+
+	gchar * confdir;
+	confdir = g_build_path (G_DIR_SEPARATOR_S, g_get_home_dir (), ".libgda", NULL);
+	classpath = locate_jars (classpath, confdir);
+	g_free (confdir);
+
+	if (class_path) {
+		if (!classpath)
+			classpath = g_string_new ("-Djava.class.path=");
+		g_string_append_c (classpath, PATH_SEPARATOR);
+		g_string_append (classpath, class_path);
+	}
+
+	if ((tmp = g_getenv ("CLASSPATH")) && *tmp) {
+		gchar **arr = g_strsplit (tmp, ":", 0);
+		gchar **ptr;
+		for (ptr = arr; ptr && *ptr; ptr++)
+			classpath = locate_jars (classpath, *ptr);
+		g_strfreev (arr);
+	}
+
+	nopt = 0;
+	if (classpath)
+		options[nopt++].optionString = classpath->str;
+	options[nopt++].optionString = "-Djava.compiler=NONE";
+
+	if (lib_path) 
+		options[nopt++].optionString = g_strdup_printf ("-Djava.library.path=%s", lib_path);
+	vm_args.nOptions = nopt;
+
+	if (g_getenv ("GDA_JAVA_OPTION")) {
+		const gchar *opt = g_getenv ("GDA_JAVA_OPTION");
+		options[vm_args.nOptions].optionString = opt;
+		vm_args.nOptions++;
+	}
+	vm_args.version = JNI_VERSION_1_2;
+	vm_args.options = options;
+
+#ifdef JNI_WRAPPER_DEBUG
+	{
+		gint i;
+		for (i = 0; i < vm_args.nOptions; i++)
+			g_print ("VMOption %d: %s\n", i, options[i].optionString);
+	}
+#endif
+
+	vm_args.ignoreUnrecognized = JNI_FALSE;
+	result = create_func (&jvm,(void **) &env, &vm_args);
+	g_string_free (classpath, TRUE);
+	g_free (options[2].optionString);
+	if ((result == JNI_ERR) || !env) {
+		g_set_error (error, 0, 0,
+			     "Can't invoke the JVM");
+		return NULL;
+	}
+
+	*out_jvm = jvm;
+
+#ifdef JNI_WRAPPER_DEBUG
+	g_print ("JVM loaded\n");
+#endif
+
+	jclass klass;
+	klass = jni_wrapper_class_get (env, "java/lang/Throwable", NULL);
+	if (!klass) 
+		g_warning ("Error loading '%s' class (error messages won't be detailled)",
+			   "java.lang.Throwable");
+	else {
+		get_message_method = jni_wrapper_method_create (env, klass, 
+								"getMessage", "()Ljava/lang/String;", 
+								FALSE, NULL);
+		if (!get_message_method)
+			g_warning ("Error loading '%s' method (error messages won't be detailled)",
+				   "java.lang.Throwable.getMessage");
+		(*env)->DeleteGlobalRef (env, klass);
+	}
+
+	klass = jni_wrapper_class_get (env, "java/sql/SQLException", NULL);
+	if (!klass) 
+		g_warning ("Error loading '%s' class (error messages won't be detailled)",
+			   "java.sql.SqlException");
+	else {
+		SQLException__class = klass;
+		get_error_code_method = jni_wrapper_method_create (env, SQLException__class, 
+								   "getErrorCode", "()I", 
+								   FALSE, NULL);
+		if (!get_error_code_method)
+			g_warning ("Error loading '%s' method (error messages won't be detailled)",
+				   "java.SQLException.getErrorCode");
+
+		get_sql_state_method = jni_wrapper_method_create (env, SQLException__class, 
+								  "getSQLState", "()Ljava/lang/String;", 
+								  FALSE, NULL);
+
+		if (!get_sql_state_method)
+			g_warning ("Error loading '%s' method (error messages won't be detailled)",
+				   "java.SQLException.getSQLState");
+	}
+
+	return env;
+#endif
+}
+
+/**
+ * jni_wrapper_destroy
+ */
+void
+jni_wrapper_destroy_vm (JavaVM *jvm)
+{
+	g_return_if_fail (jvm);
+	(*jvm)->DestroyJavaVM (jvm);
+#ifdef JNI_WRAPPER_DEBUG
+	g_print ("JVM destroyed\n");
+#endif
+}
+
+/**
+ * jni_wrapper_class_create
+ *
+ * Returns: a jclass object as a JNI global reference
+ */
+jclass
+jni_wrapper_class_get (JNIEnv *jenv, const gchar *class_name, GError **error)
+{
+	jclass cls, gcls;
+
+	g_return_val_if_fail (jenv, NULL);
+	cls = (*jenv)->FindClass (jenv, class_name);
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
+#ifdef JNI_WRAPPER_DEBUG
+		g_warning ("Class '%s' NOT found\n", class_name);
+#endif
+		return NULL;
+	}
+
+#ifdef JNI_WRAPPER_DEBUG
+	g_print ("Class '%s' found\n", class_name);
+#endif
+	gcls = (*jenv)->NewGlobalRef (jenv, cls);
+	(*jenv)-> DeleteLocalRef (jenv, cls);
+
+	return gcls;
+}
+
+/**
+ * jni_wrapper_instantiate_object
+ *
+ * Returns: a new GValue with a pointer to the new java object
+ */
+GValue *
+jni_wrapper_instantiate_object (JNIEnv *jenv, jclass klass, const gchar *signature, 
+				GError **error, ...)
+{
+	JniWrapperMethod *method;
+	GValue *retval;
+	va_list args;
+	JavaVM *jvm;
+
+	g_return_val_if_fail (klass, NULL);
+
+	method = jni_wrapper_method_create (jenv, klass, "<init>", signature, FALSE, error);
+	if (!method)
+		return NULL;
+
+	if ((*jenv)->GetJavaVM (jenv, &jvm))
+		g_error ("Could not attach JAVA virtual machine's current thread");
+	
+	retval = g_new0 (GValue, 1);
+	g_value_init (retval, GDA_TYPE_JNI_OBJECT);
+
+	va_start (args, error);
+	gda_value_set_jni_object (retval, jvm, jenv, 
+				  (*jenv)->NewObjectV (jenv, klass, method->mid, args));
+	va_end (args);
+	
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
+		g_value_unset (retval);
+		g_free (retval);
+		retval = NULL;
+	}
+
+	jni_wrapper_method_free (jenv, method);
+	return retval;
+}
+
+/**
+ * jni_wrapper_handle_exception
+ * @jenv:
+ * @out_error_code: place to store an error code, or %NULL
+ * @out_sql_state: place to store a (new) sql state string, or %NULL
+ * @error: place to store errors, or %NULL
+ *
+ * Returns: TRUE if there was an exception, and clears the exceptions
+ */
+gboolean
+jni_wrapper_handle_exception (JNIEnv *jenv, gint *out_error_code, gchar **out_sql_state, GError **error)
+{
+	jthrowable exc;
+	GValue *exc_value = NULL;
+
+	if (out_error_code)
+		*out_error_code = 0;
+	if (out_sql_state)
+		*out_sql_state = NULL;
+
+	exc = (*jenv)->ExceptionOccurred (jenv);
+	if (!exc)
+		return FALSE; /* no exception */
+
+	if (jni_wrapper_describe_exceptions) {
+		static gint c = 0;
+		g_print ("JAVA EXCEPTION %d\n", c);
+		(*jenv)->ExceptionDescribe (jenv);
+		g_print ("JAVA EXCEPTION %d\n", c);
+		c++;
+	}
+
+	if (out_error_code || out_sql_state || error) {
+		JavaVM *jvm;
+		exc_value = g_new0 (GValue, 1);
+		g_value_init (exc_value, GDA_TYPE_JNI_OBJECT);
+		if ((*jenv)->GetJavaVM (jenv, &jvm))
+			g_error ("Could not attach JAVA virtual machine's current thread");
+
+		gda_value_set_jni_object (exc_value, jvm, jenv, exc);
+	}
+	(*jenv)->ExceptionClear (jenv);
+
+	if (out_error_code || out_sql_state) {
+		if ((*jenv)->IsInstanceOf (jenv, exc, SQLException__class)) {
+			if (out_error_code) {
+				GValue *res;				
+				
+				res = jni_wrapper_method_call (jenv, get_error_code_method, exc_value, 
+							       NULL, NULL, NULL);
+				if (res) {
+					if (G_VALUE_TYPE (res) == G_TYPE_INT)
+						*out_error_code = g_value_get_int (res);
+					g_value_unset (res);
+					g_free (res);
+				}
+			}
+			if (out_sql_state) {
+				GValue *res;				
+				
+				res = jni_wrapper_method_call (jenv, get_sql_state_method, exc_value, 
+							       NULL, NULL, NULL);
+				if (res) {
+					if (G_VALUE_TYPE (res) == G_TYPE_STRING)
+						*out_sql_state = g_value_dup_string (res);
+					g_value_unset (res);
+					g_free (res);
+				}
+			}
+		}
+	}
+	(*jenv)->DeleteLocalRef(jenv, exc);
+
+	if (error) {
+		if (get_message_method) {
+			GValue *res;
+
+			res = jni_wrapper_method_call (jenv, get_message_method, exc_value, NULL, NULL, NULL);
+			
+			if (res) {
+				if (G_VALUE_TYPE (res) == G_TYPE_STRING) {
+					g_set_error (error, 0, 0, "%s", g_value_get_string (res));
+					g_value_unset (res);
+					g_free (res);
+				}
+				else {
+					g_value_unset (res);
+					g_free (res);
+					goto fallback;
+				}
+			}
+			else
+				goto fallback;
+		}
+		else
+			goto fallback;
+	}
+
+	if (exc_value) {
+		g_value_unset (exc_value);
+		g_free (exc_value);
+	}
+
+	return TRUE;
+
+ fallback:
+	g_set_error (error, 0, 0,
+		     "An exception occurred");
+	if (exc_value) {
+		g_value_unset (exc_value);
+		g_free (exc_value);
+	}
+	(*jenv)->DeleteLocalRef(jenv, exc);
+	return TRUE;
+}
+
+/**
+ * jni_wrapper_method_create
+ * @jenv:
+ * @klass:
+ * @method_name: name of the requested method
+ * @signature: methods's signature (use "java -p -s <classname>" to get it)
+ * @is_static: TRUE if the requested method is a class method (and FALSE if it's an instance method)
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #JniWrapperMethod structure
+ */
+JniWrapperMethod *
+jni_wrapper_method_create (JNIEnv *jenv, jclass klass, 
+			   const gchar *method_name, const gchar *signature,
+			   gboolean is_static, GError **error)
+{
+	JniWrapperMethod *method;
+	jmethodID mid;
+	const gchar *ptr;
+	g_return_val_if_fail (klass, NULL);
+	if (is_static) 
+		mid = (*jenv)->GetStaticMethodID (jenv, klass, method_name, signature);
+	else 
+		mid = (*jenv)->GetMethodID (jenv, klass, method_name, signature);
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error))
+		return NULL;
+
+	method = g_new0 (JniWrapperMethod, 1);
+	method->klass = (*jenv)->NewGlobalRef (jenv, klass);
+	method->is_static = is_static;
+	method->mid = mid;
+
+	for (ptr = signature; *ptr && (*ptr != ')'); ptr++);
+	g_assert (*ptr);
+	ptr++;
+	method->ret_type = g_strdup (ptr);
+
+	return method;
+}
+
+/**
+ * jni_wrapper_method_call
+ * @jenv:
+ * @method:
+ * @object: instance on which the method is executed, or %NULL for a static method call
+ * @out_error_code: place to store an error code, or %NULL
+ * @out_sql_state: place to store a (new) sql state string, or %NULL
+ * @error: a place to store errors, or %NULL
+ * @...: methods' arguments, USED AS IS by the JNI
+ *
+ * Executes an instance method.
+ *
+ * Returns: a GValue (may return a GDA_TYPE_NULL value for functions returning void), or %NULL if an error occurred
+ */
+GValue *
+jni_wrapper_method_call (JNIEnv *jenv, JniWrapperMethod *method, GValue *object, 
+			 gint *out_error_code, gchar **out_sql_state, GError **error, ...)
+{
+	GValue *retval;
+	va_list args;
+	jobject jobj = NULL;
+	g_return_val_if_fail (method, NULL);
+	if (method->is_static)
+		g_return_val_if_fail (!object, NULL);
+	else {
+		g_return_val_if_fail (object, NULL);
+		g_return_val_if_fail (G_VALUE_TYPE (object) == GDA_TYPE_JNI_OBJECT, NULL);
+		jobj = gda_value_get_jni_object (object);
+		g_return_val_if_fail (jobj, NULL);
+	}
+
+	if (out_error_code)
+		*out_error_code = 0;
+	if (out_sql_state)
+		*out_sql_state = NULL;
+
+	retval = g_new0 (GValue, 1);
+
+	/* actual method call */
+	va_start (args, error);
+	switch (*method->ret_type) {
+	case 'V':
+		if (method->is_static)
+			(*jenv)->CallStaticVoidMethodV (jenv, method->klass, method->mid, args);
+		else
+			(*jenv)->CallVoidMethodV (jenv, jobj, method->mid, args);
+		break;
+	case '[':
+	case 'L': 
+		if (!strcmp (method->ret_type, "Ljava/lang/String;")) {
+			jstring string;
+			gchar *str;
+			gint len;
+			if (method->is_static)
+				string = (*jenv)->CallStaticObjectMethodV (jenv, method->klass, 
+									   method->mid, args);
+			else
+				string = (*jenv)->CallObjectMethodV (jenv, jobj, method->mid, args);
+			if (string) {
+				g_value_init (retval, G_TYPE_STRING);
+				len = (*jenv)->GetStringUTFLength (jenv, string);
+				str = g_new (gchar, len + 1);
+				(*jenv)->GetStringUTFRegion (jenv, string, 0, len, str);
+				g_value_take_string (retval, str);
+
+				(*jenv)-> DeleteLocalRef (jenv, string);
+			}
+		}
+		else {
+			JavaVM *jvm;
+			if ((*jenv)->GetJavaVM (jenv, &jvm))
+				g_error ("Could not attach JAVA virtual machine's current thread");
+			g_value_init (retval, GDA_TYPE_JNI_OBJECT);
+			if (method->is_static)
+				gda_value_set_jni_object (retval, jvm, jenv, 
+							  (*jenv)->CallStaticObjectMethodV (jenv, method->klass, 
+											    method->mid, args));
+			else
+				gda_value_set_jni_object (retval, jvm, jenv, 
+							  (*jenv)->CallObjectMethodV (jenv, 
+										      jobj, method->mid, args));
+		}
+		break;
+	case 'Z':
+		g_value_init (retval, G_TYPE_BOOLEAN);
+		if (method->is_static)
+			g_value_set_boolean (retval,
+					     (*jenv)->CallStaticBooleanMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_boolean (retval,
+					     (*jenv)->CallBooleanMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'B':
+		g_value_init (retval, G_TYPE_CHAR);
+		if (method->is_static)
+			g_value_set_char (retval,
+					  (*jenv)->CallStaticByteMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_char (retval,
+					  (*jenv)->CallByteMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'C':
+		g_value_init (retval, G_TYPE_INT); // FIXME: should be an unsigned 16 bits value
+		if (method->is_static)
+			g_value_set_int (retval,
+					 (*jenv)->CallStaticCharMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_int (retval,
+					 (*jenv)->CallCharMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'S':
+		g_value_init (retval, G_TYPE_INT); // FIXME: should be a signed 16 bits value
+		if (method->is_static)
+			g_value_set_int (retval,
+					 (*jenv)->CallStaticShortMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_int (retval,
+					 (*jenv)->CallShortMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'I':
+		g_value_init (retval, G_TYPE_INT);
+		if (method->is_static)
+			g_value_set_int (retval, 
+					 (*jenv)->CallStaticIntMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_int (retval, 
+					 (*jenv)->CallIntMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'J':
+		g_value_init (retval, G_TYPE_INT64);
+		if (method->is_static)
+			g_value_set_int64 (retval,
+				   (*jenv)->CallStaticLongMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_int64 (retval,
+					   (*jenv)->CallLongMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'F':
+		g_value_init (retval, G_TYPE_FLOAT);
+		if (method->is_static)
+			g_value_set_float (retval,
+					   (*jenv)->CallStaticFloatMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_float (retval,
+					   (*jenv)->CallFloatMethodV (jenv, jobj, method->mid, args));
+		break;
+	case 'D':
+		g_value_init (retval, G_TYPE_DOUBLE);
+		if (method->is_static)
+			g_value_set_double (retval,
+					    (*jenv)->CallStaticDoubleMethodV (jenv, method->klass, method->mid, args));
+		else
+			g_value_set_double (retval,
+					    (*jenv)->CallDoubleMethodV (jenv, jobj, method->mid, args));
+		break;
+	default:
+		(*jenv)->FatalError (jenv, "illegal descriptor");
+	}
+	va_end (args);
+
+	if (jni_wrapper_handle_exception (jenv, out_error_code, out_sql_state, error)) {
+		if (G_VALUE_TYPE (retval) != 0)
+			g_value_unset (retval);
+		g_free (retval);
+		return NULL;
+	}
+ 
+	return retval;
+}
+
+/**
+ * jni_wrapper_method_free
+ * @jenv:
+ * @method:
+ *
+ */
+void
+jni_wrapper_method_free (JNIEnv *jenv, JniWrapperMethod *method)
+{
+	g_return_if_fail (method);
+	(*jenv)->DeleteGlobalRef (jenv, method->klass);
+	g_free (method->ret_type);
+	g_free (method);
+}
+
+/**
+ * jni_wrapper_field_create
+ * @jenv:
+ * @klass:
+ * @field_name: name of the requested field
+ * @signature: fields's signature (use "java -p -s <classname>" to get it)
+ * @is_static: TRUE if the requested field is a class field (and FALSE if it's an instance field)
+ * @error: a place to store errors, or %NULL
+ *
+ * Creates a new #JniWrapperField structure
+ */
+JniWrapperField *
+jni_wrapper_field_create (JNIEnv *jenv, jclass klass, 
+			   const gchar *field_name, const gchar *signature,
+			   gboolean is_static, GError **error)
+{
+	JniWrapperField *field;
+	jfieldID fid;
+
+	g_return_val_if_fail (klass, NULL);
+	if (is_static) 
+		fid = (*jenv)->GetStaticFieldID (jenv, klass, field_name, signature);
+	else 
+		fid = (*jenv)->GetFieldID (jenv, klass, field_name, signature);
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error))
+		return NULL;
+
+	field = g_new0 (JniWrapperField, 1);
+	field->klass = (*jenv)->NewGlobalRef (jenv, klass);
+	field->is_static = is_static;
+	field->fid = fid;
+
+	field->type = g_strdup (signature);
+
+	return field;
+}
+
+
+/**
+ * jni_wrapper_field_get
+ * @jenv:
+ * @field:
+ * @object: instance of which the field is to be obtained, or %NULL for a static field
+ * @error: a place to store errors, or %NULL
+ *
+ * Set the value of a static field or an instance's field.
+ *
+ * Returns: a GValue (may return a GDA_TYPE_NULL value for functions returning void), or %NULL if an error occurred
+ */
+GValue *
+jni_wrapper_field_get (JNIEnv *jenv, JniWrapperField *field, GValue *object, GError **error)
+{
+	GValue *retval;
+	jobject jobj = NULL;
+	g_return_val_if_fail (field, NULL);
+	if (field->is_static)
+		g_return_val_if_fail (!object, NULL);
+	else {
+		g_return_val_if_fail (object, NULL);
+		g_return_val_if_fail (G_VALUE_TYPE (object) == GDA_TYPE_JNI_OBJECT, NULL);
+		jobj = gda_value_get_jni_object (object);
+		g_return_val_if_fail (jobj, NULL);
+	}
+
+	retval = g_new0 (GValue, 1);
+	
+	switch (*field->type) {
+	case '[':
+	case 'L': 
+		if (!strcmp (field->type, "Ljava/lang/String;")) {
+			jstring string;
+			gchar *str;
+			gint len;
+			if (field->is_static)
+				string = (*jenv)->GetStaticObjectField (jenv, field->klass, field->fid);
+			else
+				string = (*jenv)->GetObjectField (jenv, jobj, field->fid);
+			if (string) {
+				g_value_init (retval, G_TYPE_STRING);
+				len = (*jenv)->GetStringUTFLength (jenv, string);
+				str = g_new (gchar, len + 1);
+				(*jenv)->GetStringUTFRegion (jenv, string, 0, len, str);
+				g_value_take_string (retval, str);
+
+				(*jenv)-> DeleteLocalRef (jenv, string);
+			}
+		}
+		else {
+			JavaVM *jvm;
+			if ((*jenv)->GetJavaVM (jenv, &jvm))
+				g_error ("Could not attach JAVA virtual machine's current thread");
+			g_value_init (retval, GDA_TYPE_JNI_OBJECT);
+			if (field->is_static)
+				gda_value_set_jni_object (retval, jvm, jenv, 
+							  (*jenv)->GetStaticObjectField (jenv, field->klass, field->fid));
+			else
+				gda_value_set_jni_object (retval, jvm, jenv, 
+							  (*jenv)->GetObjectField (jenv, jobj, field->fid));
+		}
+		break;
+	case 'Z':
+		g_value_init (retval, G_TYPE_BOOLEAN);
+		if (field->is_static)
+			g_value_set_boolean (retval,
+					     (*jenv)->GetStaticBooleanField (jenv, field->klass, field->fid));
+		else
+			g_value_set_boolean (retval,
+					     (*jenv)->GetBooleanField (jenv, jobj, field->fid));
+		break;
+	case 'B':
+		g_value_init (retval, G_TYPE_CHAR);
+		if (field->is_static)
+			g_value_set_char (retval,
+					  (*jenv)->GetStaticByteField (jenv, field->klass, field->fid));
+		else
+			g_value_set_char (retval,
+					  (*jenv)->GetByteField (jenv, jobj, field->fid));
+		break;
+	case 'C':
+		g_value_init (retval, G_TYPE_INT); // FIXME: should be an unsigned 16 bits value
+		if (field->is_static)
+			g_value_set_int (retval,
+					 (*jenv)->GetStaticCharField (jenv, field->klass, field->fid));
+		else
+			g_value_set_int (retval,
+					 (*jenv)->GetCharField (jenv, jobj, field->fid));
+		break;
+	case 'S':
+		g_value_init (retval, G_TYPE_INT); // FIXME: should be a signed 16 bits value
+		if (field->is_static)
+			g_value_set_int (retval,
+					 (*jenv)->GetStaticShortField (jenv, field->klass, field->fid));
+		else
+			g_value_set_int (retval,
+					 (*jenv)->GetShortField (jenv, jobj, field->fid));
+		break;
+	case 'I':
+		g_value_init (retval, G_TYPE_INT);
+		if (field->is_static)
+			g_value_set_int (retval, 
+					 (*jenv)->GetStaticIntField (jenv, field->klass, field->fid));
+		else
+			g_value_set_int (retval, 
+					 (*jenv)->GetIntField (jenv, jobj, field->fid));
+		break;
+	case 'J':
+		g_value_init (retval, G_TYPE_INT64);
+		if (field->is_static)
+			g_value_set_int64 (retval,
+				   (*jenv)->GetStaticLongField (jenv, field->klass, field->fid));
+		else
+			g_value_set_int64 (retval,
+					   (*jenv)->GetLongField (jenv, jobj, field->fid));
+		break;
+	case 'F':
+		g_value_init (retval, G_TYPE_FLOAT);
+		if (field->is_static)
+			g_value_set_float (retval,
+					   (*jenv)->GetStaticFloatField (jenv, field->klass, field->fid));
+		else
+			g_value_set_float (retval,
+					   (*jenv)->GetFloatField (jenv, jobj, field->fid));
+		break;
+	case 'D':
+		g_value_init (retval, G_TYPE_DOUBLE);
+		if (field->is_static)
+			g_value_set_double (retval,
+					    (*jenv)->GetStaticDoubleField (jenv, field->klass, field->fid));
+		else
+			g_value_set_double (retval,
+					    (*jenv)->GetDoubleField (jenv, jobj, field->fid));
+		break;
+	default:
+		(*jenv)->FatalError (jenv, "illegal descriptor");
+	}
+
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) {
+		if (G_VALUE_TYPE (retval) != 0)
+			g_value_unset (retval);
+		g_free (retval);
+		return NULL;
+	}
+ 
+	return retval;
+}
+
+/**
+ * jni_wrapper_field_set
+ * @jenv:
+ * @field:
+ * @object: instance of which the field is to be obtained, or %NULL for a static field
+ * @value: a #GValue to set the field to
+ * @error: a place to store errors, or %NULL
+ *
+ * Set the value of a static field or an instance's field.
+ *
+ * Returns: TRUE if no error occurred
+ */
+gboolean
+jni_wrapper_field_set (JNIEnv *jenv, JniWrapperField *field, 
+		       GValue *object, const GValue *value, GError **error)
+{
+	jobject jobj = NULL;
+		
+	g_return_val_if_fail (field, FALSE);
+	g_return_val_if_fail (value, FALSE);
+	if (field->is_static)
+		g_return_val_if_fail (!object, FALSE);
+	else {
+		g_return_val_if_fail (object, FALSE);
+		g_return_val_if_fail (G_VALUE_TYPE (object) == GDA_TYPE_JNI_OBJECT, FALSE);
+		jobj = gda_value_get_jni_object (object);
+		g_return_val_if_fail (jobj, FALSE);
+	}
+
+	switch (*field->type) {
+	case '[':
+	case 'L': 
+		if (!strcmp (field->type, "Ljava/lang/String;")) {
+			jstring string;
+
+			if (G_VALUE_TYPE (value) == G_TYPE_STRING) {
+				string = (*jenv)->NewStringUTF (jenv, g_value_get_string (value));
+				if (field->is_static)
+					(*jenv)->SetStaticObjectField (jenv, field->klass, field->fid, string);
+				else
+					(*jenv)->SetObjectField (jenv, jobj, field->fid, string);
+				(*jenv)-> DeleteLocalRef (jenv, string);
+			}
+			else if (G_VALUE_TYPE (value) == 0) {
+				if (field->is_static)
+					(*jenv)->SetStaticObjectField (jenv, field->klass, field->fid, NULL);
+				else
+					(*jenv)->SetObjectField (jenv, jobj, field->fid, NULL);
+			}
+			else
+				goto wrong_type;
+		}
+		else {
+			if (G_VALUE_TYPE (value) == GDA_TYPE_JNI_OBJECT) {
+				if (field->is_static)
+					(*jenv)->SetStaticObjectField (jenv, field->klass, field->fid,
+								       gda_value_get_jni_object (value));
+				else
+					(*jenv)->SetObjectField (jenv, jobj, field->fid,
+								 gda_value_get_jni_object (value));
+			}
+			else if (G_VALUE_TYPE (value) == 0) {
+				if (field->is_static)
+					(*jenv)->SetStaticObjectField (jenv, field->klass, field->fid, NULL);
+				else
+					(*jenv)->SetObjectField (jenv, jobj, field->fid, NULL);
+			}
+			else
+				goto wrong_type;
+		}
+		break;
+	case 'Z':
+		if (G_VALUE_TYPE (value) != G_TYPE_BOOLEAN)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticBooleanField (jenv, field->klass, field->fid, g_value_get_boolean (value));
+		else
+			(*jenv)->SetBooleanField (jenv, jobj, field->fid, g_value_get_boolean (value));
+		break;
+	case 'B':
+		if (G_VALUE_TYPE (value) != G_TYPE_CHAR)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticByteField (jenv, field->klass, field->fid, g_value_get_char (value));
+		else
+			(*jenv)->SetByteField (jenv, jobj, field->fid, g_value_get_char (value));
+		break;
+	case 'C':
+		if (G_VALUE_TYPE (value) != G_TYPE_INT)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticCharField (jenv, field->klass, field->fid, g_value_get_int (value));
+		else
+			(*jenv)->SetCharField (jenv, jobj, field->fid, g_value_get_int (value));
+		break;
+	case 'S':
+		if (G_VALUE_TYPE (value) != G_TYPE_INT)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticShortField (jenv, field->klass, field->fid, g_value_get_int (value));
+		else
+			(*jenv)->SetShortField (jenv, jobj, field->fid, g_value_get_int (value));
+		break;
+	case 'I':
+		if (G_VALUE_TYPE (value) != G_TYPE_INT)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticIntField (jenv, field->klass, field->fid, g_value_get_int (value));
+		else
+			(*jenv)->SetIntField (jenv, jobj, field->fid, g_value_get_int (value));
+		break;
+	case 'J':
+		if (G_VALUE_TYPE (value) != G_TYPE_INT64)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticLongField (jenv, field->klass, field->fid, g_value_get_int64 (value));
+		else
+			(*jenv)->SetLongField (jenv, jobj, field->fid, g_value_get_int64 (value));
+		break;
+	case 'F':
+		if (G_VALUE_TYPE (value) != G_TYPE_FLOAT)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticFloatField (jenv, field->klass, field->fid, g_value_get_float (value));
+		else
+			(*jenv)->SetFloatField (jenv, jobj, field->fid, g_value_get_float (value));
+		break;
+	case 'D':
+		if (G_VALUE_TYPE (value) != G_TYPE_DOUBLE)
+			goto wrong_type;
+		if (field->is_static)
+			(*jenv)->SetStaticDoubleField (jenv, field->klass, field->fid, g_value_get_double (value));
+		else
+			(*jenv)->SetDoubleField (jenv, jobj, field->fid, g_value_get_double (value));
+		break;
+	default:
+		(*jenv)->FatalError (jenv, "illegal descriptor");
+	}
+
+	if (jni_wrapper_handle_exception (jenv, NULL, NULL, error)) 
+		return FALSE;
+ 
+	return TRUE;
+
+ wrong_type:
+	g_set_error (error, 0, 0,
+		     "Wrong value type");
+	return FALSE;
+}
+
+/**
+ * jni_wrapper_field_free
+ * @jenv:
+ * @field:
+ *
+ */
+void
+jni_wrapper_field_free (JNIEnv *jenv, JniWrapperField *field)
+{
+	g_return_if_fail (field);
+	(*jenv)->DeleteGlobalRef (jenv, field->klass);
+	g_free (field->type);
+	g_free (field);
+}
+
+/*
+ * jobject wrapper in a GValue
+ */
+jobject
+gda_value_get_jni_object (const GValue *value)
+{
+	GdaJniObject *jnio = (GdaJniObject*) g_value_get_boxed (value);
+
+	g_return_val_if_fail (jnio, NULL);
+	return jnio->jobj;
+}
+
+GValue  *
+gda_value_new_jni_object (JavaVM *jvm, JNIEnv *env, jobject jni_object)
+{
+	GValue *value;
+	g_return_val_if_fail (jvm, NULL);
+	g_return_val_if_fail (env, NULL);
+	value = g_new0 (GValue, 1);
+	g_value_init (value, GDA_TYPE_JNI_OBJECT);
+	gda_value_set_jni_object (value, jvm, env, jni_object);
+	return value;
+}
+
+void
+gda_value_set_jni_object (GValue *value, JavaVM *jvm, JNIEnv *env, jobject jni_object)
+{
+	GdaJniObject *jnio;
+
+	jnio = g_new (GdaJniObject, 1);
+	jnio->jvm = jvm;
+	if (jni_object) 
+		jnio->jobj = (*env)->NewGlobalRef (env, jni_object);
+	else
+		jnio->jobj = NULL;
+	g_value_set_boxed (value, jnio);
+}
+
+GType
+gda_jni_object_get_type (void)
+{
+	static GType type = 0;
+	
+        if (G_UNLIKELY (type == 0)) {
+                type = g_boxed_type_register_static ("GdaJniObject",
+                                                     (GBoxedCopyFunc) gda_jni_object_copy,
+                                                     (GBoxedFreeFunc) gda_jni_object_free);
+        }
+
+        return type;
+}
+
+gpointer
+gda_jni_object_copy (gpointer boxed)
+{
+	JNIEnv *env;
+	GdaJniObject *src = (GdaJniObject*) boxed;
+	GdaJniObject *copy;
+	jint atres;
+
+	atres = (*src->jvm)->GetEnv (src->jvm, (void**) &env, JNI_VERSION_1_2);
+	if (atres == JNI_EDETACHED) {
+		if ((*src->jvm)->AttachCurrentThread (src->jvm, (void**) &env, NULL) < 0)
+			g_error ("Could not attach JAVA virtual machine's current thread");
+	}
+	else if (atres == JNI_EVERSION)
+		g_error ("Could not attach JAVA virtual machine's current thread");
+
+	copy = g_new (GdaJniObject, 1);
+	copy->jvm = src->jvm;
+	copy->jobj = (*env)->NewGlobalRef(env, src->jobj);
+
+	if (atres == JNI_EDETACHED)
+		(*src->jvm)->DetachCurrentThread (src->jvm);
+
+	return (gpointer) copy;
+}
+
+void
+gda_jni_object_free (gpointer boxed)
+{
+	JNIEnv *env;
+	GdaJniObject *jnio = (GdaJniObject*) boxed;
+
+	if (jnio->jobj) {
+		jint atres;
+		
+		atres = (*jnio->jvm)->GetEnv (jnio->jvm, (void**) &env, JNI_VERSION_1_2);
+		if (atres == JNI_EDETACHED) {
+			if ((*jnio->jvm)->AttachCurrentThread (jnio->jvm, (void**) &env, NULL) < 0)
+				g_error ("Could not attach JAVA virtual machine's current thread");
+		}
+		else if (atres == JNI_EVERSION)
+			g_error ("Could not attach JAVA virtual machine's current thread");
+		
+		(*env)->DeleteGlobalRef (env, jnio->jobj);
+		if (atres == JNI_EDETACHED)
+			(*jnio->jvm)->DetachCurrentThread (jnio->jvm);
+	}
+	g_free (jnio);
+}

Added: trunk/providers/jdbc/jni-wrapper.h
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/jni-wrapper.h	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,77 @@
+#include <glib.h>
+#include <glib-object.h>
+#include <stdlib.h>
+#include <string.h>
+#include <jni.h>
+#include <glib/gstdio.h>
+
+#ifndef __JNI_WRAPPER__
+#define __JNI_WRAPPER__
+
+/*
+ * general functions
+ */
+typedef jint (*CreateJavaVMFunc) (JavaVM **, void **, void *);
+
+JNIEnv           *jni_wrapper_create_vm (JavaVM **out_jvm, CreateJavaVMFunc create_func,
+					 const gchar *lib_path, 
+					 const gchar *class_path, GError **error);
+void              jni_wrapper_destroy_vm (JavaVM *jvm);
+gboolean          jni_wrapper_handle_exception (JNIEnv *jvm, gint *out_error_code, 
+						gchar **out_sql_state, GError **error);
+
+jclass            jni_wrapper_class_get (JNIEnv *jvm, const gchar *class_name, GError **error);
+GValue           *jni_wrapper_instantiate_object (JNIEnv *jenv, jclass klass,
+						  const gchar *signature, GError **error, ...);
+
+/*
+ * methods
+ */
+typedef struct {
+	jclass    klass; /* JNI global reference */
+	gchar    *ret_type;
+	gboolean  is_static;
+	jmethodID mid;
+} JniWrapperMethod;
+JniWrapperMethod *jni_wrapper_method_create (JNIEnv *jenv, jclass jklass, 
+					     const gchar *method_name, const gchar *signature,
+					     gboolean is_static, GError **error);
+GValue           *jni_wrapper_method_call (JNIEnv *jenv, JniWrapperMethod *method, GValue *object, 
+					   gint *out_error_code, gchar **out_sql_state, GError **error, ...);
+void              jni_wrapper_method_free (JNIEnv *jenv, JniWrapperMethod *method);
+
+/*
+ * fields access
+ */
+typedef struct {
+	jclass    klass; /* JNI global reference */
+	gchar    *type;
+	gboolean  is_static;
+	jfieldID  fid;
+} JniWrapperField;
+JniWrapperField  *jni_wrapper_field_create (JNIEnv *jenv, jclass jklass, 
+					     const gchar *field_name, const gchar *signature,
+					     gboolean is_static, GError **error);
+GValue           *jni_wrapper_field_get (JNIEnv *jenv, JniWrapperField *field, 
+					 GValue *object, GError **error);
+gboolean          jni_wrapper_field_set (JNIEnv *jenv, JniWrapperField *field, 
+					 GValue *object, const GValue *value, GError **error);
+void              jni_wrapper_field_free (JNIEnv *jenv, JniWrapperField *field);
+
+
+/*
+ * jobject wrapper in a GValue
+ */
+#define GDA_TYPE_JNI_OBJECT (gda_jni_object_get_type())
+typedef struct {
+	JavaVM  *jvm;
+	jobject  jobj;
+} GdaJniObject;
+jobject  gda_value_get_jni_object (const GValue *value);
+GValue  *gda_value_new_jni_object (JavaVM *jvm, JNIEnv *env, jobject jni_object);
+void     gda_value_set_jni_object (GValue *value, JavaVM *jvm, JNIEnv *env, jobject jni_object);
+GType    gda_jni_object_get_type (void) G_GNUC_CONST;
+gpointer gda_jni_object_copy (gpointer boxed) G_GNUC_CONST;
+void     gda_jni_object_free (gpointer boxed) G_GNUC_CONST;
+
+#endif

Added: trunk/providers/jdbc/libgda-jdbc-4.0.pc.in
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/libgda-jdbc-4.0.pc.in	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,9 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+
+Name: libgda-jdbc- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Description: GDA (GNOME Data Access) JDBC provider
+Requires: libgda- GDA_ABI_MAJOR_VERSION@  GDA_ABI_MINOR_VERSION@
+Version: @VERSION@

Added: trunk/providers/jdbc/libmain.c
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/libmain.c	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,386 @@
+/* GDA Jdbc Provider
+ * Copyright (C) 2008 The GNOME Foundation
+ *
+ * AUTHORS:
+ *      TO_ADD: your name and email
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define __GDA_JDBC_LIBMAIN__
+
+#include <glib/gi18n-lib.h>
+#include <gmodule.h>
+#include <libgda/gda-log.h>
+#include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
+#include "gda-jdbc.h"
+#include "gda-jdbc-provider.h"
+#include "jni-wrapper.h"
+#include "jni-globals.h"
+
+#ifdef G_OS_WIN32
+#include <windows.h>
+#include <winreg.h>
+#define EXPORT __declspec(dllexport)
+#else
+#define EXPORT
+#endif
+
+
+/* JVM's symbols */
+static GStaticMutex vm_create = G_STATIC_MUTEX_INIT;
+static jint (*__CreateJavaVM) (JavaVM **pvm, void **penv, void *args) = NULL;
+JavaVM *_jdbc_provider_java_vm = NULL;
+
+
+static gchar      *module_path = NULL;
+
+EXPORT const gchar      **plugin_get_sub_names (void);
+EXPORT const gchar       *plugin_get_sub_description (const gchar *name);
+EXPORT gchar             *plugin_get_sub_dsn_spec (const gchar *name);
+EXPORT GdaServerProvider *plugin_create_sub_provider (const gchar *name);
+
+/* locate and load JAVA virtual machine */
+static gboolean    load_jvm ();
+
+/* get the name of the database server type from the JDBC driver name */
+static const gchar *get_database_name_from_driver_name (const gchar *driver_name);
+
+
+/* JDBC drivers installed */
+typedef struct {
+	const gchar *name;
+	const gchar *native_db;
+	gchar *descr;
+} JdbcDriver;
+static GHashTable *jdbc_drivers_hash = NULL; /* key = name, value = JdbcDriver pointer */
+static gchar **sub_names = NULL;
+static gint    sub_nb; /* size of sub_names */
+
+EXPORT void
+plugin_init (const gchar *real_path)
+{
+        if (real_path)
+                module_path = g_strdup (real_path);
+}
+
+EXPORT const gchar **
+plugin_get_sub_names (void)
+{
+	if (! __CreateJavaVM && !load_jvm ())
+		return NULL;
+	
+	GError *error = NULL;
+	GValue *lvalue;
+	JNIEnv *env;
+	jclass cls;
+	gint i;
+
+	if ((*_jdbc_provider_java_vm)->AttachCurrentThread (_jdbc_provider_java_vm,
+							    (void**) &env, NULL) < 0) {
+		g_warning ("Could not attach JAVA virtual machine's current thread");
+		return NULL;
+	}
+
+	cls = jni_wrapper_class_get (env, "GdaJProvider", NULL);
+	lvalue = jni_wrapper_method_call (env, GdaJProvider__getDrivers, NULL, NULL, NULL, &error);
+	if (!lvalue) {
+		g_warning (_("Can't get list of installed JDBC drivers: %s"),
+			   error && error->message ? error->message : _("No detail"));
+		if (error)
+			g_error_free (error);
+		return NULL;		
+	}
+	if (!gda_value_is_null (lvalue)) {
+		sub_names = g_strsplit (g_value_get_string (lvalue), ":", 0);
+		g_value_unset (lvalue);
+		g_free (lvalue);
+		
+		sub_nb = g_strv_length (sub_names);
+		jdbc_drivers_hash = g_hash_table_new (g_str_hash, g_str_equal);
+		for (i = 0; i < sub_nb; i++) {
+			JdbcDriver *dr = g_new0 (JdbcDriver, 1);
+			dr->name = sub_names [i];
+			dr->native_db = get_database_name_from_driver_name (sub_names [i]);
+			if (dr->native_db)
+				dr->descr = g_strdup_printf ("Provider to access %s databases using JDBC", 
+							     dr->native_db);
+			else
+				dr->descr = g_strdup_printf ("Provider to access databases using JDBC's %s driver",
+							     dr->name);
+			g_hash_table_insert (jdbc_drivers_hash, (gchar*) dr->name, dr);
+		}
+		
+		return (const gchar **) sub_names;
+	}
+	else {
+		g_free (lvalue);
+		return NULL;
+	}
+}
+
+EXPORT const gchar *
+plugin_get_sub_description (const gchar *name)
+{
+	JdbcDriver *dr;
+	dr = g_hash_table_lookup (jdbc_drivers_hash, name);
+	if (dr)
+		return dr->descr;
+	else
+		return NULL;
+}
+
+EXPORT gchar *
+plugin_get_sub_dsn_spec (const gchar *name)
+{
+	gchar *ret, *dir;
+
+	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");
+	g_free (dir);
+	return ret;
+}
+
+EXPORT GdaServerProvider *
+plugin_create_sub_provider (const gchar *name)
+{
+	/* server creation */
+	GdaServerProvider *prov;
+	prov = gda_jdbc_provider_new (name, NULL);
+	g_object_set_data ((GObject *) prov, "GDA_PROVIDER_DIR", module_path);
+	return prov;
+}
+
+#ifdef G_OS_WIN32
+/* Look up a key's value in the registry. */
+static gchar *
+win32_lookup_registry_key (const gchar *keyname, const gchar *name)
+{
+        gchar *retval;
+        DWORD size;
+        DWORD type;
+        LONG res;
+        HKEY reg_key = (HKEY) INVALID_HANDLE_VALUE;
+
+        res = RegOpenKeyExA (HKEY_LOCAL_MACHINE, keyname, 0, KEY_READ, &reg_key);
+        if (res != ERROR_SUCCESS) {
+                reg_key = (HKEY) INVALID_HANDLE_VALUE;
+                return NULL;
+        }
+
+        size = 128;
+        retval = g_malloc (sizeof (gchar) * size);
+
+        res = RegQueryValueExA (reg_key, name, 0, &type, retval, &size);
+        if (res == ERROR_MORE_DATA && type == REG_SZ) {
+                retval = (gchar *) g_realloc (retval, sizeof (gchar) * size);
+                res = RegQueryValueExA (reg_key, name, 0, &type, retval, &size);
+        }
+
+        if (type != REG_SZ || res != ERROR_SUCCESS) {
+                g_free (retval);
+                retval = NULL;
+        }
+
+        RegCloseKey (reg_key);
+
+        return retval;
+}
+
+#endif
+
+static gboolean find_jvm_in_dir (const gchar *dir_name);
+static gboolean
+load_jvm ()
+{
+	gboolean jvm_found = FALSE;
+	const gchar *env;
+
+	g_static_mutex_lock (&vm_create);
+	if (_jdbc_provider_java_vm) {
+		g_static_mutex_unlock (&vm_create);
+		return TRUE;
+	}
+
+#ifdef G_OS_WIN32
+	gchar *tmp1;
+	const gchar *loc = "SOFTWARE\\\JavaSoft\\Java Runtime Environment";
+	tmp1 = win32_lookup_registry_key (loc, "CurrentVersion");
+	if (tmp1) {
+		gchar *kn, *tmp2;
+		kn = g_strdup_printf ("%s\\%s", loc, tmp1);
+		g_free (tmp1);
+		tmp2 = win32_lookup_registry_key (kn, "JavaHome");
+		if (tmp2) {
+			gchar *tmp3;
+			tmp3 = g_build_filename (tmp2, "bin", "client", NULL);
+			g_free (tmp2);
+			if (find_jvm_in_dir (tmp3))
+				jvm_found = TRUE;
+		}
+	}
+	if (!jvm_found) {
+		loc = "SOFTWARE\\\JavaSoft\\Java Development Kit";
+		tmp1 = win32_lookup_registry_key (loc, "CurrentVersion");
+		if (tmp1) {
+			gchar *kn, *tmp2;
+			kn = g_strdup_printf ("%s\\%s", loc, tmp1);
+			g_free (tmp1);
+			tmp2 = win32_lookup_registry_key (kn, "JavaHome");
+			if (tmp2) {
+				gchar *tmp3;
+				tmp3 = g_build_filename (tmp2, "jre", "bin", "client", NULL);
+				g_free (tmp2);
+				if (find_jvm_in_dir (tmp3))
+					jvm_found = TRUE;
+			}
+		}
+	}
+
+#else
+	/* first, use LD_LIBRARY_PATH */
+	env = g_getenv ("LD_LIBRARY_PATH");
+	if (env) {
+		gchar **array;
+		gint i;
+		array = g_strsplit (env, ":", 0);
+		for (i = 0; array[i]; i++) {
+			if (find_jvm_in_dir (array [i])) {
+				jvm_found = TRUE;
+				break;
+			}
+		}
+		g_strfreev (array);
+	}
+	if (jvm_found)
+		goto out;
+
+	/* then use the compile time JVM_PATH */
+	if (JVM_PATH) {
+		gchar **array;
+		gint i;
+		array = g_strsplit (JVM_PATH, ":", 0);
+		for (i = 0; array[i]; i++) {
+			if (find_jvm_in_dir (array [i])) {
+				jvm_found = TRUE;
+				break;
+			}
+		}
+		g_strfreev (array);
+	}
+#endif
+	if (jvm_found)
+		goto out;
+
+	/* at last use module_path */
+	if (find_jvm_in_dir (module_path))
+		jvm_found = TRUE;
+
+ out:
+	if (jvm_found) {
+		gchar *path;
+		GError *error = NULL;
+		path = g_build_filename (module_path, "gdaprovider-4.0.jar", NULL);
+		jni_wrapper_create_vm (&_jdbc_provider_java_vm, __CreateJavaVM, module_path, path, &error);
+		if (!_jdbc_provider_java_vm)
+			g_error (_("Can't create JAVA virtual machine: %s"),
+				 error && error->message ? error->message : _("No detail"));	
+	}
+	else {
+		__CreateJavaVM = NULL;
+		g_warning (_("Could not the JVM runtime (libjvm.so), JDBC provider is unavailable."));
+	}
+
+	g_static_mutex_unlock (&vm_create);
+	return jvm_found;
+}
+
+static gboolean
+find_jvm_in_dir (const gchar *dir_name)
+{
+	GDir *dir;
+	GError *err = NULL;
+	const gchar *name;
+	gboolean jvm_found = FALSE;
+
+	/* read the plugin directory */
+#ifdef GDA_DEBUG_NO
+	g_print ("Looking for JVM in %s\n", dir_name);
+#endif
+	dir = g_dir_open (dir_name, 0, &err);
+	if (err) {
+		gda_log_error (err->message);
+		g_error_free (err);
+		return FALSE;
+	}
+
+	while ((name = g_dir_read_name (dir))) {
+		if (!g_str_has_suffix (name, "." G_MODULE_SUFFIX))
+			continue;
+		if (!g_strrstr (name, "jvm"))
+			continue;
+
+		GModule *handle;
+		gchar *path;
+
+		path = g_build_path (G_DIR_SEPARATOR_S, dir_name, name, NULL);
+		handle = g_module_open (path, G_MODULE_BIND_LAZY);
+		g_free (path);
+		if (!handle) {
+			/*g_warning (_("Error: %s"), g_module_error ());*/
+			continue;
+		}
+
+		if (g_module_symbol (handle, "JNI_CreateJavaVM", (gpointer *) &__CreateJavaVM)) {
+			/* JVM found */
+#ifdef GDA_DEBUG_NO
+			path = g_build_path (G_DIR_SEPARATOR_S, dir_name, name, NULL);
+			g_print ("JVM found as: '%s'\n", path);
+			g_free (path);
+#endif
+			jvm_found = TRUE;
+			break;
+		}
+		else
+			g_module_close (handle);
+
+	}
+	/* free memory */
+	g_dir_close (dir);
+	return jvm_found;
+}
+
+static const gchar *
+get_database_name_from_driver_name (const gchar *driver_name)
+{
+	typedef struct {
+		gchar *jdbc_name;
+		gchar *db_name;
+	} Corresp;
+	
+	static Corresp carray[] = {
+		{"org.postgresql.Driver", "PostgreSQL"},
+		{"com.mysql.jdbc.Driver", "MySQL"}
+	};
+
+	gint i;
+	for (i = 0; i < sizeof (carray) / sizeof (Corresp); i++) {
+		if (!strcmp (carray[i].jdbc_name, driver_name))
+			return carray[i].db_name;
+	}
+
+	return NULL;
+}

Added: trunk/providers/jdbc/meta.java
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/meta.java	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,262 @@
+import java.sql.*;
+import java.util.*;
+import java.io.*;
+
+/*
+ * This class is the central point for meta data extraction. It is a default implementation for all JDBC providers
+ * and can be sub-classed for database specific adaptations
+ */
+class GdaJMeta {
+	private static native void initIDs();
+	public Connection cnc;
+	public DatabaseMetaData md;
+	private HashMap<String, Boolean> current_schemas = new HashMap<String, Boolean> ();
+
+	public GdaJMeta (Connection cnc) throws Exception {
+		this.cnc = cnc;
+		this.md = cnc.getMetaData ();
+	}
+
+	public void schemaAddCurrent (String schema) {
+		current_schemas.put (GdaJValue.toLower (schema), true);
+	}
+
+	public boolean schemaIsCurrent (String schema) throws Exception {
+		return current_schemas.containsKey (GdaJValue.toLower (schema));
+	}
+
+	// The returned String must _never_ be NULL, but set to "" if it was NULL
+	public String getCatalog () throws Exception {
+		String s = cnc.getCatalog ();
+		if (s == null)
+			return "";
+		else
+			return s;
+	}
+
+	public GdaJResultSet getSchemas (String catalog, String schema) throws Exception {
+		return new GdaJMetaSchemas (this, catalog, schema);
+	}
+
+	public GdaJResultSet getTables (String catalog, String schema, String name) throws Exception {
+		return new GdaJMetaTables (this, catalog, schema, name);
+	}
+
+	public GdaJResultSet getViews (String catalog, String schema, String name) throws Exception {
+		return new GdaJMetaViews (this, catalog, schema, name);
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+/*
+ * Meta data retreival is returned as instances of the class which allows a degree of
+ * customization depending on the type of database being accessed.
+ */
+abstract class GdaJMetaResultSet extends GdaJResultSet {
+	public Vector<GdaJColumnInfos> meta_col_infos;
+	protected ResultSet rs;
+	protected DatabaseMetaData md;
+	protected GdaJMeta jm;
+
+	protected GdaJMetaResultSet (int ncols, GdaJMeta jm) {
+		super (ncols);
+		this.jm = jm;
+		md = jm.md;
+		rs = null;
+		meta_col_infos = new Vector<GdaJColumnInfos> (0);
+	}
+
+	// get result set's meta data
+	public GdaJResultSetInfos getInfos () throws Exception {
+		return new GdaJMetaInfos (this);
+	}
+
+	abstract public boolean fillNextRow (long c_pointer) throws Exception;
+}
+
+/*
+ * Extends GdaJResultSetInfos for GdaJMetaResultSet
+ */
+class GdaJMetaInfos extends GdaJResultSetInfos {
+	private GdaJMetaResultSet meta;
+
+	// Constructor
+	public GdaJMetaInfos (GdaJMetaResultSet meta) {
+		super (meta.meta_col_infos);
+		this.meta = meta;
+	}
+
+	// describe a column, index starting at 0
+        public GdaJColumnInfos describeColumn (int col) throws Exception {
+                return meta.meta_col_infos.elementAt (col);
+        }
+}
+
+
+
+/*
+ * Meta data for schemas
+ */
+class GdaJMetaSchemas extends GdaJMetaResultSet {
+	ResultSet rs;
+	String catalog = null;
+	String schema = null;
+
+	public GdaJMetaSchemas (GdaJMeta jm, String catalog, String schema) throws Exception {
+		super (4, jm);
+		meta_col_infos.add (new GdaJColumnInfos ("catalog_name", "catalog_name", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_name", "schema_name", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_owner", "owner", java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("schema_internal", "is internal", java.sql.Types.BOOLEAN));
+		rs = jm.md.getSchemas ();
+		this.catalog = catalog;
+		this.schema = schema;
+	}
+
+	protected void columnTypesDeclared () {
+		// the catalog part cannot be NULL, but "" instead
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.no_null = true;
+		cv.convert_lc = true;
+		((GdaJValue) col_values.elementAt (1)).convert_lc = true;
+	}
+
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		if (! rs.next ())
+			return false;
+
+		GdaJValue cv;
+		
+		if (catalog != null) {
+			String s = rs.getString (2);
+			if (s != catalog)
+				return fillNextRow (c_pointer);
+		}
+		if (schema != null) {
+			String s = rs.getString (1);
+			if (s != schema)
+				return fillNextRow (c_pointer);
+		}
+
+		cv = (GdaJValue) col_values.elementAt (0);
+		cv.setCValue (rs, 1, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.setCValue (rs, 0, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.setCBoolean (c_pointer, 3, false);
+
+		return true;
+	}
+}
+
+/*
+ * Meta data for tables
+ */
+class GdaJMetaTables extends GdaJMetaResultSet {
+	protected GdaJMetaTables (GdaJMeta jm) {
+		super (9, jm);
+		meta_col_infos.add (new GdaJColumnInfos ("table_catalog", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_schema", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_name", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_type", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("is_insertable_into", null, java.sql.Types.BOOLEAN));
+		meta_col_infos.add (new GdaJColumnInfos ("table_comments", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_short_name", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_full_name", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_owner", null, java.sql.Types.VARCHAR));
+		md = jm.md;
+	}
+
+	public GdaJMetaTables (GdaJMeta jm, String catalog, String schema, String name) throws Exception {
+		this (jm);
+		rs = md.getTables (catalog, schema, name, null);
+	}
+
+	protected void columnTypesDeclared () {
+		// the catalog part cannot be NULL, but "" instead
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.no_null = true;
+		((GdaJValue) col_values.elementAt (1)).convert_lc = true;
+		((GdaJValue) col_values.elementAt (2)).convert_lc = true;
+		((GdaJValue) col_values.elementAt (6)).convert_lc = true;
+		((GdaJValue) col_values.elementAt (7)).convert_lc = true;
+	}
+
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		if (! rs.next ())
+			return false;
+
+		GdaJValue cv;
+		
+		cv = (GdaJValue) col_values.elementAt (0);
+		cv.setCValue (rs, 0, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.setCValue (rs, 1, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (2);
+		cv.setCValue (rs, 2, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (3);
+		cv.setCValue (rs, 3, c_pointer);
+		
+		cv = (GdaJValue) col_values.elementAt (5);
+		cv.setCValue (rs, 4, c_pointer);
+
+		String ln = GdaJValue.toLower (rs.getString (2) + "." + rs.getString (3));
+		if (jm.schemaIsCurrent (rs.getString (2)))
+			cv.setCString (c_pointer, 6, GdaJValue.toLower (rs.getString (3)));
+		else
+			cv.setCString (c_pointer, 6, ln);
+		cv = (GdaJValue) col_values.elementAt (7);
+		cv.setCString (c_pointer, 7, ln);
+
+		return true;
+	}
+}
+
+/*
+ * Meta data for views
+ */
+class GdaJMetaViews extends GdaJMetaResultSet {
+	protected GdaJMetaViews (GdaJMeta jm) {
+		super (6, jm);
+		meta_col_infos.add (new GdaJColumnInfos ("table_catalog", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_schema", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("table_name", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("view_definition", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("check_option", null, java.sql.Types.VARCHAR));
+		meta_col_infos.add (new GdaJColumnInfos ("is_updatable", null, java.sql.Types.BOOLEAN));
+		md = jm.md;
+	}
+
+	public GdaJMetaViews (GdaJMeta jm, String catalog, String schema, String name) throws Exception {
+		this (jm);
+		rs = jm.md.getTables (catalog, schema, name, new String[]{"VIEW"});
+	}
+
+	protected void columnTypesDeclared () {
+		// the catalog part cannot be NULL, but "" instead
+		GdaJValue cv = (GdaJValue) col_values.elementAt (0);
+		cv.no_null = true;
+		((GdaJValue) col_values.elementAt (1)).convert_lc = true;
+		((GdaJValue) col_values.elementAt (2)).convert_lc = true;
+	}
+
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		if (! rs.next ())
+			return false;
+
+		GdaJValue cv;
+		
+		cv = (GdaJValue) col_values.elementAt (0);
+		cv.setCValue (rs, 0, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (1);
+		cv.setCValue (rs, 1, c_pointer);
+		cv = (GdaJValue) col_values.elementAt (2);
+		cv.setCValue (rs, 2, c_pointer);
+
+		return true;
+	}
+}
\ No newline at end of file

Added: trunk/providers/jdbc/provider.java
==============================================================================
--- (empty file)
+++ trunk/providers/jdbc/provider.java	Sat Nov 29 14:48:16 2008
@@ -0,0 +1,1006 @@
+import java.sql.*;
+import java.util.*;
+import java.io.*;
+
+/*
+ * This class will be instantiated once for each GdaJdbcProvider created.
+ */
+class GdaJProvider {
+	private static native void initIDs();
+	private String driver;
+
+	// Constructor
+	public GdaJProvider (String driver) {
+		this.driver = driver;
+	}
+
+	// Connection opening
+	public GdaJConnection openConnection (String cnc_string, String username, String password) throws Exception {
+		Connection cnc;
+		try {
+			Class.forName (driver);
+			cnc = DriverManager.getConnection (cnc_string, username, password);
+		}
+		catch (Exception e) {
+			throw e;
+		}
+		GdaJConnection jcnc = new GdaJConnection (cnc, driver);
+		return jcnc;
+	}
+
+	// Get a list of all the known drivers
+	// See also http://www.devx.com/tips/Tip/28818 for a list of drivers
+	public static String getDrivers () {
+		try {
+			Class driverClass = Class.forName ("org.hsqldb.jdbcDriver");
+		}
+		catch (Exception e) {
+			// ignore exceptions, they mean some drivers are not available
+		}
+
+		java.util.Enumeration e = DriverManager.getDrivers();
+		String res = null;
+		while (e.hasMoreElements ()) {
+			Driver driver = (Driver) e.nextElement(); 
+			if (res == null)
+				res = driver.getClass().getName();
+			else
+				res = res + ":" + driver.getClass().getName();
+
+			// Properties list, for DSN spec creation.
+			if (false) {
+				System.out.println("===== DEBUG: Properties for " + driver.getClass().getName());
+				try {
+					Properties ep = new Properties();
+					DriverPropertyInfo[] props = driver.getPropertyInfo ("", ep);
+					if (props != null) {
+						for (int i = 0; i < props.length; i++){
+							DriverPropertyInfo prop = props[i];
+							System.out.println ("  Prop name = "+prop.name);
+							System.out.println ("     Prop description = "+prop.description);
+							System.out.println ("     Prop value = "+prop.value);
+							if (prop.choices != null) {
+								for (int j = 0; j < prop.choices.length; j++) {
+									System.out.println ("     prop choice "+j
+											    +" = "+prop.choices[j]);
+								}
+							}
+						}
+					}
+				}
+				catch (Exception ex) {
+					ex.printStackTrace ();
+				}
+			}
+		}
+		return res;
+	}
+	
+	public static Connection openConnection (String driver, String cnc_string) {
+		System.out.println ("JAVA openConnection() requested");
+		return null;
+	}
+
+	// main(): in case someone tries to exetute the JAR
+	public static void main (String args[]) {
+                System.out.println ("This JAR is not intended to be executed directly, " +
+				    "but used as Libgda's JDBC provider!");
+        }
+
+	// class initializer
+	static {
+		if (System.getProperty("os.name").indexOf ("Win") >= 0) {
+			// If we are running on Windows, then we need to set the full library name
+			// because our library is still called libgda-jdbc.dll
+			System.loadLibrary ("libgda-jdbc");
+		}
+		else {
+			System.loadLibrary ("gda-jdbc");
+		}
+		initIDs ();
+
+		try {
+			/* dummy objects creation to force class loading */
+			byte[] data = {'e'};
+			GdaInputStream is = new GdaInputStream (data);
+		}
+		catch (Exception e) {
+			System.out.println ("Coult not initialize some JAVA classes");
+			e.printStackTrace ();
+		}
+	}
+}
+
+
+/*
+ * This class will be instantiated once for each GdaConnection object
+ */
+class GdaJConnection {
+	private static native void initIDs();
+	public Connection cnc = null;
+	private HashMap<String,Savepoint> svp_map = new HashMap<String,Savepoint>();
+	private GdaJMeta jmeta = null;
+	String driver;
+
+	// Constructor
+	public GdaJConnection (Connection cnc, String driver) throws Exception {
+		this.cnc = cnc;
+		this.driver = driver;
+	}
+
+	// Connection close
+	public void close () throws Exception {
+		this.cnc.close ();
+		jmeta = null;
+	}
+
+	// get server version
+	public String getServerVersion () throws Exception {
+		DatabaseMetaData meta_data;
+		meta_data = cnc.getMetaData ();
+		return meta_data.getDatabaseProductName() + " " + meta_data.getDatabaseProductVersion ();
+	}
+
+	// prepare statement
+	public GdaJPStmt prepareStatement (String sql) throws Exception {
+		GdaJPStmt ps;
+		PreparedStatement pstmt;
+
+		pstmt = cnc.prepareStatement (sql);
+		ps = new GdaJPStmt (pstmt);
+		return ps;
+	}
+
+	// direct execution of a SELECT with no parameters
+	public GdaJResultSet executeDirectSQL (String sql) throws Exception {
+		Statement st;
+		st = cnc.createStatement ();
+		return new GdaJResultSet (st.executeQuery (sql));
+	}
+
+	// Transaction management
+	public void begin () throws Exception {
+		if (cnc.getAutoCommit() == false) {
+			throw new Exception ("Transaction already started");
+		}
+		cnc.setAutoCommit (false);
+	}
+	
+	public void rollback () throws Exception {
+		if (cnc.getAutoCommit() == true) {
+			throw new Exception ("No transaction started");
+		}
+		cnc.rollback ();
+		cnc.setAutoCommit (true);
+	}
+
+	public void commit () throws Exception {
+		if (cnc.getAutoCommit() == true) {
+			throw new Exception ("No transaction started");
+		}
+		cnc.commit ();
+		cnc.setAutoCommit (true);
+	}
+
+	public void addSavepoint (String svp_name) throws Exception {
+		Savepoint svp;
+		if (cnc.getAutoCommit() == true) {
+			throw new Exception ("No transaction started");
+		}
+
+		svp = (Savepoint) svp_map.get (svp_name);
+		if (svp != null) {
+			throw new Exception ("Savepoint '" + svp_name + "' already exists");
+		}
+		svp = cnc.setSavepoint (svp_name);
+		svp_map.put (svp_name, svp);
+	}
+
+	public void rollbackSavepoint (String svp_name) throws Exception {
+		Savepoint svp = null;
+		if (cnc.getAutoCommit() == true) {
+			throw new Exception ("No transaction started");
+		}
+		svp = (Savepoint) svp_map.get (svp_name);
+		if (svp == null) {
+			throw new Exception ("No savepoint '" + svp_name + "' found");
+		}
+		cnc.rollback (svp);
+		svp_map.remove (svp_name);
+	}
+
+	public void releaseSavepoint (String svp_name) throws Exception {
+		Savepoint svp = null;
+		if (cnc.getAutoCommit() == true) {
+			throw new Exception ("No transaction started");
+		}
+		svp = (Savepoint) svp_map.get (svp_name);
+		if (svp == null) {
+			throw new Exception ("No savepoint '" + svp_name + "' found");
+		}
+		cnc.releaseSavepoint (svp);
+		svp_map.remove (svp_name);
+	}
+
+	// meta data retreival
+	public GdaJMeta getJMeta () throws Exception {
+		if (jmeta == null) {
+			String name= driver.replace (".", "_") + "Meta";
+			try {
+				Class<?> r = Class.forName (name);
+				java.lang.reflect.Constructor c = r.getConstructor (new Class [] {Class.forName ("java.sql.Connection")});
+				jmeta = (GdaJMeta) c.newInstance (new Object [] {cnc});
+			}
+			catch (Exception e) {
+				System.out.println ("Could not load Class " + name);
+				e.printStackTrace ();
+				jmeta = new GdaJMeta (cnc);
+			}
+		}
+		return jmeta;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+/*
+ * Represents a prepared statement
+ */
+class GdaJPStmt {
+	private static native void initIDs();
+	private PreparedStatement ps;
+	private Vector<GdaJValue> param_values;
+
+	// Constructor
+	public GdaJPStmt (PreparedStatement ps) {
+		this.ps = ps;
+		param_values = new Vector<GdaJValue> (0);
+	}
+
+	// declares the expected type for the parameters
+	public void declareParamTypes (long cnc_c_pointer, byte types[]) throws Exception {
+		int nparams = ps.getParameterMetaData().getParameterCount ();
+		int i;
+		if (types.length != nparams) {
+			throw new Exception ("Number of types differs from number of parameters: got " + types.length + 
+					     " and expected " + nparams);
+		}
+
+		for (i = 0; i < nparams; i++) {
+			GdaJValue cv = GdaJValue.proto_type_to_jvalue (types[i]);
+			cv.setGdaConnectionPointer (cnc_c_pointer);
+			param_values.add (cv);
+			//System.out.println ("JAVA: param " + i + " as type " + types[i]);
+		}
+	}
+
+	// sets a parameter's value
+	// if c_value_pointer is 0, then the parameter should be set to NULL
+	public void setParameterValue (int index, long c_value_pointer) throws Exception {
+		GdaJValue cv = (GdaJValue) param_values.elementAt (index);
+		cv.getCValue (ps, index, c_value_pointer);
+	}
+
+	// Clear previous set parameters
+	public void clearParameters () throws Exception {
+		ps.clearParameters ();
+	}
+
+	// Execute
+	public boolean execute () throws Exception {
+		return ps.execute ();
+	}
+
+	// Fetch result set
+	public GdaJResultSet getResultSet () throws Exception {
+		return new GdaJResultSet (ps.getResultSet ());
+	}
+
+	public int getImpactedRows () throws Exception {
+		return ps.getUpdateCount ();
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+
+/*
+ * This class represents meta data information for a GdaJResultSet.
+ *
+ * All the fields are read-only
+ */
+class GdaJResultSetInfos {
+	private static native void initIDs();
+	public Vector<GdaJColumnInfos> col_infos;
+	private int ncols;
+	
+	// Constructor
+	public GdaJResultSetInfos (ResultSetMetaData md) throws Exception {
+		int i;
+		ncols = md.getColumnCount ();
+		col_infos = new Vector<GdaJColumnInfos> (0);
+		for (i = 0; i < ncols; i++) {
+			GdaJColumnInfos ci;
+			int rcol = i + 1;
+			ci = new GdaJColumnInfos (md.getColumnName (rcol), md.getColumnLabel (rcol), md.getColumnType (rcol));
+			col_infos.add (ci);
+		}
+	}
+
+	public GdaJResultSetInfos (Vector<GdaJColumnInfos> col_infos) {
+		this.col_infos = col_infos;
+		ncols = col_infos.size ();
+	}
+
+	// describe a column, index starting at 0
+	public GdaJColumnInfos describeColumn (int col) throws Exception {
+		return (GdaJColumnInfos) col_infos.elementAt (col);
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+class GdaJColumnInfos {
+	private static native void initIDs();
+	String col_name;
+	String col_descr;
+	int col_type;
+
+	public GdaJColumnInfos (String col_name, String col_descr, int col_type) {
+		this.col_name = col_name;
+		this.col_descr = col_descr;
+		this.col_type = col_type;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+/*
+ * This class represents a result set: the result of a SELECT statement
+ */
+class GdaJResultSet {
+	private static native void initIDs();
+	private ResultSet rs;
+
+	private int ncols;
+	protected Vector<GdaJValue> col_values;
+
+	// Constructor
+	public GdaJResultSet (ResultSet rs) throws Exception {
+		this.rs = rs;
+		if (rs != null) {
+			ncols = rs.getMetaData().getColumnCount();
+			col_values = new Vector<GdaJValue> (ncols);
+		}
+	}
+
+	protected GdaJResultSet (int ncols) {
+		this.ncols = ncols;
+		col_values = new Vector<GdaJValue> (ncols);
+	}
+
+	// get result set's meta data
+	public GdaJResultSetInfos getInfos () throws Exception {
+		return new GdaJResultSetInfos (rs.getMetaData ());
+	}
+
+	/*
+	 * declares the expected type for the column
+	 */
+	public void declareColumnTypes (long cnc_c_pointer, byte types[]) throws Exception {
+		int i;
+		if (types.length != ncols) {
+			throw new Exception ("Number of types differs from number of columns: expected " + ncols + " got " +
+					     types.length);
+		}
+		for (i = 0; i < ncols; i++) {
+			GdaJValue cv = GdaJValue.proto_type_to_jvalue (types[i]);
+			cv.setGdaConnectionPointer (cnc_c_pointer);
+			cv.setGdaRowColumn (i);
+			col_values.add (cv);
+		}
+		columnTypesDeclared ();
+	}
+
+	protected void columnTypesDeclared () {
+		// do nothing here, let sub classes do it.
+	}
+
+	/* 
+	 * move iterator to next row and fills row
+	 * @c_pointer is a pointer to the new GdaRow to fill values
+	 * Returns: false if no more row available
+	 */
+	public boolean fillNextRow (long c_pointer) throws Exception {
+		int i;
+		if (! rs.next ())
+			return false;
+		for (i = 0; i < ncols; i++) {
+			GdaJValue cv = (GdaJValue) col_values.elementAt (i);
+			cv.setCValue (rs, i, c_pointer);
+		}
+		return true;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+
+/*
+ * Classes to represent value transport between the JAVA and C worlds:
+ * - JAVA -> C when reading through a resultset
+ * - C -> JAVA when setting the parameter's values of a prepared statement
+ */
+abstract class GdaJValue {
+	private static native void initIDs();
+	protected long cnc_c_pointer = 0;
+	protected int gda_row_column = -1;
+	protected boolean convert_lc = false; // true if strings must be converted to lower case (ignored by non String)
+	protected boolean no_null = false; // converts a NULL value to "" for a string (ignored by non String)
+
+	/*
+	 * @c_pointer points to a GdaRow
+	 * @col starts at 0
+	 */
+	native void setCString (long c_pointer, int col, String string);
+	native void setCInt (long c_pointer, int col, int i);
+	native void setCChar (long c_pointer, int col, byte b);
+	native void setCDouble (long c_pointer, int col, double d);
+	native void setCFloat (long c_pointer, int col, float f);
+	native void setCLong (long c_pointer, int col, long l);
+	native void setCShort (long c_pointer, int col, short s);
+	native void setCBoolean (long c_pointer, int col, boolean b);
+	native void setCDate (long c_pointer, int col, int year, int month, int day);
+	native void setCTime (long c_pointer, int col, int hour, int min, int sec);
+	native void setCTimestamp (long c_pointer, int col, int year, int month, int day, int hour, int min, int sec);
+	native void setCBinary (long c_pointer, int col, byte[] data);
+	native void setCBlob (long c_pointer, int col, long cnc_c_pointer, GdaJBlobOp blob);
+	native void setCNumeric (long c_pointer, int col, String str, int precision, int scale);
+	
+	/*
+	 * @c_pointer points to a GValue, may NOT be 0 ( <=> NULL )
+	 */
+	native String getCString (long c_pointer);
+	native int getCInt (long c_pointer);
+	native byte getCChar (long c_pointer);
+	native double getCDouble (long c_pointer);
+	native float getCFloat (long c_pointer);
+	native long getCLong (long c_pointer);
+	native short getCShort (long c_pointer);
+	native boolean getCBoolean (long c_pointer);
+	native java.sql.Date getCDate (long c_pointer);
+	native java.sql.Time getCTime (long c_pointer);
+	native java.sql.Timestamp getCTimestamp (long c_pointer);
+	native byte[] getCBinary (long c_pointer);
+	native GdaInputStream getCBlob (long c_pointer);
+	native java.math.BigDecimal getCNumeric (long c_pointer);
+
+	/*
+	 * Sets the C GValue's value from @rs at column @col (@c_pointer points to the GdaRow
+	 * which contains the GValues)
+	 */
+	abstract void setCValue (ResultSet rs, int col, long c_pointer) throws Exception; /* @col starts at 0 */
+
+	/*
+	 * Set @ps's parameter at index @index from the C GValue pointed by @c_pointer (if @c_pointer is 0, then
+	 * the parameter is set to NULL)
+	 */
+	abstract void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception; /* @index starts at 0 */
+
+	public void setGdaConnectionPointer (long cnc_c_pointer) {
+		this.cnc_c_pointer = cnc_c_pointer;
+	}
+
+	public void setGdaRowColumn (int col) {
+		gda_row_column = col;
+	}
+
+
+	// (year, month, day) -> java.sql.Date
+	public static java.sql.Date createDate (int year, int month, int day) {
+		Calendar cal = GregorianCalendar.getInstance();
+		cal.set (year, month, day);
+		return new java.sql.Date (cal.getTimeInMillis ());
+	}
+
+	// (hour, minute, sec) -> java.sql.Time
+	public static java.sql.Time createTime (int hour, int min, int sec) {
+		Calendar cal = GregorianCalendar.getInstance();
+		cal.set (0, 0, 0, hour, min, sec);
+		return new java.sql.Time (cal.getTimeInMillis ());
+	}
+
+	// (year, month, day, hour, minute, sec) -> java.sql.Timestamp
+	public static java.sql.Timestamp createTimestamp (int year, int month, int day, int hour, int min, int sec) {
+		Calendar cal = GregorianCalendar.getInstance();
+		cal.set (year, month, day, hour, min, sec);
+		return new java.sql.Timestamp (cal.getTimeInMillis ());
+	}
+
+	// types conversions
+	public static GdaJValue proto_type_to_jvalue (byte type) throws Exception {
+		GdaJValue cv;
+		switch (type) {
+		case 0: /* GDA_TYPE_NULL */
+			cv = new GdaJNull ();
+			break;
+		case 1: /* G_TYPE_STRING */
+			cv = new GdaJString ();
+			break;
+		case 2: /* G_TYPE_INT */
+			cv = new GdaJInt ();
+			break;
+		case 3: /* G_TYPE_CHAR */
+			cv = new GdaJChar ();
+			break;
+		case 4: /* G_TYPE_DOUBLE */
+			cv = new GdaJDouble ();
+			break;
+		case 5: /* G_TYPE_FLOAT */
+			cv = new GdaJFloat ();
+			break;
+		case 6: /* G_TYPE_BOOLEAN */
+			cv = new GdaJBoolean ();
+			break;
+		case 7: /* G_TYPE_DATE */
+			cv = new GdaJDate ();
+			break;
+		case 8: /* GDA_TYPE_TIME */
+			cv = new GdaJTime ();
+			break;
+		case 9: /* GDA_TYPE_TIMESTAMP */
+			cv = new GdaJTimestamp ();
+			break;
+		case 10: /* GDA_TYPE_BINARY */
+			cv = new GdaJBinary ();
+			break;
+		case 11: /* GDA_TYPE_BLOB */
+			cv = new GdaJBlob ();
+			break;
+		case 12: /* G_TYPE_INT64 */
+			cv = new GdaJInt64 ();
+			break;
+		case 13: /* GDA_TYPE_SHORT */
+			cv = new GdaJShort ();
+			break;
+		case 14: /* GDA_TYPE_NUMERIC */
+			cv = new GdaJNumeric ();
+			break;
+			
+		default:
+			throw new Exception ("Unhandled protocol type " + type);
+		}
+		return cv;
+	}
+
+	public static String toLower (String string) {
+		String s2 = string.toUpperCase();
+		if (s2 == string)
+			return string.toLowerCase();
+		else
+			return string;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+class GdaJString extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		String string;
+		string = rs.getString (col + 1);
+		if (string == null) {
+			if (no_null)
+				setCString (c_pointer, gda_row_column, "");
+		}
+		else {
+			if (convert_lc) {
+				String s2 = string.toUpperCase();
+				if (s2 == string)
+					string = string.toLowerCase();
+			}
+			setCString (c_pointer, gda_row_column, string);
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.VARCHAR);
+		else {
+			String string;
+			string = getCString (c_pointer);
+			ps.setString (index + 1, string);
+		}
+	}
+}
+
+class GdaJInt extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		int i;
+		i = rs.getInt (col + 1);
+		if ((i != 0) || !rs.wasNull ())
+			setCInt (c_pointer, gda_row_column, i);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.INTEGER);
+		else {
+			int i;
+			i = getCInt (c_pointer);
+			ps.setInt (index + 1, i);
+		}
+	}
+}
+
+class GdaJDouble extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		double d;
+		d = rs.getDouble (col + 1);
+		if ((d != 0) || !rs.wasNull ())
+			setCDouble (c_pointer, gda_row_column, d);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.DOUBLE);
+		else {
+			double d;
+			d = getCDouble (c_pointer);
+			ps.setDouble (index + 1, d);
+		}
+	}
+}
+
+class GdaJFloat extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		float f;
+		f = rs.getFloat (col + 1);
+		if ((f != 0) || !rs.wasNull ())
+			setCFloat (c_pointer, gda_row_column, f);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.FLOAT);
+		else {
+			float f;
+			f = getCFloat (c_pointer);
+			ps.setFloat (index + 1, f);
+		}
+	}
+}
+
+class GdaJBoolean extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		boolean b;
+		b = rs.getBoolean (col + 1);
+		if (b || !rs.wasNull ())
+			setCBoolean (c_pointer, gda_row_column, b);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.BOOLEAN);
+		else {
+			boolean b;
+			b = getCBoolean (c_pointer);
+			ps.setBoolean (index + 1, b);
+		}
+	}
+}
+
+class GdaJDate extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		java.sql.Date date;
+		date = rs.getDate (col + 1);
+		if (date != null) {
+			Calendar cal = GregorianCalendar.getInstance();
+			cal.setTime (date);
+			setCDate (c_pointer, gda_row_column, cal.get (Calendar.YEAR), 
+				  cal.get (Calendar.MONTH) + 1, cal.get (Calendar.DAY_OF_MONTH));
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.DATE);
+		else {
+			java.sql.Date d;
+			d = getCDate (c_pointer);
+			ps.setDate (index + 1, d);
+		}
+	}
+}
+
+class GdaJTime extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		java.sql.Time time;
+		time = rs.getTime (col + 1);
+		if (time != null) {
+			Calendar cal = GregorianCalendar.getInstance();
+			cal.setTime (time);
+			setCTime (c_pointer, gda_row_column, cal.get (Calendar.HOUR_OF_DAY), 
+				  cal.get (Calendar.MINUTE) + 1, cal.get (Calendar.SECOND));
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.TIME);
+		else {
+			java.sql.Time t;
+			t = getCTime (c_pointer);
+			ps.setTime (index + 1, t);
+		}
+	}
+}
+
+class GdaJTimestamp extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		java.sql.Timestamp ts;
+		ts = rs.getTimestamp (col + 1);
+		if (ts != null) {
+			Calendar cal = GregorianCalendar.getInstance();
+			cal.setTime (ts);
+			setCTimestamp (c_pointer, gda_row_column, cal.get (Calendar.YEAR), 
+				       cal.get (Calendar.MONTH) + 1, cal.get (Calendar.DAY_OF_MONTH),
+				       cal.get (Calendar.HOUR_OF_DAY), 
+				       cal.get (Calendar.MINUTE) + 1, cal.get (Calendar.SECOND));
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.TIMESTAMP);
+		else {
+			java.sql.Timestamp ts;
+			ts = getCTimestamp (c_pointer);
+			ps.setTimestamp (index + 1, ts);
+		}
+	}
+}
+
+class GdaJBinary extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		byte[] bin;
+		bin = rs.getBytes (col + 1);
+		if (bin != null) {
+			setCBinary (c_pointer, gda_row_column, bin);
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.BINARY);
+		else {
+			byte[] bin;
+			bin = getCBinary (c_pointer);
+			ps.setBytes (index + 1, bin);
+		}
+	}
+}
+
+class GdaJBlob extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		java.sql.Blob blob;
+		blob = rs.getBlob (col + 1);
+		if (blob != null) {
+			setCBlob (c_pointer, gda_row_column, cnc_c_pointer, new GdaJBlobOp (blob));
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.BLOB);
+		else {
+			GdaInputStream is;
+			is = getCBlob (c_pointer);
+			ps.setBinaryStream (index + 1, is, is.size);
+		}
+	}
+}
+
+class GdaJChar extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		Byte b;
+		b = rs.getByte (col + 1);
+		if ((b != 0) || !rs.wasNull ())
+			setCChar (c_pointer, gda_row_column, b);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.CHAR);
+		else {
+			byte b;
+			b = getCChar (c_pointer);
+			ps.setByte (index + 1, b);
+		}
+	}
+}
+
+class GdaJInt64 extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		long l;
+		l = rs.getLong (col + 1);
+		if ((l != 0) || !rs.wasNull ())
+			setCLong (c_pointer, gda_row_column, l);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.BIGINT);
+		else {
+			long l;
+			l = getCLong (c_pointer);
+			ps.setLong (index + 1, l);
+		}
+	}
+}
+
+class GdaJShort extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		short s;
+		s = rs.getShort (col + 1);
+		if ((s != 0) || !rs.wasNull ())
+			setCShort (c_pointer, gda_row_column, s);
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.SMALLINT);
+		else {
+			short s;
+			s = getCShort (c_pointer);
+			ps.setShort (index + 1, s);
+		}
+	}
+}
+
+class GdaJNumeric extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		java.math.BigDecimal bd;
+
+		bd = rs.getBigDecimal (col + 1);
+		if (bd != null) {
+			setCNumeric (c_pointer, gda_row_column, bd.toString(), bd.precision(), bd.scale());
+		}
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		if (c_pointer == 0)
+			ps.setNull (index + 1, java.sql.Types.NUMERIC);
+		else {
+			java.math.BigDecimal bd;
+			bd = getCNumeric (c_pointer);
+			ps.setBigDecimal (index + 1, bd);
+		}
+	}
+}
+
+class GdaJNull extends GdaJValue {
+	void setCValue (ResultSet rs, int col, long c_pointer) throws Exception {
+		// nothing to do
+	}
+
+	void getCValue (PreparedStatement ps, int index, long c_pointer) throws Exception {
+		ParameterMetaData md;
+		int i = index + 1;
+		md = ps.getParameterMetaData ();
+		ps.setNull (i, md.getParameterType (i));
+	}
+}
+
+
+/*
+ * This class represents a Blob, used by the GdaBlobOp object
+ * to transfer data from JDBC -> C
+ */
+class GdaJBlobOp {
+	private static native void initIDs();
+	private Blob blob;
+
+	// Constructor
+	public GdaJBlobOp (Blob blob) {
+		this.blob = blob;
+	}
+
+	// Get Blob's length
+	public long length () throws Exception {
+		return blob.length ();
+	}
+
+	// Read data
+	public byte[] read (long offset, int len) throws Exception {
+		return blob.getBytes (offset + 1, len);
+	}
+
+	// Write data
+	public int write (long offset, byte[] data) throws Exception {
+		int i;
+		i = blob.setBytes (offset, data);
+		if (i != data.length) {
+			throw new Exception ("Could not write the complete BLOB");
+		}
+		return i;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}
+
+/*
+ * an InputStream which reads from a GdaBlob, for
+ * data transfer C -> JDBC
+ *
+ * Note: the @size attribute is not used here since the PreparedStatement.setBinaryStream() already
+ * contains the blob's size and won't try to get more. If this InputStream were to be used
+ * somewhere else, then @size would have to be handled correclty.
+ */
+class GdaInputStream extends InputStream {
+	static int chunk_size = 65536; // 64kb chunks
+
+	private static native void initIDs();
+	private native int[] readData (long gda_blob_pointer, long offset, long size);
+	private native byte[] readByteData (long gda_blob_pointer, long offset, long size);
+	public long size;
+	private long current_pos;
+	private long gda_blob_pointer;
+	private byte[] data;
+
+	private InputStream ist = null; // delegate
+
+	// Constructor
+	public GdaInputStream (long gda_blob_pointer, long size) {
+		current_pos = 0;
+		this.size = size;
+		this.gda_blob_pointer = gda_blob_pointer;
+	}
+
+	// Constructor
+	public GdaInputStream (byte[] data) {
+		this.gda_blob_pointer = 0;
+		ist = new ByteArrayInputStream (data);
+	}
+
+	// abstract class implementation
+	public int read() throws IOException {
+		int i = -1;
+		if (ist != null)
+			i = ist.read ();
+
+		if ((i == -1) && (gda_blob_pointer != 0)) {
+			byte[] data;
+			data = readByteData (gda_blob_pointer, current_pos, chunk_size);
+			current_pos += data.length;
+			ist = new ByteArrayInputStream (data);
+			i = ist.read ();
+		}
+		return i;
+	}
+
+	// class initializer
+	static {
+		initIDs ();
+	}
+}

Modified: trunk/providers/mdb/libmain.c
==============================================================================
--- trunk/providers/mdb/libmain.c	(original)
+++ trunk/providers/mdb/libmain.c	Sat Nov 29 14:48:16 2008
@@ -22,6 +22,7 @@
 
 #include <glib/gi18n-lib.h>
 #include <libgda/gda-server-provider-extra.h>
+#include <libgda/binreloc/gda-binreloc.h>
 #include "gda-mdb.h"
 #include "gda-mdb-provider.h"
 
@@ -54,7 +55,12 @@
 gchar *
 plugin_get_dsn_spec (void)
 {
-	return gda_server_provider_load_file_contents (module_path, LIBGDA_DATA_DIR, "mdb_specs_dsn.xml");
+	gchar *ret, *dir;
+
+        dir = gda_gbr_get_file_path (GDA_DATA_DIR, LIBGDA_ABI_NAME, NULL);
+        ret = gda_server_provider_load_file_contents (module_path, dir, "mdb_specs_dsn.xml");
+        g_free (dir);
+        return ret;
 }
 
 gchar *

Modified: trunk/providers/postgres/gda-postgres-blob-op.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-blob-op.c	(original)
+++ trunk/providers/postgres/gda-postgres-blob-op.c	Sat Nov 29 14:48:16 2008
@@ -384,18 +384,18 @@
 		#define buf_size 16384
 		gint nread = 0;
 		GdaBlob *tmpblob = g_new0 (GdaBlob, 1);
-		tmpblob->op = blob->op;
+		gda_blob_set_op (tmpblob, blob->op);
 
 		nbwritten = 0;
 
-		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size);
+		for (nread = gda_blob_op_read (tmpblob->op, tmpblob, 0, buf_size);
 		     nread > 0;
 		     nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) {
 			GdaBinary *bin = (GdaBinary *) tmpblob;
 			glong tmp_written;
 			tmp_written = lo_write (pconn, pgop->priv->fd, (char*) bin->data, 
 						bin->binary_length);
-			if (tmp_written < 0) {
+			if (tmp_written < bin->binary_length) {
 				_gda_postgres_make_error (pgop->priv->cnc, pconn, NULL, NULL);
 				gda_blob_free ((gpointer) tmpblob);
 				goto out_error;

Modified: trunk/providers/postgres/gda-postgres-recordset.c
==============================================================================
--- trunk/providers/postgres/gda-postgres-recordset.c	(original)
+++ trunk/providers/postgres/gda-postgres-recordset.c	Sat Nov 29 14:48:16 2008
@@ -469,7 +469,7 @@
 }
 
 /*
- * Create a new filled #GdaRow object for the next cursor row
+ * Create a new filled #GdaRow object for the next cursor row, and put it into *prow.
  *
  * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
  * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
@@ -506,7 +506,7 @@
 }
 
 /*
- * Create a new filled #GdaRow object for the previous cursor row
+ * Create a new filled #GdaRow object for the previous cursor row, and put it into *prow.
  *
  * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
  * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.
@@ -543,7 +543,7 @@
 }
 
 /*
- * Create a new filled #GdaRow object for the cursor row at position @rownum
+ * Create a new filled #GdaRow object for the cursor row at position @rownum, and put it into *prow.
  *
  * Each new #GdaRow created is referenced only by imodel->priv->tmp_row (the #GdaDataSelect implementation
  * never keeps a reference to it). Before a new #GdaRow gets created, the previous one, if set, is discarded.

Modified: trunk/tests/data-models/check_virtual.c
==============================================================================
--- trunk/tests/data-models/check_virtual.c	(original)
+++ trunk/tests/data-models/check_virtual.c	Sat Nov 29 14:48:16 2008
@@ -16,6 +16,9 @@
 	GdaDataModel *rw_model;
 	gchar *file;
 	
+	/* set up test environment */
+        g_setenv ("GDA_TOP_BUILD_DIR", TOP_BUILD_DIR, 0);
+        g_setenv ("GDA_TOP_SRC_DIR", TOP_SRC_DIR, TRUE);
 	gda_init ();
 
 	provider = gda_vprovider_data_model_new ();

Modified: trunk/tools/gda-sql.c
==============================================================================
--- trunk/tools/gda-sql.c	(original)
+++ trunk/tools/gda-sql.c	Sat Nov 29 14:48:16 2008
@@ -730,7 +730,6 @@
 						res = NULL;
 						goto cleanup;
 					}
-					g_free (str);
 				}
 			}
 			else {
@@ -1965,6 +1964,8 @@
 	res = g_new0 (GdaInternalCommandResult, 1);
 	res->type = GDA_INTERNAL_COMMAND_RESULT_TXT_STDOUT;
 	res->u.txt = g_string_new (args[0]);
+	if (args[0][strlen (args[0]) - 1] != '\n')
+		g_string_append_c (res->u.txt, '\n');
 	return res;
 }
 



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