1/* Callbacks */
2%define JAVA_CALLBACK(_sig, _jclass, _name)
3JAVA_TYPEMAP(_sig, _jclass, jboolean)
4%typemap(jtype) _sig "boolean"
5%typemap(javain) _sig %{ (_name##_handler = $javainput) != null %}
6
7/*
8 * The Java object is stored in the Db or DbEnv class.
9 * Here we only care whether it is non-NULL.
10 */
11%typemap(in) _sig %{
12	$1 = ($input == JNI_TRUE) ? __dbj_##_name : NULL;
13%}
14%enddef
15
16%{
17static void __dbj_error(const DB_ENV *dbenv,
18    const char *prefix, const char *msg)
19{
20	JNIEnv *jenv = __dbj_get_jnienv();
21	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
22	jobject jmsg;
23
24	COMPQUIET(prefix, NULL);
25
26	if (jdbenv != NULL){
27		jmsg = (*jenv)->NewStringUTF(jenv, msg);
28		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv, dbenv_class,
29		    errcall_method, jmsg);
30		(*jenv)->DeleteLocalRef(jenv, jmsg);
31	}
32}
33
34static void __dbj_env_feedback(DB_ENV *dbenv, int opcode, int percent)
35{
36	JNIEnv *jenv = __dbj_get_jnienv();
37	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
38
39	if (jdbenv != NULL)
40		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv, dbenv_class,
41		    env_feedback_method, opcode, percent);
42}
43
44static void __dbj_message(const DB_ENV *dbenv, const char *msg)
45{
46	JNIEnv *jenv = __dbj_get_jnienv();
47	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
48	jobject jmsg;
49
50	if (jdbenv != NULL){
51		jmsg = (*jenv)->NewStringUTF(jenv, msg);
52		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv, dbenv_class,
53		    msgcall_method, jmsg);
54		(*jenv)->DeleteLocalRef(jenv, jmsg);
55	}
56}
57
58static void __dbj_panic(DB_ENV *dbenv, int err)
59{
60	JNIEnv *jenv = __dbj_get_jnienv();
61	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
62
63	if (jdbenv != NULL)
64		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv, dbenv_class,
65		    paniccall_method,
66		    __dbj_get_except(jenv, err, NULL, NULL, jdbenv));
67}
68
69static int __dbj_app_dispatch(DB_ENV *dbenv,
70    DBT *dbt, DB_LSN *lsn, db_recops recops)
71{
72	JNIEnv *jenv = __dbj_get_jnienv();
73	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
74	jobject jdbt, jlsn;
75	jbyteArray jdbtarr;
76	int ret;
77
78	if (jdbenv == NULL)
79		return (EINVAL);
80
81	jdbt = (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
82	__dbj_dbt_copyout(jenv, dbt, &jdbtarr, jdbt);
83	if (jdbt == NULL)
84		return (ENOMEM); /* An exception is pending */
85
86	jlsn = (lsn == NULL) ? NULL : __dbj_wrap_DB_LSN(jenv, lsn);
87
88	ret = (*jenv)->CallNonvirtualIntMethod(jenv, jdbenv, dbenv_class,
89	    app_dispatch_method, jdbt, jlsn, recops);
90
91	if ((*jenv)->ExceptionOccurred(jenv)) {
92		/* The exception will be thrown, so this could be any error. */
93		ret = EINVAL;
94	}
95
96	(*jenv)->DeleteLocalRef(jenv, jdbtarr);
97	(*jenv)->DeleteLocalRef(jenv, jdbt);
98	if (jlsn != NULL)
99		(*jenv)->DeleteLocalRef(jenv, jlsn);
100
101	return (ret);
102}
103
104static void __dbj_event_notify(DB_ENV *dbenv, u_int32_t event_id, void * info)
105{
106	JNIEnv *jenv = __dbj_get_jnienv();
107	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
108
109	if (jdbenv == NULL)
110		return ;
111
112	switch (event_id) {
113	case DB_EVENT_PANIC:
114		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
115		    dbenv_class, panic_event_notify_method);
116		break;
117	case DB_EVENT_REP_CLIENT:
118		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
119		    dbenv_class, rep_client_event_notify_method);
120		break;
121	case DB_EVENT_REP_ELECTED:
122		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
123		    dbenv_class, rep_elected_event_notify_method);
124		break;
125	case DB_EVENT_REP_MASTER:
126		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
127		    dbenv_class, rep_master_event_notify_method);
128		break;
129	case DB_EVENT_REP_NEWMASTER:
130		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
131		    dbenv_class, rep_new_master_event_notify_method,
132		    *(int*)info);
133		break;
134	case DB_EVENT_REP_PERM_FAILED:
135		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
136		    dbenv_class, rep_perm_failed_event_notify_method);
137		break;
138	case DB_EVENT_REP_STARTUPDONE:
139		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
140		    dbenv_class, rep_startup_done_event_notify_method);
141		break;
142	case DB_EVENT_WRITE_FAILED:
143		(*jenv)->CallNonvirtualVoidMethod(jenv, jdbenv,
144		    dbenv_class, write_failed_event_notify_method,
145		    *(int*)info);
146		break;
147	default:
148                dbenv->errx(dbenv, "Unhandled event callback in the Java API");
149                DB_ASSERT(dbenv->env, 0);
150	}
151}
152
153static int __dbj_rep_transport(DB_ENV *dbenv,
154    const DBT *control, const DBT *rec, const DB_LSN *lsn, int envid,
155    u_int32_t flags)
156{
157	JNIEnv *jenv = __dbj_get_jnienv();
158	jobject jdbenv = (jobject)DB_ENV_INTERNAL(dbenv);
159	jobject jcontrol, jrec, jlsn;
160	jbyteArray jcontrolarr, jrecarr;
161	int ret;
162
163	if (jdbenv == NULL)
164		return (EINVAL);
165
166	jcontrol = (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
167	jrec = (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
168	if (jcontrol == NULL || jrec == NULL)
169		return (ENOMEM); /* An exception is pending */
170
171	__dbj_dbt_copyout(jenv, control, &jcontrolarr, jcontrol);
172	__dbj_dbt_copyout(jenv, rec, &jrecarr, jrec);
173	jlsn = (lsn == NULL) ? NULL : __dbj_wrap_DB_LSN(jenv, (DB_LSN *)lsn);
174
175	if (jcontrolarr == NULL || jrecarr == NULL)
176		return (ENOMEM); /* An exception is pending */
177
178	ret = (*jenv)->CallNonvirtualIntMethod(jenv, jdbenv, dbenv_class,
179	    rep_transport_method, jcontrol, jrec, jlsn, envid, flags);
180
181	if ((*jenv)->ExceptionOccurred(jenv)) {
182		/* The exception will be thrown, so this could be any error. */
183		ret = EINVAL;
184	}
185
186	(*jenv)->DeleteLocalRef(jenv, jrecarr);
187	(*jenv)->DeleteLocalRef(jenv, jcontrolarr);
188	(*jenv)->DeleteLocalRef(jenv, jrec);
189	(*jenv)->DeleteLocalRef(jenv, jcontrol);
190	if (jlsn != NULL)
191		(*jenv)->DeleteLocalRef(jenv, jlsn);
192
193	return (ret);
194}
195
196static int __dbj_foreignkey_nullify(DB *db,
197    const DBT *key, DBT *data, const DBT *skey, int *changed)
198{
199	DBT_LOCKED lresult;
200	JNIEnv *jenv = __dbj_get_jnienv();
201	jobject jdb = (jobject)DB_INTERNAL(db);
202	jobject jkey, jdata, jskey;
203	jbyteArray jkeyarr, jdataarr, jskeyarr;
204	jboolean jresult;
205	int ret;
206
207	if (jdb == NULL)
208		return (EINVAL);
209
210	jkey = (key->app_data != NULL) ?
211	    ((DBT_LOCKED *)key->app_data)->jdbt :
212	    (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
213	jdata = (data->app_data != NULL) ?
214	    ((DBT_LOCKED *)data->app_data)->jdbt :
215	    (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
216	jskey = (skey->app_data != NULL) ?
217	    ((DBT_LOCKED *)skey->app_data)->jdbt :
218	    (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
219	if (jkey == NULL || jdata == NULL || jskey == NULL)
220		return (ENOMEM); /* An exception is pending */
221
222	if (key->app_data == NULL) {
223		__dbj_dbt_copyout(jenv, key, &jkeyarr, jkey);
224		if (jkeyarr == NULL)
225			return (ENOMEM); /* An exception is pending */
226	}
227	if (data->app_data == NULL) {
228		__dbj_dbt_copyout(jenv, data, &jdataarr, jdata);
229		if (jdataarr == NULL)
230			return (ENOMEM); /* An exception is pending */
231	}
232	if (skey->app_data == NULL) {
233		__dbj_dbt_copyout(jenv, skey, &jskeyarr, jskey);
234		if (jskeyarr == NULL)
235			return (ENOMEM); /* An exception is pending */
236	}
237
238	jresult = (*jenv)->CallNonvirtualBooleanMethod(jenv, jdb, db_class, foreignkey_nullify_method, jkey, jdata, jskey);
239
240	if ((*jenv)->ExceptionOccurred(jenv)) {
241		/* The exception will be thrown, so this could be any error. */
242		ret = EINVAL;
243		goto err;
244	}
245
246	if (jresult == JNI_FALSE)
247		*changed = ret = 0;
248	else{
249		*changed = 1;
250		/* copy jdata into data */
251		if ((ret = __dbj_dbt_copyin(jenv, &lresult, NULL, jdata, 0)) != 0)
252			goto err;
253		if (lresult.dbt.size != 0){
254			data->size = lresult.dbt.size;
255			if ((ret = __os_umalloc(
256			    NULL, data->size, &data->data)) != 0)
257				goto err;
258			if ((ret = __dbj_dbt_memcopy(&lresult.dbt, 0,
259			    data->data, data->size, DB_USERCOPY_GETDATA)) != 0)
260				goto err;
261			__dbj_dbt_release(jenv, jdata,  &lresult.dbt, &lresult);
262			(*jenv)->DeleteLocalRef(jenv, lresult.jarr);
263			F_SET(data, DB_DBT_APPMALLOC);
264		}
265	}
266
267err:	if (key->app_data == NULL) {
268		(*jenv)->DeleteLocalRef(jenv, jkeyarr);
269		(*jenv)->DeleteLocalRef(jenv, jkey);
270	}
271	if (data->app_data == NULL) {
272		(*jenv)->DeleteLocalRef(jenv, jdataarr);
273		(*jenv)->DeleteLocalRef(jenv, jdata);
274	}
275
276	return ret;
277}
278
279static int __dbj_seckey_create(DB *db,
280    const DBT *key, const DBT *data, DBT *result)
281{
282	JNIEnv *jenv = __dbj_get_jnienv();
283	jobject jdb = (jobject)DB_INTERNAL(db);
284	jobject jkey, jdata, jresult;
285	jobjectArray jskeys;
286	jsize i, num_skeys;
287	jbyteArray jkeyarr, jdataarr;
288	DBT_LOCKED lresult;
289	DBT *tresult;
290	int ret;
291
292	if (jdb == NULL)
293		return (EINVAL);
294
295	jkey = (key->app_data != NULL) ?
296	    ((DBT_LOCKED *)key->app_data)->jdbt :
297	    (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
298	jdata = (data->app_data != NULL) ?
299	    ((DBT_LOCKED *)data->app_data)->jdbt :
300	    (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
301	if (jkey == NULL || jdata == NULL)
302		return (ENOMEM); /* An exception is pending */
303
304	if (key->app_data == NULL) {
305		__dbj_dbt_copyout(jenv, key, &jkeyarr, jkey);
306		if (jkeyarr == NULL)
307			return (ENOMEM); /* An exception is pending */
308	}
309	if (data->app_data == NULL) {
310		__dbj_dbt_copyout(jenv, data, &jdataarr, jdata);
311		if (jdataarr == NULL)
312			return (ENOMEM); /* An exception is pending */
313	}
314
315	jskeys = (jobjectArray)(*jenv)->CallNonvirtualObjectMethod(jenv,
316	    jdb, db_class, seckey_create_method, jkey, jdata);
317
318	if (jskeys == NULL ||
319	    (num_skeys = (*jenv)->GetArrayLength(jenv, jskeys)) == 0) {
320		ret = DB_DONOTINDEX;
321		goto err;
322	} else if (num_skeys == 1) {
323		memset(result, 0, sizeof (DBT));
324		tresult = result;
325	} else {
326		if ((ret = __os_umalloc(db->env,
327		    num_skeys * sizeof (DBT), &result->data)) != 0)
328			goto err;
329		memset(result->data, 0, num_skeys * sizeof (DBT));
330		result->size = num_skeys;
331		F_SET(result, DB_DBT_APPMALLOC | DB_DBT_MULTIPLE);
332		tresult = (DBT *)result->data;
333	}
334
335	if ((*jenv)->ExceptionOccurred(jenv)) {
336		/* The exception will be thrown, so this could be any error. */
337		ret = EINVAL;
338		goto err;
339	}
340
341	for (i = 0; i < num_skeys; i++, tresult++) {
342		jresult = (*jenv)->GetObjectArrayElement(jenv, jskeys, i);
343
344		if ((ret =
345		    __dbj_dbt_copyin(jenv, &lresult, NULL, jresult, 0)) != 0)
346			goto err;
347
348		if (lresult.dbt.size != 0) {
349			/* If there's data, we need to take a copy of it.  */
350			tresult->size = lresult.dbt.size;
351			if ((ret = __os_umalloc(NULL,
352			    tresult->size, &tresult->data)) != 0)
353				goto err;
354			if ((ret = __dbj_dbt_memcopy(&lresult.dbt, 0,
355			    tresult->data, tresult->size,
356			    DB_USERCOPY_GETDATA)) != 0)
357				goto err;
358			__dbj_dbt_release(jenv,
359			    jresult, &lresult.dbt, &lresult);
360			(*jenv)->DeleteLocalRef(jenv, lresult.jarr);
361			F_SET(tresult, DB_DBT_APPMALLOC);
362		}
363
364		(*jenv)->DeleteLocalRef(jenv, jresult);
365	}
366
367err:	if (key->app_data == NULL) {
368		(*jenv)->DeleteLocalRef(jenv, jkeyarr);
369		(*jenv)->DeleteLocalRef(jenv, jkey);
370	}
371	if (data->app_data == NULL) {
372		(*jenv)->DeleteLocalRef(jenv, jdataarr);
373		(*jenv)->DeleteLocalRef(jenv, jdata);
374	}
375
376	return (ret);
377}
378
379static int __dbj_append_recno(DB *db, DBT *dbt, db_recno_t recno)
380{
381	JNIEnv *jenv = __dbj_get_jnienv();
382	jobject jdb = (jobject)DB_INTERNAL(db);
383	jobject jdbt;
384	DBT_LOCKED lresult;
385	jbyteArray jdbtarr;
386	int ret;
387
388	if (jdb == NULL)
389		return (EINVAL);
390
391	/*
392	 * The dbt we're passed will be from the application, but we can't
393	 * just reuse it, since we will have already taken a copy of the data.
394	 * Make a new DatabaseEntry object here for the callback.
395	 */
396	jdbt = (*jenv)->NewObject(jenv, dbt_class, dbt_construct);
397	if (jdbt == NULL)
398		return (ENOMEM); /* An exception is pending */
399
400	__dbj_dbt_copyout(jenv, dbt, &jdbtarr, jdbt);
401	if (jdbtarr == NULL)
402		return (ENOMEM); /* An exception is pending */
403
404	ret = 0;
405	(*jenv)->CallNonvirtualVoidMethod(jenv, jdb, db_class,
406	    append_recno_method, jdbt, recno);
407
408	if ((*jenv)->ExceptionOccurred(jenv)) {
409		/* The exception will be thrown, so this could be any error. */
410		return (EINVAL);
411	}
412
413	ret = __dbj_dbt_copyin(jenv, &lresult, NULL, jdbt, 0);
414	memset(dbt, 0, sizeof (DBT));
415
416	if (ret == 0 && lresult.dbt.size != 0) {
417		/* If there's data, we need to take a copy of it.  */
418		dbt->size = lresult.dbt.size;
419		if ((ret =
420		    __os_umalloc(NULL, dbt->size, &dbt->data)) != 0)
421			goto err;
422		if ((ret = __dbj_dbt_memcopy(&lresult.dbt, 0,
423		    dbt->data, dbt->size,
424		    DB_USERCOPY_GETDATA)) != 0)
425			goto err;
426		__dbj_dbt_release(jenv, jdbt, &lresult.dbt, &lresult);
427		(*jenv)->DeleteLocalRef(jenv, lresult.jarr);
428		F_SET(dbt, DB_DBT_APPMALLOC);
429	}
430
431err:	(*jenv)->DeleteLocalRef(jenv, jdbtarr);
432	(*jenv)->DeleteLocalRef(jenv, jdbt);
433
434	return (ret);
435}
436
437/*
438 * Shared by __dbj_bt_compare and __dbj_h_compare
439 */
440static int __dbj_am_compare(DB *db, const DBT *dbt1, const DBT *dbt2,
441    jmethodID compare_method)
442{
443	JNIEnv *jenv = __dbj_get_jnienv();
444	jobject jdb = (jobject)DB_INTERNAL(db);
445	jbyteArray jdbtarr1, jdbtarr2;
446	int ret;
447
448	if (jdb == NULL)
449		return (EINVAL);
450
451	if (dbt1->app_data != NULL)
452		jdbtarr1 = ((DBT_LOCKED *)dbt1->app_data)->jarr;
453	else {
454		jdbtarr1 = (*jenv)->NewByteArray(jenv, (jsize)dbt1->size);
455		if (jdbtarr1 == NULL)
456			return (ENOMEM);
457		(*jenv)->SetByteArrayRegion(jenv, jdbtarr1, 0,
458		    (jsize)dbt1->size, (jbyte *)dbt1->data);
459	}
460
461	if (dbt2->app_data != NULL)
462		jdbtarr2 = ((DBT_LOCKED *)dbt2->app_data)->jarr;
463	else {
464		jdbtarr2 = (*jenv)->NewByteArray(jenv, (jsize)dbt2->size);
465		if (jdbtarr2 == NULL)
466			return (ENOMEM);
467		(*jenv)->SetByteArrayRegion(jenv, jdbtarr2, 0,
468		    (jsize)dbt2->size, (jbyte *)dbt2->data);
469	}
470
471	ret = (int)(*jenv)->CallNonvirtualIntMethod(jenv, jdb, db_class,
472	    compare_method, jdbtarr1, jdbtarr2);
473
474	if ((*jenv)->ExceptionOccurred(jenv)) {
475		/* The exception will be thrown, so this could be any error. */
476		ret = EINVAL;
477	}
478
479	if (dbt1->app_data == NULL)
480		(*jenv)->DeleteLocalRef(jenv, jdbtarr1);
481	if (dbt2->app_data == NULL)
482		(*jenv)->DeleteLocalRef(jenv, jdbtarr2);
483
484	return (ret);
485}
486
487static int __dbj_bt_compare(DB *db, const DBT *dbt1, const DBT *dbt2)
488{
489	return __dbj_am_compare(db, dbt1, dbt2, bt_compare_method);
490}
491
492static size_t __dbj_bt_prefix(DB *db, const DBT *dbt1, const DBT *dbt2)
493{
494	JNIEnv *jenv = __dbj_get_jnienv();
495	jobject jdb = (jobject)DB_INTERNAL(db);
496	jobject jdbt1, jdbt2;
497	jbyteArray jdbtarr1, jdbtarr2;
498	int ret;
499
500	if (jdb == NULL)
501		return (EINVAL);
502
503	if (dbt1->app_data != NULL)
504		jdbt1 = ((DBT_LOCKED *)dbt1->app_data)->jdbt;
505	else {
506		if ((jdbt1 =
507		    (*jenv)->NewObject(jenv, dbt_class, dbt_construct)) == NULL)
508			return (ENOMEM); /* An exception is pending */
509		__dbj_dbt_copyout(jenv, dbt1, &jdbtarr1, jdbt1);
510		if (jdbtarr1 == NULL)
511			return (ENOMEM); /* An exception is pending */
512	}
513
514	if (dbt2->app_data != NULL)
515		jdbt2 = ((DBT_LOCKED *)dbt2->app_data)->jdbt;
516	else {
517		if ((jdbt2 =
518		    (*jenv)->NewObject(jenv, dbt_class, dbt_construct)) == NULL)
519			return (ENOMEM); /* An exception is pending */
520		__dbj_dbt_copyout(jenv, dbt2, &jdbtarr2, jdbt2);
521		if (jdbtarr2 == NULL)
522			return (ENOMEM); /* An exception is pending */
523	}
524
525	ret = (int)(*jenv)->CallNonvirtualIntMethod(jenv, jdb, db_class,
526	    bt_prefix_method, jdbt1, jdbt2);
527
528	if (dbt1->app_data == NULL) {
529		(*jenv)->DeleteLocalRef(jenv, jdbtarr1);
530		(*jenv)->DeleteLocalRef(jenv, jdbt1);
531	}
532	if (dbt2->app_data == NULL) {
533		(*jenv)->DeleteLocalRef(jenv, jdbtarr2);
534		(*jenv)->DeleteLocalRef(jenv, jdbt2);
535	}
536
537	return (ret);
538}
539
540static int __dbj_dup_compare(DB *db, const DBT *dbt1, const DBT *dbt2)
541{
542	JNIEnv *jenv = __dbj_get_jnienv();
543	jobject jdb = (jobject)DB_INTERNAL(db);
544	jbyteArray jdbtarr1, jdbtarr2;
545	int ret;
546
547	if (jdb == NULL)
548		return (EINVAL);
549
550	jdbtarr1 = (*jenv)->NewByteArray(jenv, (jsize)dbt1->size);
551	if (jdbtarr1 == NULL)
552		return (ENOMEM);
553	(*jenv)->SetByteArrayRegion(jenv, jdbtarr1, 0, (jsize)dbt1->size,
554	    (jbyte *)dbt1->data);
555
556	jdbtarr2 = (*jenv)->NewByteArray(jenv, (jsize)dbt2->size);
557	if (jdbtarr2 == NULL)
558		return (ENOMEM);
559	(*jenv)->SetByteArrayRegion(jenv, jdbtarr2, 0, (jsize)dbt2->size,
560	    (jbyte *)dbt2->data);
561
562	ret = (int)(*jenv)->CallNonvirtualIntMethod(jenv, jdb, db_class,
563	    dup_compare_method, jdbtarr1, jdbtarr2);
564
565	if ((*jenv)->ExceptionOccurred(jenv)) {
566		/* The exception will be thrown, so this could be any error. */
567		ret = EINVAL;
568	}
569
570	(*jenv)->DeleteLocalRef(jenv, jdbtarr2);
571	(*jenv)->DeleteLocalRef(jenv, jdbtarr1);
572
573	return (ret);
574}
575
576static void __dbj_db_feedback(DB *db, int opcode, int percent)
577{
578	JNIEnv *jenv = __dbj_get_jnienv();
579	jobject jdb = (jobject)DB_INTERNAL(db);
580
581	if (jdb != NULL)
582		(*jenv)->CallNonvirtualVoidMethod(jenv, jdb, db_class,
583		    db_feedback_method, opcode, percent);
584}
585
586static int __dbj_h_compare(DB *db, const DBT *dbt1, const DBT *dbt2)
587{
588	return __dbj_am_compare(db, dbt1, dbt2, h_compare_method);
589}
590
591static u_int32_t __dbj_h_hash(DB *db, const void *data, u_int32_t len)
592{
593	JNIEnv *jenv = __dbj_get_jnienv();
594	jobject jdb = (jobject)DB_INTERNAL(db);
595	jbyteArray jarr = (*jenv)->NewByteArray(jenv, (jsize)len);
596	int ret;
597
598	if (jdb == NULL)
599		return (EINVAL);
600
601	if ((jarr = (*jenv)->NewByteArray(jenv, (jsize)len)) == NULL)
602		return (ENOMEM); /* An exception is pending */
603
604	(*jenv)->SetByteArrayRegion(jenv, jarr, 0, (jsize)len, (jbyte *)data);
605
606	ret = (int)(*jenv)->CallNonvirtualIntMethod(jenv, jdb, db_class,
607	    h_hash_method, jarr, len);
608
609	(*jenv)->DeleteLocalRef(jenv, jarr);
610
611	return (ret);
612}
613%}
614
615JAVA_CALLBACK(void (*db_errcall_fcn)(const DB_ENV *,
616    const char *, const char *), com.sleepycat.db.ErrorHandler, error)
617JAVA_CALLBACK(void (*env_feedback_fcn)(DB_ENV *, int, int),
618    com.sleepycat.db.FeedbackHandler, env_feedback)
619JAVA_CALLBACK(void (*db_msgcall_fcn)(const DB_ENV *, const char *),
620    com.sleepycat.db.MessageHandler, message)
621JAVA_CALLBACK(void (*db_panic_fcn)(DB_ENV *, int),
622    com.sleepycat.db.PanicHandler, panic)
623JAVA_CALLBACK(void (*event_notify)(DB_ENV *, u_int32_t, void *),
624    com.sleepycat.db.EventHandler, event_notify)
625JAVA_CALLBACK(int (*tx_recover)(DB_ENV *, DBT *, DB_LSN *, db_recops),
626    com.sleepycat.db.LogRecordHandler, app_dispatch)
627JAVA_CALLBACK(int (*send)(DB_ENV *, const DBT *, const DBT *,
628			       const DB_LSN *, int, u_int32_t),
629    com.sleepycat.db.ReplicationTransport, rep_transport)
630
631/*
632 * Db.associate is a special case, because the handler must be set in the
633 * secondary DB - that's what we have in the callback.  In addition, there
634 * are two flavors of callback (single key and multi-key), so we need to
635 * check for both types when working out whether the C callback should
636 * be NULL.  Note that this implies that the multi-key callback will be set
637 * on the secondary database *before* associate is called.
638 */
639JAVA_CALLBACK(int (*callback)(DB *, const DBT *, const DBT *, DBT *),
640    com.sleepycat.db.SecondaryKeyCreator, seckey_create)
641%typemap(javain) int (*callback)(DB *, const DBT *, const DBT *, DBT *)
642    %{ (secondary.seckey_create_handler = $javainput) != null ||
643	(secondary.secmultikey_create_handler != null) %}
644JAVA_CALLBACK(int (*callback)(DB *, const DBT *, DBT *, const DBT *, int *),
645    com.sleepycat.db.ForeignKeyNullifier, foreignkey_nullify)
646%typemap(javain) int (*callback)(DB *, const DBT *, DBT *, const DBT *, int *)
647    %{ (primary.foreignkey_nullify_handler = $javainput) != null ||
648	(primary.foreignmultikey_nullify_handler != null) %}
649
650JAVA_CALLBACK(int (*db_append_recno_fcn)(DB *, DBT *, db_recno_t),
651    com.sleepycat.db.RecordNumberAppender, append_recno)
652JAVA_CALLBACK(int (*bt_compare_fcn)(DB *, const DBT *, const DBT *),
653    java.util.Comparator, bt_compare)
654JAVA_CALLBACK(size_t (*bt_prefix_fcn)(DB *, const DBT *, const DBT *),
655    com.sleepycat.db.BtreePrefixCalculator, bt_prefix)
656JAVA_CALLBACK(int (*dup_compare_fcn)(DB *, const DBT *, const DBT *),
657    java.util.Comparator, dup_compare)
658JAVA_CALLBACK(void (*db_feedback_fcn)(DB *, int, int),
659    com.sleepycat.db.FeedbackHandler, db_feedback)
660JAVA_CALLBACK(int (*h_compare_fcn)(DB *, const DBT *, const DBT *),
661    java.util.Comparator, h_compare)
662JAVA_CALLBACK(u_int32_t (*h_hash_fcn)(DB *, const void *, u_int32_t),
663    com.sleepycat.db.Hasher, h_hash)
664