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
- From: vivien svn gnome org
- To: svn-commits-list gnome org
- Subject: 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
- Date: Sat, 29 Nov 2008 14:48:16 +0000 (UTC)
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-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-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-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-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-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-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-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 (®istering);
+ if (type == 0)
+ type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaJdbcBlobOp", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ 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 (®istering);
+ if (type == 0)
+ type = g_type_register_static (GDA_TYPE_SERVER_PROVIDER, "GdaJdbcProvider", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+
+ 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, ¶ms, 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 (®istering);
+ if (type == 0)
+ type = g_type_register_static (GDA_TYPE_PSTMT, "GdaJdbcPStmt", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+ 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 (®istering);
+ if (type == 0)
+ type = g_type_register_static (GDA_TYPE_DATA_SELECT, "GdaJdbcRecordset", &info, 0);
+ g_static_mutex_unlock (®istering);
+ }
+
+ 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 > 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, ®_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]