1 /* 2 * Copyright (C) 2008 - 2011 Vivien Malerba <malerba@gnome-db.org> 3 * Copyright (C) 2010 David King <davidk@openismus.com> 4 * 5 * This library is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU Lesser General Public 7 * License as published by the Free Software Foundation; either 8 * version 2 of the License, or (at your option) any later version. 9 * 10 * This library is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * Lesser General Public License for more details. 14 * 15 * You should have received a copy of the GNU Lesser General Public 16 * License along with this library; if not, write to the 17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, 18 * Boston, MA 02110-1301, USA. 19 */ 20 21 #include <glib/gi18n-lib.h> 22 #include <string.h> 23 #include <libgda/libgda.h> 24 #include "gda-jdbc.h" 25 #include "gda-jdbc-util.h" 26 #include "gda-jdbc-blob-op.h" 27 #include "jni-globals.h" 28 29 struct _GdaJdbcBlobOpPrivate { 30 GdaConnection *cnc; 31 GValue *blob_obj; /* JAVA GdaJBlobOp object */ 32 }; 33 34 static void gda_jdbc_blob_op_class_init (GdaJdbcBlobOpClass *klass); 35 static void gda_jdbc_blob_op_init (GdaJdbcBlobOp *blob, 36 GdaJdbcBlobOpClass *klass); 37 static void gda_jdbc_blob_op_finalize (GObject *object); 38 39 static glong gda_jdbc_blob_op_get_length (GdaBlobOp *op); 40 static glong gda_jdbc_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size); 41 static glong gda_jdbc_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset); 42 43 static GObjectClass *parent_class = NULL; 44 45 /* 46 * Object init and finalize 47 */ 48 GType 49 gda_jdbc_blob_op_get_type (void) 50 { 51 static GType type = 0; 52 53 if (G_UNLIKELY (type == 0)) { 54 static GMutex registering; 55 static const GTypeInfo info = { 56 sizeof (GdaJdbcBlobOpClass), 57 (GBaseInitFunc) NULL, 58 (GBaseFinalizeFunc) NULL, 59 (GClassInitFunc) gda_jdbc_blob_op_class_init, 60 NULL, 61 NULL, 62 sizeof (GdaJdbcBlobOp), 63 0, 64 (GInstanceInitFunc) gda_jdbc_blob_op_init, 65 0 66 }; 67 g_mutex_lock (®istering); 68 if (type == 0) 69 type = g_type_register_static (GDA_TYPE_BLOB_OP, "GdaJdbcBlobOp", &info, 0); 70 g_mutex_unlock (®istering); 71 } 72 return type; 73 } 74 75 static void 76 gda_jdbc_blob_op_init (GdaJdbcBlobOp *op, 77 G_GNUC_UNUSED GdaJdbcBlobOpClass *klass) 78 { 79 g_return_if_fail (GDA_IS_JDBC_BLOB_OP (op)); 80 81 op->priv = g_new0 (GdaJdbcBlobOpPrivate, 1); 82 op->priv->blob_obj = NULL; 83 } 84 85 static void 86 gda_jdbc_blob_op_class_init (GdaJdbcBlobOpClass *klass) 87 { 88 GObjectClass *object_class = G_OBJECT_CLASS (klass); 89 GdaBlobOpClass *blob_class = GDA_BLOB_OP_CLASS (klass); 90 91 parent_class = g_type_class_peek_parent (klass); 92 93 object_class->finalize = gda_jdbc_blob_op_finalize; 94 blob_class->get_length = gda_jdbc_blob_op_get_length; 95 blob_class->read = gda_jdbc_blob_op_read; 96 blob_class->write = gda_jdbc_blob_op_write; 97 } 98 99 static void 100 gda_jdbc_blob_op_finalize (GObject * object) 101 { 102 GdaJdbcBlobOp *bop = (GdaJdbcBlobOp *) object; 103 104 g_return_if_fail (GDA_IS_JDBC_BLOB_OP (bop)); 105 106 /* free specific information */ 107 if (bop->priv->blob_obj) 108 gda_value_free (bop->priv->blob_obj); 109 g_free (bop->priv); 110 bop->priv = NULL; 111 112 parent_class->finalize (object); 113 } 114 115 /** 116 * gda_jdbc_blob_op_new_with_jblob 117 * 118 * Steals @blob_op. 119 */ 120 GdaBlobOp * 121 gda_jdbc_blob_op_new_with_jblob (GdaConnection *cnc, JNIEnv *jenv, jobject blob_obj) 122 { 123 GdaJdbcBlobOp *bop; 124 JavaVM *jvm; 125 126 g_return_val_if_fail (GDA_IS_CONNECTION (cnc), NULL); 127 g_return_val_if_fail (blob_obj, NULL); 128 129 if ((*jenv)->GetJavaVM (jenv, &jvm)) 130 g_error ("Could not attach JAVA virtual machine's current thread"); 131 132 bop = g_object_new (GDA_TYPE_JDBC_BLOB_OP, NULL); 133 bop->priv->cnc = cnc; 134 bop->priv->blob_obj = gda_value_new_jni_object (jvm, jenv, blob_obj); 135 136 return GDA_BLOB_OP (bop); 137 } 138 139 /* 140 * Get length request 141 */ 142 static glong 143 gda_jdbc_blob_op_get_length (GdaBlobOp *op) 144 { 145 GdaJdbcBlobOp *bop; 146 GValue *jexec_res; 147 gint error_code; 148 gchar *sql_state; 149 glong retval; 150 JNIEnv *jenv = NULL; 151 gboolean jni_detach; 152 GError *error = NULL; 153 154 g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1); 155 bop = GDA_JDBC_BLOB_OP (op); 156 g_return_val_if_fail (bop->priv, -1); 157 g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1); 158 159 /* fetch JNIEnv */ 160 jenv = _gda_jdbc_get_jenv (&jni_detach, &error); 161 if (!jenv) 162 return -1; 163 164 /* get length */ 165 jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__length, 166 bop->priv->blob_obj, &error_code, &sql_state, &error); 167 if (!jexec_res) { 168 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 169 return -1; 170 } 171 172 _gda_jdbc_release_jenv (jni_detach); 173 174 retval = g_value_get_int64 (jexec_res); 175 gda_value_free (jexec_res); 176 return retval; 177 } 178 179 /* 180 * Blob read request 181 */ 182 static glong 183 gda_jdbc_blob_op_read (GdaBlobOp *op, GdaBlob *blob, glong offset, glong size) 184 { 185 GdaJdbcBlobOp *bop; 186 GdaBinary *bin; 187 gint error_code; 188 gchar *sql_state; 189 GValue *jexec_res; 190 JNIEnv *jenv = NULL; 191 gboolean jni_detach; 192 GError *error = NULL; 193 jbyteArray bytes; 194 195 g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1); 196 bop = GDA_JDBC_BLOB_OP (op); 197 g_return_val_if_fail (bop->priv, -1); 198 g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1); 199 if (offset >= G_MAXINT) 200 return -1; 201 g_return_val_if_fail (blob, -1); 202 203 /* fetch JNIEnv */ 204 jenv = _gda_jdbc_get_jenv (&jni_detach, &error); 205 if (!jenv) 206 return -1; 207 208 /* get data */ 209 jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__read, 210 bop->priv->blob_obj, &error_code, &sql_state, &error, 211 (jlong) offset, (jint) size); 212 if (!jexec_res) { 213 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 214 return -1; 215 } 216 217 /* copy data */ 218 bin = (GdaBinary *) blob; 219 if (bin->data) 220 g_free (bin->data); 221 bytes = (jbyteArray) gda_value_get_jni_object (jexec_res); 222 bin->binary_length = (*jenv)->GetArrayLength (jenv, bytes); 223 bin->data = g_new (guchar, bin->binary_length); 224 (*jenv)->GetByteArrayRegion(jenv, bytes, 0, bin->binary_length, (jbyte *) bin->data); 225 226 _gda_jdbc_release_jenv (jni_detach); 227 gda_value_free (jexec_res); 228 229 return bin->binary_length; 230 } 231 232 /* 233 * Blob write request 234 */ 235 static glong 236 gda_jdbc_blob_op_write (GdaBlobOp *op, GdaBlob *blob, glong offset) 237 { 238 GdaJdbcBlobOp *bop; 239 GdaBinary *bin; 240 gint error_code; 241 gchar *sql_state; 242 GValue *jexec_res; 243 JNIEnv *jenv = NULL; 244 gboolean jni_detach; 245 GError *error = NULL; 246 jbyteArray bytes; 247 glong nbwritten; 248 249 g_return_val_if_fail (GDA_IS_JDBC_BLOB_OP (op), -1); 250 bop = GDA_JDBC_BLOB_OP (op); 251 g_return_val_if_fail (bop->priv, -1); 252 g_return_val_if_fail (GDA_IS_CONNECTION (bop->priv->cnc), -1); 253 g_return_val_if_fail (blob, -1); 254 255 /* fetch JNIEnv */ 256 jenv = _gda_jdbc_get_jenv (&jni_detach, &error); 257 if (!jenv) 258 return -1; 259 260 if (blob->op && (blob->op != op)) { 261 /* use data through blob->op */ 262 #define buf_size 16384 263 gint nread = 0; 264 GdaBlob *tmpblob; 265 266 nbwritten = 0; 267 tmpblob = g_new0 (GdaBlob, 1); 268 gda_blob_set_op (tmpblob, blob->op); 269 270 for (nread = gda_blob_op_read (tmpblob->op, tmpblob, 0, buf_size); 271 nread > 0; 272 nread = gda_blob_op_read (tmpblob->op, tmpblob, nbwritten, buf_size)) { 273 GdaBinary *bin = (GdaBinary *) tmpblob; 274 glong tmp_written; 275 276 bytes = (*jenv)->NewByteArray (jenv, nread); 277 if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) { 278 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 279 _gda_jdbc_release_jenv (jni_detach); 280 gda_blob_free ((gpointer) tmpblob); 281 return -1; 282 } 283 284 (*jenv)->SetByteArrayRegion (jenv, bytes, 0, nread, (jbyte*) bin->data); 285 if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) { 286 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 287 (*jenv)->DeleteLocalRef (jenv, bytes); 288 _gda_jdbc_release_jenv (jni_detach); 289 gda_blob_free ((gpointer) tmpblob); 290 return -1; 291 } 292 293 /* write data */ 294 jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__write, 295 bop->priv->blob_obj, &error_code, 296 &sql_state, &error, (jlong) offset, bytes); 297 (*jenv)->DeleteLocalRef (jenv, bytes); 298 if (!jexec_res) { 299 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 300 _gda_jdbc_release_jenv (jni_detach); 301 gda_blob_free ((gpointer) tmpblob); 302 return -1; 303 } 304 305 tmp_written = g_value_get_int64 (jexec_res); 306 gda_value_free (jexec_res); 307 308 g_assert (tmp_written == nread); 309 310 nbwritten += tmp_written; 311 if (nread < buf_size) 312 /* nothing more to read */ 313 break; 314 } 315 gda_blob_free ((gpointer) tmpblob); 316 } 317 else { 318 /* prepare data to be written using bin->data and bin->binary_length */ 319 bin = (GdaBinary *) blob; 320 bytes = (*jenv)->NewByteArray (jenv, bin->binary_length); 321 if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) { 322 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 323 _gda_jdbc_release_jenv (jni_detach); 324 return -1; 325 } 326 327 (*jenv)->SetByteArrayRegion (jenv, bytes, 0, bin->binary_length, (jbyte*) bin->data); 328 if (jni_wrapper_handle_exception (jenv, &error_code, &sql_state, &error)) { 329 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 330 (*jenv)->DeleteLocalRef (jenv, bytes); 331 _gda_jdbc_release_jenv (jni_detach); 332 return -1; 333 } 334 335 /* write data */ 336 jexec_res = jni_wrapper_method_call (jenv, GdaJBlobOp__write, 337 bop->priv->blob_obj, &error_code, &sql_state, &error, 338 (jlong) offset, bytes); 339 (*jenv)->DeleteLocalRef (jenv, bytes); 340 if (!jexec_res) { 341 _gda_jdbc_make_error (bop->priv->cnc, error_code, sql_state, error); 342 return -1; 343 } 344 nbwritten = g_value_get_int64 (jexec_res); 345 gda_value_free (jexec_res); 346 } 347 _gda_jdbc_release_jenv (jni_detach); 348 349 return nbwritten; 350 } 351