2
* See the file LICENSE for redistribution information.
4
* Copyright (c) 1997-2002
5
* Sleepycat Software. All rights reserved.
10
static const char revid[] = "$Id$";
19
#include "java_util.h"
21
/****************************************************************
26
static int Db_assoc_callback(DB *db,
33
DB_ASSERT(db != NULL);
34
dbinfo = (DB_JAVAINFO *)db->api_internal;
35
return (dbji_call_assoc(dbinfo, db, dbinfo->jdbref,
39
static void Db_feedback_callback(DB *db, int opcode, int percent)
43
DB_ASSERT(db != NULL);
44
dbinfo = (DB_JAVAINFO *)db->api_internal;
45
dbji_call_feedback(dbinfo, db, dbinfo->jdbref, opcode, percent);
48
static int Db_append_recno_callback(DB *db, DBT *dbt, db_recno_t recno)
52
dbinfo = (DB_JAVAINFO *)db->api_internal;
53
return (dbji_call_append_recno(dbinfo, db, dbinfo->jdbref, dbt, recno));
56
static int Db_bt_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
60
dbinfo = (DB_JAVAINFO *)db->api_internal;
61
return (dbji_call_bt_compare(dbinfo, db, dbinfo->jdbref, dbt1, dbt2));
64
static size_t Db_bt_prefix_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
68
dbinfo = (DB_JAVAINFO *)db->api_internal;
69
return (dbji_call_bt_prefix(dbinfo, db, dbinfo->jdbref, dbt1, dbt2));
72
static int Db_dup_compare_callback(DB *db, const DBT *dbt1, const DBT *dbt2)
76
dbinfo = (DB_JAVAINFO *)db->api_internal;
77
return (dbji_call_dup_compare(dbinfo, db, dbinfo->jdbref, dbt1, dbt2));
80
static u_int32_t Db_h_hash_callback(DB *db, const void *data, u_int32_t len)
84
dbinfo = (DB_JAVAINFO *)db->api_internal;
85
return (dbji_call_h_hash(dbinfo, db, dbinfo->jdbref, data, len));
88
static void DbEnv_feedback_callback(DB_ENV *dbenv, int opcode, int percent)
90
DB_ENV_JAVAINFO *dbinfo;
92
DB_ASSERT(dbenv != NULL);
93
dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal;
94
dbjie_call_feedback(dbinfo, dbenv, dbinfo->jenvref, opcode, percent);
97
static int DbEnv_rep_transport_callback(DB_ENV *dbenv,
98
const DBT *control, const DBT *rec,
99
int envid, u_int32_t flags)
101
DB_ENV_JAVAINFO *dbinfo;
103
dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal;
104
return (dbjie_call_rep_transport(dbinfo, dbenv,
105
dbinfo->jenvref, control, rec, envid, (int)flags));
108
static int DbEnv_app_dispatch_callback(DB_ENV *dbenv, DBT *dbt,
109
DB_LSN *lsn, db_recops recops)
111
DB_ENV_JAVAINFO *dbinfo;
113
DB_ASSERT(dbenv != NULL);
114
dbinfo = (DB_ENV_JAVAINFO *)dbenv->api2_internal;
115
return (dbjie_call_app_dispatch(dbinfo, dbenv, dbinfo->jenvref, dbt,
119
/****************************************************************
121
* Implementation of class DBT_javainfo
129
/*XXX should return err*/
130
if ((err = __os_malloc(NULL, sizeof(DBT_JAVAINFO), &dbjit)) != 0)
133
memset(dbjit, 0, sizeof(DBT_JAVAINFO));
137
void dbjit_destroy(DBT_JAVAINFO *dbjit)
139
DB_ASSERT(!F_ISSET(dbjit, DBT_JAVAINFO_LOCKED));
141
memset(dbjit, 0, sizeof(DBT_JAVAINFO));
142
(void)__os_free(NULL, dbjit);
145
/****************************************************************
147
* Implementation of class DB_ENV_JAVAINFO
150
/* create/initialize an object */
152
dbjie_construct(JNIEnv *jnienv,
154
jobject default_errcall,
157
DB_ENV_JAVAINFO *dbjie;
160
/*XXX should return err*/
161
if ((err = __os_malloc(NULL, sizeof(DB_ENV_JAVAINFO), &dbjie)) != 0)
163
memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO));
164
dbjie->is_dbopen = is_dbopen;
166
if ((*jnienv)->GetJavaVM(jnienv, &dbjie->javavm) != 0) {
167
__os_free(NULL, dbjie);
168
report_exception(jnienv, "cannot get Java VM", 0, 0);
173
* The default error call just prints to the 'System.err'
174
* stream. If the user does set_errcall to null, we'll
175
* want to have a reference to set it back to.
177
* Why do we have always set db_errcall to our own callback?
178
* Because it makes the interaction between setting the
179
* error prefix, error stream, and user's error callback
182
dbjie->default_errcall = NEW_GLOBAL_REF(jnienv, default_errcall);
183
dbjie->errcall = NEW_GLOBAL_REF(jnienv, default_errcall);
184
dbjie->jenvref = NEW_GLOBAL_REF(jnienv, jenv);
188
/* release all objects held by this this one */
189
void dbjie_dealloc(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
191
if (dbjie->feedback != NULL) {
192
DELETE_GLOBAL_REF(jnienv, dbjie->feedback);
193
dbjie->feedback = NULL;
195
if (dbjie->app_dispatch != NULL) {
196
DELETE_GLOBAL_REF(jnienv, dbjie->app_dispatch);
197
dbjie->app_dispatch = NULL;
199
if (dbjie->errcall != NULL) {
200
DELETE_GLOBAL_REF(jnienv, dbjie->errcall);
201
dbjie->errcall = NULL;
203
if (dbjie->default_errcall != NULL) {
204
DELETE_GLOBAL_REF(jnienv, dbjie->default_errcall);
205
dbjie->default_errcall = NULL;
207
if (dbjie->jenvref != NULL) {
208
DELETE_GLOBAL_REF(jnienv, dbjie->jenvref);
209
dbjie->jenvref = NULL;
212
if (dbjie->conflict != NULL) {
213
__os_free(NULL, dbjie->conflict);
214
dbjie->conflict = NULL;
215
dbjie->conflict_size = 0;
217
if (dbjie->errpfx != NULL) {
218
__os_free(NULL, dbjie->errpfx);
219
dbjie->errpfx = NULL;
223
/* free this object, releasing anything allocated on its behalf */
224
void dbjie_destroy(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
226
dbjie_dealloc(dbjie, jnienv);
229
memset(dbjie, 0, sizeof(DB_ENV_JAVAINFO));
230
(void)__os_free(NULL, dbjie);
234
* Attach to the current thread that is running and
235
* return that. We use the java virtual machine
236
* that we saved in the constructor.
239
dbjie_get_jnienv(DB_ENV_JAVAINFO *dbjie)
243
* Different versions of the JNI disagree on the signature
244
* for AttachCurrentThread. The most recent documentation
245
* seems to say that (JNIEnv **) is correct, but newer
246
* JNIs seem to use (void **), oddly enough.
248
#ifdef JNI_VERSION_1_2
251
JNIEnv *attachret = 0;
255
* This should always succeed, as we are called via
256
* some Java activity. I think therefore I am (a thread).
258
if ((*dbjie->javavm)->AttachCurrentThread(dbjie->javavm, &attachret, 0)
262
return ((JNIEnv *)attachret);
266
dbjie_get_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv)
268
return (get_java_string(jnienv, dbjie->errpfx));
272
dbjie_set_errcall(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jobject new_errcall)
275
* If the new_errcall is null, we'll set the error call
276
* to the default one.
278
if (new_errcall == NULL)
279
new_errcall = dbjie->default_errcall;
281
DELETE_GLOBAL_REF(jnienv, dbjie->errcall);
282
dbjie->errcall = NEW_GLOBAL_REF(jnienv, new_errcall);
286
dbjie_set_errpfx(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv, jstring errpfx)
288
if (dbjie->errpfx != NULL)
289
__os_free(NULL, dbjie->errpfx);
292
dbjie->errpfx = get_c_string(jnienv, errpfx);
294
dbjie->errpfx = NULL;
298
dbjie_set_conflict(DB_ENV_JAVAINFO *dbjie, u_char *newarr, size_t size)
300
if (dbjie->conflict != NULL)
301
(void)__os_free(NULL, dbjie->conflict);
302
dbjie->conflict = newarr;
303
dbjie->conflict_size = size;
306
void dbjie_set_feedback_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
307
DB_ENV *dbenv, jobject jfeedback)
311
if (dbjie->feedback != NULL) {
312
DELETE_GLOBAL_REF(jnienv, dbjie->feedback);
314
if (jfeedback == NULL) {
315
if ((err = dbenv->set_feedback(dbenv, NULL)) != 0)
316
report_exception(jnienv, "set_feedback failed",
320
if ((err = dbenv->set_feedback(dbenv,
321
DbEnv_feedback_callback)) != 0)
322
report_exception(jnienv, "set_feedback failed",
326
dbjie->feedback = NEW_GLOBAL_REF(jnienv, jfeedback);
329
void dbjie_call_feedback(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv,
330
int opcode, int percent)
333
jclass feedback_class;
336
COMPQUIET(dbenv, NULL);
337
jnienv = dbjie_get_jnienv(dbjie);
338
if (jnienv == NULL) {
339
fprintf(stderr, "Cannot attach to current thread!\n");
343
if ((feedback_class =
344
get_class(jnienv, name_DbEnvFeedback)) == NULL) {
345
fprintf(stderr, "Cannot find callback class %s\n",
347
return; /* An exception has been posted. */
349
id = (*jnienv)->GetMethodID(jnienv, feedback_class,
351
"(Lcom/sleepycat/db/DbEnv;II)V");
353
fprintf(stderr, "Cannot find callback method feedback\n");
357
(*jnienv)->CallVoidMethod(jnienv, dbjie->feedback, id,
358
jenv, (jint)opcode, (jint)percent);
361
void dbjie_set_rep_transport_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
362
DB_ENV *dbenv, int id, jobject jtransport)
366
if (dbjie->rep_transport != NULL)
367
DELETE_GLOBAL_REF(jnienv, dbjie->rep_transport);
369
err = dbenv->set_rep_transport(dbenv, id,
370
DbEnv_rep_transport_callback);
371
verify_return(jnienv, err, 0);
373
dbjie->rep_transport = NEW_GLOBAL_REF(jnienv, jtransport);
376
int dbjie_call_rep_transport(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv,
377
jobject jenv, const DBT *control,
378
const DBT *rec, int flags, int envid)
381
jclass rep_transport_class;
383
jobject jcdbt, jrdbt;
385
COMPQUIET(dbenv, NULL);
386
jnienv = dbjie_get_jnienv(dbjie);
387
if (jnienv == NULL) {
388
fprintf(stderr, "Cannot attach to current thread!\n");
392
if ((rep_transport_class =
393
get_class(jnienv, name_DbRepTransport)) == NULL) {
394
fprintf(stderr, "Cannot find callback class %s\n",
395
name_DbRepTransport);
396
return (0); /* An exception has been posted. */
398
jid = (*jnienv)->GetMethodID(jnienv, rep_transport_class,
400
"(Lcom/sleepycat/db/DbEnv;"
401
"Lcom/sleepycat/db/Dbt;"
402
"Lcom/sleepycat/db/Dbt;II)I");
405
fprintf(stderr, "Cannot find callback method send\n");
409
jcdbt = get_const_Dbt(jnienv, control, NULL);
410
jrdbt = get_const_Dbt(jnienv, rec, NULL);
412
return (*jnienv)->CallIntMethod(jnienv, dbjie->rep_transport, jid, jenv,
413
jcdbt, jrdbt, flags, envid);
416
void dbjie_set_app_dispatch_object(DB_ENV_JAVAINFO *dbjie, JNIEnv *jnienv,
417
DB_ENV *dbenv, jobject japp_dispatch)
421
if (dbjie->app_dispatch != NULL) {
422
DELETE_GLOBAL_REF(jnienv, dbjie->app_dispatch);
424
if (japp_dispatch == NULL) {
425
if ((err = dbenv->set_app_dispatch(dbenv, NULL)) != 0)
426
report_exception(jnienv, "set_app_dispatch failed",
430
if ((err = dbenv->set_app_dispatch(dbenv,
431
DbEnv_app_dispatch_callback)) != 0)
432
report_exception(jnienv, "set_app_dispatch failed",
436
dbjie->app_dispatch = NEW_GLOBAL_REF(jnienv, japp_dispatch);
439
int dbjie_call_app_dispatch(DB_ENV_JAVAINFO *dbjie, DB_ENV *dbenv, jobject jenv,
440
DBT *dbt, DB_LSN *lsn, int recops)
443
jclass app_dispatch_class;
448
COMPQUIET(dbenv, NULL);
449
jnienv = dbjie_get_jnienv(dbjie);
450
if (jnienv == NULL) {
451
fprintf(stderr, "Cannot attach to current thread!\n");
455
if ((app_dispatch_class =
456
get_class(jnienv, name_DbTxnRecover)) == NULL) {
457
fprintf(stderr, "Cannot find callback class %s\n",
459
return (0); /* An exception has been posted. */
461
id = (*jnienv)->GetMethodID(jnienv, app_dispatch_class,
463
"(Lcom/sleepycat/db/DbEnv;"
464
"Lcom/sleepycat/db/Dbt;"
465
"Lcom/sleepycat/db/DbLsn;"
468
fprintf(stderr, "Cannot find callback method app_dispatch\n");
472
jdbt = get_Dbt(jnienv, dbt, NULL);
477
jlsn = get_DbLsn(jnienv, *lsn);
479
return (*jnienv)->CallIntMethod(jnienv, dbjie->app_dispatch, id, jenv,
483
jobject dbjie_get_errcall(DB_ENV_JAVAINFO *dbjie)
485
return (dbjie->errcall);
488
jint dbjie_is_dbopen(DB_ENV_JAVAINFO *dbjie)
490
return (dbjie->is_dbopen);
493
/****************************************************************
495
* Implementation of class DB_JAVAINFO
498
DB_JAVAINFO *dbji_construct(JNIEnv *jnienv, jobject jdb, jint flags)
503
/*XXX should return err*/
504
if ((err = __os_malloc(NULL, sizeof(DB_JAVAINFO), &dbji)) != 0)
507
memset(dbji, 0, sizeof(DB_JAVAINFO));
509
if ((*jnienv)->GetJavaVM(jnienv, &dbji->javavm) != 0) {
510
report_exception(jnienv, "cannot get Java VM", 0, 0);
511
(void)__os_free(NULL, dbji);
514
dbji->jdbref = NEW_GLOBAL_REF(jnienv, jdb);
515
dbji->construct_flags = flags;
520
dbji_dealloc(DB_JAVAINFO *dbji, JNIEnv *jnienv)
522
if (dbji->append_recno != NULL) {
523
DELETE_GLOBAL_REF(jnienv, dbji->append_recno);
524
dbji->append_recno = NULL;
526
if (dbji->assoc != NULL) {
527
DELETE_GLOBAL_REF(jnienv, dbji->assoc);
530
if (dbji->bt_compare != NULL) {
531
DELETE_GLOBAL_REF(jnienv, dbji->bt_compare);
532
dbji->bt_compare = NULL;
534
if (dbji->bt_prefix != NULL) {
535
DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix);
536
dbji->bt_prefix = NULL;
538
if (dbji->dup_compare != NULL) {
539
DELETE_GLOBAL_REF(jnienv, dbji->dup_compare);
540
dbji->dup_compare = NULL;
542
if (dbji->feedback != NULL) {
543
DELETE_GLOBAL_REF(jnienv, dbji->feedback);
544
dbji->feedback = NULL;
546
if (dbji->h_hash != NULL) {
547
DELETE_GLOBAL_REF(jnienv, dbji->h_hash);
550
if (dbji->jdbref != NULL) {
551
DELETE_GLOBAL_REF(jnienv, dbji->jdbref);
557
dbji_destroy(DB_JAVAINFO *dbji, JNIEnv *jnienv)
559
dbji_dealloc(dbji, jnienv);
560
__os_free(NULL, dbji);
563
JNIEnv *dbji_get_jnienv(DB_JAVAINFO *dbji)
567
* Different versions of the JNI disagree on the signature
568
* for AttachCurrentThread. The most recent documentation
569
* seems to say that (JNIEnv **) is correct, but newer
570
* JNIs seem to use (void **), oddly enough.
572
#ifdef JNI_VERSION_1_2
575
JNIEnv *attachret = 0;
579
* This should always succeed, as we are called via
580
* some Java activity. I think therefore I am (a thread).
582
if ((*dbji->javavm)->AttachCurrentThread(dbji->javavm, &attachret, 0)
586
return ((JNIEnv *)attachret);
589
jint dbji_get_flags(DB_JAVAINFO *dbji)
591
return (dbji->construct_flags);
594
void dbji_set_feedback_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
595
DB *db, jobject jfeedback)
597
jclass feedback_class;
599
if (dbji->feedback_method_id == NULL) {
600
if ((feedback_class =
601
get_class(jnienv, name_DbFeedback)) == NULL)
602
return; /* An exception has been posted. */
603
dbji->feedback_method_id =
604
(*jnienv)->GetMethodID(jnienv, feedback_class,
606
"(Lcom/sleepycat/db/Db;II)V");
607
if (dbji->feedback_method_id == NULL) {
610
* We should really have a better way
611
* to translate this to a Java exception class.
612
* In theory, it shouldn't happen.
614
report_exception(jnienv, "Cannot find callback method",
620
if (dbji->feedback != NULL) {
621
DELETE_GLOBAL_REF(jnienv, dbji->feedback);
623
if (jfeedback == NULL) {
624
db->set_feedback(db, NULL);
627
db->set_feedback(db, Db_feedback_callback);
630
dbji->feedback = NEW_GLOBAL_REF(jnienv, jfeedback);
634
void dbji_call_feedback(DB_JAVAINFO *dbji, DB *db, jobject jdb,
635
int opcode, int percent)
640
jnienv = dbji_get_jnienv(dbji);
641
if (jnienv == NULL) {
642
fprintf(stderr, "Cannot attach to current thread!\n");
646
DB_ASSERT(dbji->feedback_method_id != NULL);
647
(*jnienv)->CallVoidMethod(jnienv, dbji->feedback,
648
dbji->feedback_method_id,
649
jdb, (jint)opcode, (jint)percent);
652
void dbji_set_append_recno_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
653
DB *db, jobject jcallback)
655
jclass append_recno_class;
657
if (dbji->append_recno_method_id == NULL) {
658
if ((append_recno_class =
659
get_class(jnienv, name_DbAppendRecno)) == NULL)
660
return; /* An exception has been posted. */
661
dbji->append_recno_method_id =
662
(*jnienv)->GetMethodID(jnienv, append_recno_class,
664
"(Lcom/sleepycat/db/Db;"
665
"Lcom/sleepycat/db/Dbt;I)V");
666
if (dbji->append_recno_method_id == NULL) {
669
* We should really have a better way
670
* to translate this to a Java exception class.
671
* In theory, it shouldn't happen.
673
report_exception(jnienv, "Cannot find callback method",
679
if (dbji->append_recno != NULL) {
680
DELETE_GLOBAL_REF(jnienv, dbji->append_recno);
682
if (jcallback == NULL) {
683
db->set_append_recno(db, NULL);
686
db->set_append_recno(db, Db_append_recno_callback);
689
dbji->append_recno = NEW_GLOBAL_REF(jnienv, jcallback);
692
extern int dbji_call_append_recno(DB_JAVAINFO *dbji, DB *db, jobject jdb,
693
DBT *dbt, jint recno)
703
jnienv = dbji_get_jnienv(dbji);
705
if (jnienv == NULL) {
706
fprintf(stderr, "Cannot attach to current thread!\n");
710
jresult = get_Dbt(jnienv, dbt, &dbtji);
712
DB_ASSERT(dbji->append_recno_method_id != NULL);
713
(*jnienv)->CallVoidMethod(jnienv, dbji->append_recno,
714
dbji->append_recno_method_id,
715
jdb, jresult, recno);
718
* The underlying C API requires that an errno be returned
719
* on error. Java users know nothing of errnos, so we
720
* allow them to throw exceptions instead. We leave the
721
* exception in place and return DB_JAVA_CALLBACK to the C API
722
* that called us. Eventually the DB->get will fail and
723
* when java prepares to throw an exception in
724
* report_exception(), this will be spotted as a special case,
725
* and the original exception will be preserved.
727
* Note: we have sometimes noticed strange behavior with
728
* exceptions under Linux 1.1.7 JVM. (i.e. multiple calls
729
* to ExceptionOccurred() may report different results).
730
* Currently we don't know of any problems related to this
731
* in our code, but if it pops up in the future, users are
732
* encouranged to get a more recent JVM.
734
if ((*jnienv)->ExceptionOccurred(jnienv) != NULL)
735
return (DB_JAVA_CALLBACK);
738
* Now get the DBT back from java, because the user probably
739
* changed it. We'll have to copy back the array too and let
740
* our caller free it.
742
* We expect that the user *has* changed the DBT (why else would
743
* they set up an append_recno callback?) so we don't
744
* worry about optimizing the unchanged case.
746
if ((err = locked_dbt_get(&lresult, jnienv, dbenv, jresult, inOp)) != 0)
749
memcpy(dbt, &lresult.javainfo->dbt, sizeof(DBT));
750
if ((err = __os_malloc(dbenv, dbt->size, &bytearray)) != 0)
753
memcpy(bytearray, dbt->data, dbt->size);
754
dbt->data = bytearray;
755
dbt->flags |= DB_DBT_APPMALLOC;
758
locked_dbt_put(&lresult, jnienv, dbenv);
762
void dbji_set_assoc_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
763
DB *db, DB_TXN *txn, DB *second,
764
jobject jcallback, int flags)
769
if (dbji->assoc_method_id == NULL) {
771
get_class(jnienv, name_DbSecondaryKeyCreate)) == NULL)
772
return; /* An exception has been posted. */
773
dbji->assoc_method_id =
774
(*jnienv)->GetMethodID(jnienv, assoc_class,
775
"secondary_key_create",
776
"(Lcom/sleepycat/db/Db;"
777
"Lcom/sleepycat/db/Dbt;"
778
"Lcom/sleepycat/db/Dbt;"
779
"Lcom/sleepycat/db/Dbt;)I");
780
if (dbji->assoc_method_id == NULL) {
783
* We should really have a better way
784
* to translate this to a Java exception class.
785
* In theory, it shouldn't happen.
787
report_exception(jnienv, "Cannot find callback method",
793
if (dbji->assoc != NULL) {
794
DELETE_GLOBAL_REF(jnienv, dbji->assoc);
798
if (jcallback == NULL)
799
err = db->associate(db, txn, second, NULL, flags);
801
err = db->associate(db, txn, second, Db_assoc_callback, flags);
803
if (verify_return(jnienv, err, 0))
804
dbji->assoc = NEW_GLOBAL_REF(jnienv, jcallback);
807
extern int dbji_call_assoc(DB_JAVAINFO *dbji, DB *db, jobject jdb,
808
const DBT *key, const DBT *value, DBT *result)
819
jnienv = dbji_get_jnienv(dbji);
820
if (jnienv == NULL) {
821
fprintf(stderr, "Cannot attach to current thread!\n");
825
DB_ASSERT(dbji->assoc_method_id != NULL);
828
jresult = create_default_object(jnienv, name_DBT);
830
retval = (*jnienv)->CallIntMethod(jnienv, dbji->assoc,
831
dbji->assoc_method_id, jdb,
832
get_const_Dbt(jnienv, key, NULL),
833
get_const_Dbt(jnienv, value, NULL),
838
if ((*jnienv)->ExceptionOccurred(jnienv) != NULL)
839
return (DB_JAVA_CALLBACK);
841
if ((err = locked_dbt_get(&lresult, jnienv, dbenv, jresult, inOp)) != 0)
844
sz = lresult.javainfo->dbt.size;
846
bytearray = (u_char *)lresult.javainfo->dbt.data;
849
* If the byte array is in the range of one of the
850
* arrays passed to us we can use it directly.
851
* If not, we must create our own array and
852
* fill it in with the java array. Since
853
* the java array may disappear and we don't
854
* want to keep its memory locked indefinitely,
855
* we cannot just pin the array.
857
* XXX consider pinning the array, and having
858
* some way for the C layer to notify the java
859
* layer when it can be unpinned.
861
if ((bytearray < (u_char *)key->data ||
862
bytearray + sz > (u_char *)key->data + key->size) &&
863
(bytearray < (u_char *)value->data ||
864
bytearray + sz > (u_char *)value->data + value->size)) {
866
result->flags |= DB_DBT_APPMALLOC;
867
if ((err = __os_malloc(dbenv, sz, &bytearray)) != 0)
869
memcpy(bytearray, lresult.javainfo->dbt.data, sz);
871
result->data = bytearray;
875
locked_dbt_put(&lresult, jnienv, dbenv);
879
void dbji_set_bt_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
880
DB *db, jobject jcompare)
882
jclass bt_compare_class;
884
if (dbji->bt_compare_method_id == NULL) {
885
if ((bt_compare_class =
886
get_class(jnienv, name_DbBtreeCompare)) == NULL)
887
return; /* An exception has been posted. */
888
dbji->bt_compare_method_id =
889
(*jnienv)->GetMethodID(jnienv, bt_compare_class,
891
"(Lcom/sleepycat/db/Db;"
892
"Lcom/sleepycat/db/Dbt;"
893
"Lcom/sleepycat/db/Dbt;)I");
894
if (dbji->bt_compare_method_id == NULL) {
897
* We should really have a better way
898
* to translate this to a Java exception class.
899
* In theory, it shouldn't happen.
901
report_exception(jnienv, "Cannot find callback method",
907
if (dbji->bt_compare != NULL) {
908
DELETE_GLOBAL_REF(jnienv, dbji->bt_compare);
910
if (jcompare == NULL) {
911
db->set_bt_compare(db, NULL);
914
db->set_bt_compare(db, Db_bt_compare_callback);
917
dbji->bt_compare = NEW_GLOBAL_REF(jnienv, jcompare);
920
int dbji_call_bt_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb,
921
const DBT *dbt1, const DBT *dbt2)
924
jobject jdbt1, jdbt2;
927
jnienv = dbji_get_jnienv(dbji);
928
if (jnienv == NULL) {
929
fprintf(stderr, "Cannot attach to current thread!\n");
933
jdbt1 = get_const_Dbt(jnienv, dbt1, NULL);
934
jdbt2 = get_const_Dbt(jnienv, dbt2, NULL);
936
DB_ASSERT(dbji->bt_compare_method_id != NULL);
937
return (*jnienv)->CallIntMethod(jnienv, dbji->bt_compare,
938
dbji->bt_compare_method_id,
942
void dbji_set_bt_prefix_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
943
DB *db, jobject jprefix)
945
jclass bt_prefix_class;
947
if (dbji->bt_prefix_method_id == NULL) {
948
if ((bt_prefix_class =
949
get_class(jnienv, name_DbBtreePrefix)) == NULL)
950
return; /* An exception has been posted. */
951
dbji->bt_prefix_method_id =
952
(*jnienv)->GetMethodID(jnienv, bt_prefix_class,
954
"(Lcom/sleepycat/db/Db;"
955
"Lcom/sleepycat/db/Dbt;"
956
"Lcom/sleepycat/db/Dbt;)I");
957
if (dbji->bt_prefix_method_id == NULL) {
960
* We should really have a better way
961
* to translate this to a Java exception class.
962
* In theory, it shouldn't happen.
964
report_exception(jnienv, "Cannot find callback method",
970
if (dbji->bt_prefix != NULL) {
971
DELETE_GLOBAL_REF(jnienv, dbji->bt_prefix);
973
if (jprefix == NULL) {
974
db->set_bt_prefix(db, NULL);
977
db->set_bt_prefix(db, Db_bt_prefix_callback);
980
dbji->bt_prefix = NEW_GLOBAL_REF(jnienv, jprefix);
983
size_t dbji_call_bt_prefix(DB_JAVAINFO *dbji, DB *db, jobject jdb,
984
const DBT *dbt1, const DBT *dbt2)
987
jobject jdbt1, jdbt2;
990
jnienv = dbji_get_jnienv(dbji);
991
if (jnienv == NULL) {
992
fprintf(stderr, "Cannot attach to current thread!\n");
996
jdbt1 = get_const_Dbt(jnienv, dbt1, NULL);
997
jdbt2 = get_const_Dbt(jnienv, dbt2, NULL);
999
DB_ASSERT(dbji->bt_prefix_method_id != NULL);
1000
return (size_t)(*jnienv)->CallIntMethod(jnienv, dbji->bt_prefix,
1001
dbji->bt_prefix_method_id,
1005
void dbji_set_dup_compare_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
1006
DB *db, jobject jcompare)
1008
jclass dup_compare_class;
1010
if (dbji->dup_compare_method_id == NULL) {
1011
if ((dup_compare_class =
1012
get_class(jnienv, name_DbDupCompare)) == NULL)
1013
return; /* An exception has been posted. */
1014
dbji->dup_compare_method_id =
1015
(*jnienv)->GetMethodID(jnienv, dup_compare_class,
1017
"(Lcom/sleepycat/db/Db;"
1018
"Lcom/sleepycat/db/Dbt;"
1019
"Lcom/sleepycat/db/Dbt;)I");
1020
if (dbji->dup_compare_method_id == NULL) {
1023
* We should really have a better way
1024
* to translate this to a Java exception class.
1025
* In theory, it shouldn't happen.
1027
report_exception(jnienv, "Cannot find callback method",
1033
if (dbji->dup_compare != NULL)
1034
DELETE_GLOBAL_REF(jnienv, dbji->dup_compare);
1036
if (jcompare == NULL)
1037
db->set_dup_compare(db, NULL);
1039
db->set_dup_compare(db, Db_dup_compare_callback);
1041
dbji->dup_compare = NEW_GLOBAL_REF(jnienv, jcompare);
1044
int dbji_call_dup_compare(DB_JAVAINFO *dbji, DB *db, jobject jdb,
1045
const DBT *dbt1, const DBT *dbt2)
1048
jobject jdbt1, jdbt2;
1050
COMPQUIET(db, NULL);
1051
jnienv = dbji_get_jnienv(dbji);
1052
if (jnienv == NULL) {
1053
fprintf(stderr, "Cannot attach to current thread!\n");
1057
jdbt1 = get_const_Dbt(jnienv, dbt1, NULL);
1058
jdbt2 = get_const_Dbt(jnienv, dbt2, NULL);
1060
DB_ASSERT(dbji->dup_compare_method_id != NULL);
1061
return (*jnienv)->CallIntMethod(jnienv, dbji->dup_compare,
1062
dbji->dup_compare_method_id,
1066
void dbji_set_h_hash_object(DB_JAVAINFO *dbji, JNIEnv *jnienv,
1067
DB *db, jobject jhash)
1069
jclass h_hash_class;
1071
if (dbji->h_hash_method_id == NULL) {
1073
get_class(jnienv, name_DbHash)) == NULL)
1074
return; /* An exception has been posted. */
1075
dbji->h_hash_method_id =
1076
(*jnienv)->GetMethodID(jnienv, h_hash_class,
1078
"(Lcom/sleepycat/db/Db;"
1080
if (dbji->h_hash_method_id == NULL) {
1083
* We should really have a better way
1084
* to translate this to a Java exception class.
1085
* In theory, it shouldn't happen.
1087
report_exception(jnienv, "Cannot find callback method",
1093
if (dbji->h_hash != NULL)
1094
DELETE_GLOBAL_REF(jnienv, dbji->h_hash);
1097
db->set_h_hash(db, NULL);
1099
db->set_h_hash(db, Db_h_hash_callback);
1101
dbji->h_hash = NEW_GLOBAL_REF(jnienv, jhash);
1104
int dbji_call_h_hash(DB_JAVAINFO *dbji, DB *db, jobject jdb,
1105
const void *data, int len)
1110
COMPQUIET(db, NULL);
1111
jnienv = dbji_get_jnienv(dbji);
1112
if (jnienv == NULL) {
1113
fprintf(stderr, "Cannot attach to current thread!\n");
1117
DB_ASSERT(dbji->h_hash_method_id != NULL);
1119
if ((jdata = (*jnienv)->NewByteArray(jnienv, len)) == NULL)
1120
return (0); /* An exception has been posted by the JVM */
1121
(*jnienv)->SetByteArrayRegion(jnienv, jdata, 0, len, (void *)data);
1122
return (*jnienv)->CallIntMethod(jnienv, dbji->h_hash,
1123
dbji->h_hash_method_id,