1 /* Typemaps */
2 %define JAVA_TYPEMAP(_ctype, _jtype, _jnitype)
3 %typemap(jstype) _ctype #_jtype
4 %typemap(jtype) _ctype #_jtype
5 %typemap(jni) _ctype #_jnitype
6 %typemap(out) _ctype %{ $result = (_jnitype)$1; %}
7 %typemap(javain) _ctype "$javainput"
8 %typemap(javaout) _ctype { return $jnicall; }
9 %enddef
10 
11 JAVA_TYPEMAP(int32_t, int, jint)
12 JAVA_TYPEMAP(u_int32_t, int, jint)
13 JAVA_TYPEMAP(u_int32_t pagesize, long, jlong)
14 JAVA_TYPEMAP(long, long, jlong)
15 JAVA_TYPEMAP(db_seq_t, long, jlong)
16 JAVA_TYPEMAP(db_size_t, long, jlong)
17 JAVA_TYPEMAP(db_ssize_t, long, jlong)
18 JAVA_TYPEMAP(pid_t, long, jlong)
19 JAVA_TYPEMAP(roff_t, long, jlong)
20 #ifndef SWIGJAVA
21 JAVA_TYPEMAP(db_threadid_t, long, jlong)
22 #endif
23 JAVA_TYPEMAP(db_timeout_t, long, jlong)
24 JAVA_TYPEMAP(size_t, long, jlong)
25 JAVA_TYPEMAP(db_ret_t, void, void)
26 %typemap(javaout) db_ret_t { $jnicall; }
27 %typemap(out) db_ret_t ""
28 
29 JAVA_TYPEMAP(int_bool, boolean, jboolean)
30 %typemap(in) int_bool %{ $1 = ($input == JNI_TRUE); %}
31 %typemap(out) int_bool %{ $result = ($1) ? JNI_TRUE : JNI_FALSE; %}
32 
33 /* Fake typedefs for SWIG */
34 typedef        int db_ret_t;    /* An int that is mapped to a void */
35 typedef        int int_bool;    /* An int that is mapped to a boolean */
36 
37 %{
38 typedef int db_ret_t;
39 typedef int int_bool;
40 
41 struct __db_lk_conflicts {
42        u_int8_t *lk_conflicts;
43        int lk_modes;
44 };
45 
46 struct __db_out_stream {
47        void *handle;
48        int (*callback) __P((void *, const void *));
49 };
50 
51 struct __db_repmgr_site_address {
52 	const char *host;
53 	u_int port;
54 };
55 
56 struct __db_repmgr_sites {
57        DB_REPMGR_SITE *sites;
58        u_int32_t nsites;
59 };
60 
61 #define        Db __db
62 #define        Dbc __dbc
63 #define        Dbt __db_dbt
64 #define        DbChannel __db_channel
65 #define        DbEnv __db_env
66 #define        DbLock __db_lock_u
67 #define        DbLogc __db_log_cursor
68 #define        DbLsn __db_lsn
69 #define        DbMpoolFile __db_mpoolfile
70 #define        DbSequence __db_sequence
71 #define        DbSite __db_site
72 #define        DbTxn __db_txn
73 
74 /* Suppress a compilation warning for an unused symbol */
75 void *unused = (void *)SWIG_JavaThrowException;
76 %}
77 
78 /* Dbt handling */
79 JAVA_TYPEMAP(DBT *, com.sleepycat.db.DatabaseEntry, jobject)
80 
81 %{
82 typedef struct __dbt_locked {
83 	JNIEnv *jenv;
84 	jobject jdbt;
85 	DBT dbt;
86 	jobject jdata_nio;
87 	jbyteArray jarr;
88 	jint offset;
89 	int reuse;
90 	u_int32_t orig_size;
91 	jsize array_len;
92 } DBT_LOCKED;
93 
__dbj_dbt_memcopy(DBT * dbt,u_int32_t offset,void * buf,u_int32_t size,u_int32_t flags)94 static int __dbj_dbt_memcopy(DBT *dbt, u_int32_t offset, void *buf, u_int32_t size, u_int32_t flags) {
95 	DBT_LOCKED *ldbt = dbt->app_data;
96 	JNIEnv *jenv = ldbt->jenv;
97 
98 	if (size == 0)
99 		return (0);
100 	else if (!F_ISSET(dbt, DB_DBT_USERCOPY)) {
101 		/*
102 		  * For simplicity, the Java API calls this function directly,
103 		  * so it needs to work with regular DBTs.
104 		  */
105 		switch (flags) {
106 		case DB_USERCOPY_GETDATA:
107 			memcpy(buf, (u_int8_t *)dbt->data + offset, size);
108 			return (0);
109 		case DB_USERCOPY_SETDATA:
110 			memcpy((u_int8_t *)dbt->data + offset, buf, size);
111 			return (0);
112 		default:
113 			return (EINVAL);
114 		}
115 	}
116 
117 	switch (flags) {
118 	case DB_USERCOPY_GETDATA:
119 		(*jenv)->GetByteArrayRegion(jenv, ldbt->jarr, ldbt->offset +
120 					    offset, size, buf);
121 		break;
122 	case DB_USERCOPY_SETDATA:
123 		/*
124 		 * Check whether this is the first time through the callback by relying
125 		 * on the offset being zero.
126 		 */
127 		if (offset == 0 && (!ldbt->reuse ||
128 		    (jsize)(ldbt->offset + dbt->size) > ldbt->array_len)) {
129 			if (ldbt->jarr != NULL)
130 				(*jenv)->DeleteLocalRef(jenv, ldbt->jarr);
131 			ldbt->jarr = (*jenv)->NewByteArray(jenv, (jsize)dbt->size);
132 			if (ldbt->jarr == NULL)
133 				return (ENOMEM);
134 			(*jenv)->SetObjectField(jenv, ldbt->jdbt, dbt_data_fid, ldbt->jarr);
135 			/* We've allocated a new array, start from the beginning. */
136 			ldbt->offset = 0;
137 		}
138 		(*jenv)->SetByteArrayRegion(jenv, ldbt->jarr, ldbt->offset +
139 					    offset, size, buf);
140 		break;
141 	default:
142 		return (EINVAL);
143 	}
144 	return ((*jenv)->ExceptionOccurred(jenv) ? EINVAL : 0);
145 }
146 
__dbj_dbt_copyout(JNIEnv * jenv,const DBT * dbt,jbyteArray * jarr,jobject jdbt)147 static void __dbj_dbt_copyout(
148     JNIEnv *jenv, const DBT *dbt, jbyteArray *jarr, jobject jdbt)
149 {
150 	jbyteArray newarr = (*jenv)->NewByteArray(jenv, (jsize)dbt->size);
151 	if (newarr == NULL)
152 		return; /* An exception is pending */
153 	(*jenv)->SetByteArrayRegion(jenv, newarr, 0, (jsize)dbt->size,
154 	    (jbyte *)dbt->data);
155 	(*jenv)->SetObjectField(jenv, jdbt, dbt_data_fid, newarr);
156 	(*jenv)->SetIntField(jenv, jdbt, dbt_offset_fid, 0);
157 	(*jenv)->SetIntField(jenv, jdbt, dbt_size_fid, (jint)dbt->size);
158 	if (jarr != NULL)
159 		*jarr = newarr;
160 	else
161 		(*jenv)->DeleteLocalRef(jenv, newarr);
162 }
163 
__dbj_dbt_copyin(JNIEnv * jenv,DBT_LOCKED * ldbt,DBT ** dbtp,jobject jdbt,int allow_null)164 static int __dbj_dbt_copyin(
165     JNIEnv *jenv, DBT_LOCKED *ldbt, DBT **dbtp, jobject jdbt, int allow_null)
166 {
167 	DBT *dbt;
168 	jlong capacity;
169 
170 	memset(ldbt, 0, sizeof (*ldbt));
171 	ldbt->jenv = jenv;
172 	ldbt->jdbt = jdbt;
173 
174 	if (jdbt == NULL) {
175 		if (allow_null) {
176 			*dbtp = NULL;
177 			return (0);
178 		} else {
179 			return (__dbj_throw(jenv, EINVAL,
180 			    "DatabaseEntry must not be null", NULL, NULL));
181 		}
182 	}
183 
184 	dbt = &ldbt->dbt;
185 	if (dbtp != NULL)
186 		*dbtp = dbt;
187 
188 	ldbt->jdata_nio = (*jenv)->GetObjectField(jenv, jdbt, dbt_data_nio_fid);
189 	if (ldbt->jdata_nio != NULL)
190 		F_SET(dbt, DB_DBT_USERMEM);
191 	else
192 		ldbt->jarr = (jbyteArray)(*jenv)->GetObjectField(jenv, jdbt, dbt_data_fid);
193 	ldbt->offset = (*jenv)->GetIntField(jenv, jdbt, dbt_offset_fid);
194 	dbt->size = (*jenv)->GetIntField(jenv, jdbt, dbt_size_fid);
195 	ldbt->orig_size = dbt->size;
196 	dbt->flags = (*jenv)->GetIntField(jenv, jdbt, dbt_flags_fid);
197 
198 	if (F_ISSET(dbt, DB_DBT_USERMEM))
199 		dbt->ulen = (*jenv)->GetIntField(jenv, jdbt, dbt_ulen_fid);
200 	if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
201 		dbt->dlen = (*jenv)->GetIntField(jenv, jdbt, dbt_dlen_fid);
202 		dbt->doff = (*jenv)->GetIntField(jenv, jdbt, dbt_doff_fid);
203 
204 		if ((jint)dbt->doff < 0)
205 			return (__dbj_throw(jenv, EINVAL, "DatabaseEntry doff illegal",
206 			    NULL, NULL));
207 	}
208 
209 	/*
210 	 * We don't support DB_DBT_REALLOC - map anything that's not USERMEM to
211 	 * MALLOC.
212 	 */
213 	if (!F_ISSET(dbt, DB_DBT_USERMEM)) {
214 		ldbt->reuse = !F_ISSET(dbt, DB_DBT_MALLOC);
215 		F_CLR(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC);
216 	}
217 
218 	/* Verify parameters before allocating or locking data. */
219 	if (ldbt->jdata_nio != NULL) {
220 		capacity = (*jenv)->GetDirectBufferCapacity(jenv,
221 				ldbt->jdata_nio);
222 		if (capacity > (jlong)UINT32_MAX)
223 			return (__dbj_throw(jenv, EINVAL,
224 			    "DirectBuffer may not be larger than 4GB",
225 			    NULL, NULL));
226 		ldbt->array_len = (u_int32_t)capacity;
227 	} else if (ldbt->jarr == NULL) {
228 		/*
229 		 * Some code makes the assumption that if a DBT's size or ulen
230 		 * is non-zero, there is data to copy from dbt->data.
231 		 *
232 		 * Clean up the dbt fields so we don't run into trouble.
233 		 * (Note that doff, dlen, and flags all may contain
234 		 * meaningful values.)
235 		 */
236 		dbt->data = NULL;
237 		ldbt->array_len = ldbt->offset = dbt->size = dbt->ulen = 0;
238 	} else
239 		ldbt->array_len = (*jenv)->GetArrayLength(jenv, ldbt->jarr);
240 
241 	if (F_ISSET(dbt, DB_DBT_USERMEM)) {
242 		if (ldbt->offset < 0)
243 			return (__dbj_throw(jenv, EINVAL,
244 			    "offset cannot be negative",
245 			    NULL, NULL));
246 		if (dbt->size > dbt->ulen)
247 			return (__dbj_throw(jenv, EINVAL,
248 			    "size must be less than or equal to ulen",
249 			    NULL, NULL));
250 		if ((jsize)(ldbt->offset + dbt->ulen) > ldbt->array_len)
251 			return (__dbj_throw(jenv, EINVAL,
252 			    "offset + ulen greater than array length",
253 			    NULL, NULL));
254 	}
255 
256 	if (ldbt->jdata_nio) {
257 		dbt->data = (*jenv)->GetDirectBufferAddress(jenv,
258 				ldbt->jdata_nio);
259 		dbt->data = (u_int8_t *)dbt->data + ldbt->offset;
260 	} else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
261 		if (ldbt->jarr != NULL &&
262 		    (dbt->data = (*jenv)->GetByteArrayElements(jenv,
263 		    ldbt->jarr, NULL)) == NULL)
264 			return (EINVAL); /* an exception will be pending */
265 		dbt->data = (u_int8_t *)dbt->data + ldbt->offset;
266 	} else
267 		F_SET(dbt, DB_DBT_USERCOPY);
268 	dbt->app_data = ldbt;
269 
270 	return (0);
271 }
272 
__dbj_dbt_release(JNIEnv * jenv,jobject jdbt,DBT * dbt,DBT_LOCKED * ldbt)273 static void __dbj_dbt_release(
274     JNIEnv *jenv, jobject jdbt, DBT *dbt, DBT_LOCKED *ldbt) {
275 	jthrowable t;
276 
277 	if (dbt == NULL)
278 		return;
279 
280 	if (dbt->size != ldbt->orig_size)
281 		(*jenv)->SetIntField(jenv, jdbt, dbt_size_fid, (jint)dbt->size);
282 
283 	if (F_ISSET(dbt, DB_DBT_USERMEM)) {
284 		if (ldbt->jarr != NULL)
285 			(*jenv)->ReleaseByteArrayElements(jenv, ldbt->jarr,
286 			    (jbyte *)dbt->data - ldbt->offset, 0);
287 
288 		if (dbt->size > dbt->ulen &&
289 		    (t = (*jenv)->ExceptionOccurred(jenv)) != NULL &&
290 		    (*jenv)->IsInstanceOf(jenv, t, memex_class)) {
291 			(*jenv)->CallNonvirtualVoidMethod(jenv, t, memex_class,
292 			    memex_update_method, jdbt);
293 			/*
294 			 * We have to rethrow the exception because calling
295 			 * into Java clears it.
296 			 */
297 			(*jenv)->Throw(jenv, t);
298 		}
299 	}
300 }
301 %}
302 
303 %typemap(in) DBT * (DBT_LOCKED ldbt) %{
304 	if (__dbj_dbt_copyin(jenv, &ldbt, &$1, $input, 0) != 0) {
305 		return $null; /* An exception will be pending. */
306 	}%}
307 
308 /* Special cases for DBTs that may be null: DbEnv.rep_start, Db.compact Db.set_partition */
309 %typemap(in) DBT *data_or_null (DBT_LOCKED ldbt) %{
310 	if (__dbj_dbt_copyin(jenv, &ldbt, &$1, $input, 1) != 0) {
311 		return $null; /* An exception will be pending. */
312 	}%}
313 
314 %apply DBT *data_or_null {DBT *cdata, DBT *start, DBT *stop, DBT *end, DBT *db_put_data, DBT *keys};
315 
316 %typemap(freearg) DBT * %{ __dbj_dbt_release(jenv, $input, $1, &ldbt$argnum); %}
317 
318 /* DB_TXN_TOKEN handling */
319 JAVA_TYPEMAP(DB_TXN_TOKEN *, byte[], jobject)
320 
321 %typemap(check) DB_TXN_TOKEN * %{
322        if ($1 == NULL) {
323                __dbj_throw(jenv, EINVAL, "null txn commit token", NULL, NULL);
324                return $null;
325        }
326 %}
327 
328 
329 %typemap(in) DB_TXN_TOKEN * (DB_TXN_TOKEN token) %{
330        if ($input == NULL) {
331                $1 = NULL;
332        } else {
333                $1 = &token;
334                (*jenv)->GetByteArrayRegion(jenv, (jbyteArray)$input, 0, DB_TXN_TOKEN_SIZE, $1->buf);
335        }
336 %}
337 
338 %typemap(out) DB_TXN_TOKEN * %{
339        if ($input != NULL) {
340                (*jenv)->SetByteArrayRegion(jenv, (jbyteArray)$input, 0, DB_TXN_TOKEN_SIZE, $1->buf);
341        }
342 %}
343 
344 /* DbLsn handling */
345 JAVA_TYPEMAP(DB_LSN *, com.sleepycat.db.LogSequenceNumber, jobject)
346 
347 %typemap(check) DB_LSN *lsn_or_null ""
348 
349 %typemap(check) DB_LSN * %{
350 	if ($1 == NULL) {
351 		__dbj_throw(jenv, EINVAL, "null LogSequenceNumber", NULL, NULL);
352 		return $null;
353 	}
354 %}
355 
356 %typemap(in) DB_LSN * (DB_LSN lsn) %{
357 	if ($input == NULL) {
358 		$1 = NULL;
359 	} else {
360 		$1 = &lsn;
361 		$1->file = (*jenv)->GetIntField(jenv, $input, dblsn_file_fid);
362 		$1->offset = (*jenv)->GetIntField(jenv, $input,
363 		    dblsn_offset_fid);
364 	}
365 %}
366 
367 %typemap(freearg) DB_LSN * %{
368 	if ($input != NULL) {
369 		(*jenv)->SetIntField(jenv, $input, dblsn_file_fid, $1->file);
370 		(*jenv)->SetIntField(jenv, $input,
371 		    dblsn_offset_fid, $1->offset);
372 	}
373 %}
374 
375 /* Various typemaps */
376 JAVA_TYPEMAP(time_t, long, jlong)
377 JAVA_TYPEMAP(time_t *, long, jlong)
378 %typemap(in) time_t * (time_t time) %{
379 	time = (time_t)$input;
380 	$1 = &time;
381 %}
382 
383 %typemap(in) time_t %{
384         $1 = $input;
385 %}
386 
387 JAVA_TYPEMAP(u_int, long, jlong)
388 JAVA_TYPEMAP(u_int *, long, jlong)
389 %typemap(in) u_int * (u_int value) %{
390         value = (u_int)$input;
391         $1 = &value;
392 %}
393 
394 %typemap(in) u_int %{
395         $1 = $input;
396 %}
397 
398 JAVA_TYPEMAP(DB_KEY_RANGE *, com.sleepycat.db.KeyRange, jobject)
399 %typemap(in) DB_KEY_RANGE * (DB_KEY_RANGE range) {
400 	$1 = &range;
401 }
402 %typemap(argout) DB_KEY_RANGE * {
403 	(*jenv)->SetDoubleField(jenv, $input, kr_less_fid, $1->less);
404 	(*jenv)->SetDoubleField(jenv, $input, kr_equal_fid, $1->equal);
405 	(*jenv)->SetDoubleField(jenv, $input, kr_greater_fid, $1->greater);
406 }
407 
408 JAVA_TYPEMAP(DBC **, Dbc[], jobjectArray)
409 %typemap(in) DBC ** {
410 	int i, count, ret;
411 
412 	count = (*jenv)->GetArrayLength(jenv, $input);
413 	if ((ret = __os_malloc(NULL, (count + 1) * sizeof(DBC *), &$1)) != 0) {
414 		__dbj_throw(jenv, ret, NULL, NULL, DB2JDBENV);
415 		return $null;
416 	}
417 	for (i = 0; i < count; i++) {
418 		jobject jobj = (*jenv)->GetObjectArrayElement(jenv, $input, i);
419 		/*
420 		 * A null in the array is treated as an endpoint.
421 		 */
422 		if (jobj == NULL) {
423 			$1[i] = NULL;
424 			break;
425 		} else {
426 			jlong jptr = (*jenv)->GetLongField(jenv, jobj,
427 			    dbc_cptr_fid);
428 			$1[i] = *(DBC **)(void *)&jptr;
429 		}
430 	}
431 	$1[count] = NULL;
432 }
433 
434 %typemap(freearg) DBC ** %{
435 	__os_free(NULL, $1);
436 %}
437 
438 JAVA_TYPEMAP(u_int8_t *gid, byte[], jbyteArray)
439 %typemap(check) u_int8_t *gid %{
440 	if ((*jenv)->GetArrayLength(jenv, $input) < DB_GID_SIZE) {
441 		__dbj_throw(jenv, EINVAL,
442 		    "DbTxn.prepare gid array must be >= 128 bytes", NULL,
443 		    TXN2JDBENV);
444 		return $null;
445 	}
446 %}
447 
448 %typemap(in) u_int8_t *gid %{
449 	$1 = (u_int8_t *)(*jenv)->GetByteArrayElements(jenv, $input, NULL);
450 %}
451 
452 %typemap(freearg) u_int8_t *gid %{
453 	(*jenv)->ReleaseByteArrayElements(jenv, $input, (jbyte *)$1, 0);
454 %}
455 
456 %define STRING_ARRAY_OUT
457 	int i, len;
458 
459 	len = 0;
460 	while ($1[len] != NULL)
461 		len++;
462 	if (($result = (*jenv)->NewObjectArray(jenv, (jsize)len, string_class,
463 	    NULL)) == NULL)
464 		return $null; /* an exception is pending */
465 	for (i = 0; i < len; i++) {
466 		jstring str = (*jenv)->NewStringUTF(jenv, $1[i]);
467 		(*jenv)->SetObjectArrayElement(jenv, $result, (jsize)i, str);
468 	}
469 %enddef
470 
471 JAVA_TYPEMAP(char **, String[], jobjectArray)
472 %typemap(out) const char ** {
473 	if ($1 != NULL) {
474 		STRING_ARRAY_OUT
475 	}
476 }
477 %typemap(out) char ** {
478 	if ($1 != NULL) {
479 		STRING_ARRAY_OUT
480 		__os_ufree(NULL, $1);
481 	}
482 }
483 
484 JAVA_TYPEMAP(char **hostp, String, jobjectArray)
485 
486 JAVA_TYPEMAP(struct __db_lk_conflicts, byte[][], jobjectArray)
487 %typemap(in) struct __db_lk_conflicts {
488 	int i, len, ret;
489 	size_t bytesize;
490 
491 	len = $1.lk_modes = (*jenv)->GetArrayLength(jenv, $input);
492 	bytesize = sizeof(u_char) * len * len;
493 
494 	if ((ret = __os_malloc(NULL, bytesize, &$1.lk_conflicts)) != 0) {
495 		__dbj_throw(jenv, ret, NULL, NULL, JDBENV);
496 		return $null;
497 	}
498 
499 	for (i = 0; i < len; i++) {
500 		jobject sub_array = (*jenv)->GetObjectArrayElement(jenv,
501 		    $input, i);
502 		(*jenv)->GetByteArrayRegion(jenv,(jbyteArray)sub_array, 0, len,
503 		    (jbyte *)&$1.lk_conflicts[i * len]);
504 	}
505 }
506 
507 %typemap(freearg) struct __db_lk_conflicts %{
508 	__os_free(NULL, $1.lk_conflicts);
509 %}
510 
511 %typemap(out) struct __db_lk_conflicts {
512 	int i;
513 	jbyteArray bytes;
514 
515 	$result = (*jenv)->NewObjectArray(jenv,
516 	    (jsize)$1.lk_modes, bytearray_class, NULL);
517 	if ($result == NULL)
518 		return $null; /* an exception is pending */
519 	for (i = 0; i < $1.lk_modes; i++) {
520 		bytes = (*jenv)->NewByteArray(jenv, (jsize)$1.lk_modes);
521 		if (bytes == NULL)
522 			return $null; /* an exception is pending */
523 		(*jenv)->SetByteArrayRegion(jenv, bytes, 0, (jsize)$1.lk_modes,
524 		    (jbyte *)($1.lk_conflicts + i * $1.lk_modes));
525 		(*jenv)->SetObjectArrayElement(jenv, $result, (jsize)i, bytes);
526 	}
527 }
528 
529 %{
530 struct __dbj_verify_data {
531 	JNIEnv *jenv;
532 	jobject streamobj;
533 	jbyteArray bytes;
534 	int nbytes;
535 };
536 
__dbj_verify_callback(void * handle,const void * str_arg)537 static int __dbj_verify_callback(void *handle, const void *str_arg) {
538 	char *str;
539 	struct __dbj_verify_data *vd;
540 	int len;
541 	JNIEnv *jenv;
542 
543 	str = (char *)str_arg;
544 	vd = (struct __dbj_verify_data *)handle;
545 	jenv = vd->jenv;
546 	len = (int)strlen(str) + 1;
547 	if (len > vd->nbytes) {
548 		vd->nbytes = len;
549 		if (vd->bytes != NULL)
550 			(*jenv)->DeleteLocalRef(jenv, vd->bytes);
551 		if ((vd->bytes = (*jenv)->NewByteArray(jenv, (jsize)len))
552 		    == NULL)
553 			return (ENOMEM);
554 	}
555 
556 	if (vd->bytes != NULL) {
557 		(*jenv)->SetByteArrayRegion(jenv, vd->bytes, 0, (jsize)len,
558 		    (jbyte*)str);
559 		(*jenv)->CallVoidMethod(jenv, vd->streamobj,
560 		    outputstream_write_method, vd->bytes, 0, len - 1);
561 	}
562 
563 	if ((*jenv)->ExceptionOccurred(jenv) != NULL)
564 		return (EIO);
565 
566 	return (0);
567 }
568 %}
569 
570 JAVA_TYPEMAP(struct __db_out_stream, java.io.OutputStream, jobject)
571 %typemap(in) struct __db_out_stream (struct __dbj_verify_data data) {
572 	data.jenv = jenv;
573 	data.streamobj = $input;
574 	data.bytes = NULL;
575 	data.nbytes = 0;
576 	$1.handle = &data;
577 	$1.callback = __dbj_verify_callback;
578 }
579 
580 JAVA_TYPEMAP(DB_PREPLIST *, com.sleepycat.db.PreparedTransaction[],
581     jobjectArray)
582 %typemap(out) DB_PREPLIST * {
583 	int i, len;
584 
585 	if ($1 == NULL)
586 		$result = NULL;
587 	else {
588 		len = 0;
589 		while ($1[len].txn != NULL)
590 			len++;
591 		$result = (*jenv)->NewObjectArray(jenv, (jsize)len, dbpreplist_class,
592 		    NULL);
593 		if ($result == NULL)
594 			return $null; /* an exception is pending */
595 		for (i = 0; i < len; i++) {
596 			jobject jtxn = (*jenv)->NewObject(jenv, dbtxn_class,
597 			    dbtxn_construct, $1[i].txn, JNI_FALSE);
598 			jobject bytearr = (*jenv)->NewByteArray(jenv,
599 			    (jsize)sizeof($1[i].gid));
600 			jobject obj = (*jenv)->NewObject(jenv, dbpreplist_class,
601 			    dbpreplist_construct, jtxn, bytearr);
602 
603 			if (jtxn == NULL || bytearr == NULL || obj == NULL)
604 				return $null; /* An exception is pending */
605 
606 			(*jenv)->SetByteArrayRegion(jenv, bytearr, 0,
607 			    (jsize)sizeof($1[i].gid), (jbyte *)$1[i].gid);
608 			(*jenv)->SetObjectArrayElement(jenv, $result, i, obj);
609 		}
610 		__os_ufree(NULL, $1);
611 	}
612 }
613 
614 JAVA_TYPEMAP(DB_LOCKREQ *, com.sleepycat.db.LockRequest[], jobjectArray)
615 
616 %native(DbEnv_lock_vec) void DbEnv_lock_vec(DB_ENV *dbenv, u_int32_t locker,
617     u_int32_t flags, DB_LOCKREQ *list, int offset, int nlist);
618 %{
619 SWIGEXPORT void JNICALL
Java_com_sleepycat_db_internal_db_1javaJNI_DbEnv_1lock_1vec(JNIEnv * jenv,jclass jcls,jlong jdbenvp,jobject jdbenv,jint locker,jint flags,jobjectArray list,jint offset,jint count)620 Java_com_sleepycat_db_internal_db_1javaJNI_DbEnv_1lock_1vec(JNIEnv *jenv,
621     jclass jcls, jlong jdbenvp, jobject jdbenv, jint locker, jint flags,
622     jobjectArray list, jint offset, jint count) {
623 	DB_ENV *dbenv;
624 	DB_LOCKREQ *lockreq;
625 	DB_LOCKREQ *prereq;	/* preprocessed requests */
626 	DB_LOCKREQ *failedreq;
627 	DB_LOCK *lockp;
628 	DBT_LOCKED *locked_dbts;
629 	DBT *obj;
630 	ENV *env;
631 	int alloc_err, i, ret;
632 	size_t bytesize, ldbtsize;
633 	jobject jlockreq;
634 	db_lockop_t op;
635 	jobject jobj, jlock;
636 	jlong jlockp;
637 	int completed;
638 
639 	/*
640 	 * We can't easily #include "dbinc/db_ext.h" because of name
641 	 * clashes, so we declare this explicitly.
642 	 */
643 	extern int __dbt_usercopy __P((ENV *, DBT *));
644 	extern void __dbt_userfree __P((ENV *, DBT *, DBT *, DBT *));
645 
646 	COMPQUIET(jcls, NULL);
647 	dbenv = *(DB_ENV **)(void *)&jdbenvp;
648 	env = dbenv->env;
649 	locked_dbts = NULL;
650 	lockreq = NULL;
651 
652 	if (dbenv == NULL) {
653 		__dbj_throw(jenv, EINVAL, "null object", NULL, jdbenv);
654 		return;
655 	}
656 
657 	if ((*jenv)->GetArrayLength(jenv, list) < offset + count) {
658 		__dbj_throw(jenv, EINVAL,
659 		    "DbEnv.lock_vec array not large enough", NULL, jdbenv);
660 		return;
661 	}
662 
663 	bytesize = sizeof(DB_LOCKREQ) * count;
664 	if ((ret = __os_malloc(env, bytesize, &lockreq)) != 0) {
665 		__dbj_throw(jenv, ret, NULL, NULL, jdbenv);
666 		return;
667 	}
668 	memset(lockreq, 0, bytesize);
669 
670 	ldbtsize = sizeof(DBT_LOCKED) * count;
671 	if ((ret = __os_malloc(env, ldbtsize, &locked_dbts)) != 0) {
672 		__dbj_throw(jenv, ret, NULL, NULL, jdbenv);
673 		goto err;
674 	}
675 	memset(locked_dbts, 0, ldbtsize);
676 	prereq = &lockreq[0];
677 
678 	/* fill in the lockreq array */
679 	for (i = 0, prereq = &lockreq[0]; i < count; i++, prereq++) {
680 		jlockreq = (*jenv)->GetObjectArrayElement(jenv, list,
681 		    offset + i);
682 		if (jlockreq == NULL) {
683 			__dbj_throw(jenv, EINVAL,
684 			    "DbEnv.lock_vec list entry is null", NULL, jdbenv);
685 			goto err;
686 		}
687 		op = (db_lockop_t)(*jenv)->GetIntField(
688                     jenv, jlockreq, lockreq_op_fid);
689 		prereq->op = op;
690 
691 		switch (op) {
692 		case DB_LOCK_GET_TIMEOUT:
693 			/* Needed: mode, timeout, obj.  Returned: lock. */
694 			prereq->op = (db_lockop_t)(*jenv)->GetIntField(
695 			    jenv, jlockreq, lockreq_timeout_fid);
696 			/* FALLTHROUGH */
697 		case DB_LOCK_GET:
698 			/* Needed: mode, obj.  Returned: lock. */
699 			prereq->mode = (db_lockmode_t)(*jenv)->GetIntField(
700 			    jenv, jlockreq, lockreq_modeflag_fid);
701 			jobj = (*jenv)->GetObjectField(jenv, jlockreq,
702 			    lockreq_obj_fid);
703 			if ((ret = __dbj_dbt_copyin(jenv,
704 			    &locked_dbts[i], &obj, jobj, 0)) != 0 ||
705 			    (ret = __dbt_usercopy(env, obj)) != 0)
706 				goto err;
707 			prereq->obj = obj;
708 			break;
709 		case DB_LOCK_PUT:
710 			/* Needed: lock.  Ignored: mode, obj. */
711 			jlock = (*jenv)->GetObjectField(jenv, jlockreq,
712 				lockreq_lock_fid);
713 			if (jlock == NULL ||
714 			    (jlockp = (*jenv)->GetLongField(jenv, jlock,
715 			    lock_cptr_fid)) == 0L) {
716 				__dbj_throw(jenv, EINVAL,
717 				    "LockRequest lock field is NULL", NULL,
718 				    jdbenv);
719 				goto err;
720 			}
721 			lockp = *(DB_LOCK **)(void *)&jlockp;
722 			prereq->lock = *lockp;
723 			break;
724 		case DB_LOCK_PUT_ALL:
725 		case DB_LOCK_TIMEOUT:
726 			/* Needed: (none).  Ignored: lock, mode, obj. */
727 			break;
728 		case DB_LOCK_PUT_OBJ:
729 			/* Needed: obj.  Ignored: lock, mode. */
730 			jobj = (*jenv)->GetObjectField(jenv, jlockreq,
731 			    lockreq_obj_fid);
732 			if ((ret = __dbj_dbt_copyin(jenv,
733 			    &locked_dbts[i], &obj, jobj, 0)) != 0 ||
734 			    (ret = __dbt_usercopy(env, obj)) != 0)
735 				goto err;
736 			prereq->obj = obj;
737 			break;
738 		default:
739 			__dbj_throw(jenv, EINVAL,
740 			    "DbEnv.lock_vec bad op value", NULL, jdbenv);
741 			goto err;
742 		}
743 	}
744 
745 	ret = dbenv->lock_vec(dbenv, (u_int32_t)locker, (u_int32_t)flags,
746 	    lockreq, count, &failedreq);
747 	if (ret == 0)
748 		completed = count;
749 	else
750 		completed = (int)(failedreq - lockreq);
751 
752 	/* do post processing for any and all requests that completed */
753 	for (i = 0; i < completed; i++) {
754 		op = lockreq[i].op;
755 		if (op == DB_LOCK_PUT) {
756 			/*
757 			 * After a successful put, the DbLock can no longer be
758 			 * used, so we release the storage related to it.
759 			 */
760 			jlockreq = (*jenv)->GetObjectArrayElement(jenv,
761 			    list, i + offset);
762 			jlock = (*jenv)->GetObjectField(jenv, jlockreq,
763 			    lockreq_lock_fid);
764 			jlockp = (*jenv)->GetLongField(jenv, jlock,
765 			    lock_cptr_fid);
766 			lockp = *(DB_LOCK **)(void *)&jlockp;
767 			__os_free(NULL, lockp);
768 			(*jenv)->SetLongField(jenv, jlock, lock_cptr_fid,
769 			    (jlong)0);
770 		} else if (op == DB_LOCK_GET_TIMEOUT || op == DB_LOCK_GET) {
771 			/*
772 			 * Store the lock that was obtained.  We need to create
773 			 * storage for it since the lockreq array only exists
774 			 * during this method call.
775 			 */
776 			if ((alloc_err =
777 			    __os_malloc(env, sizeof(DB_LOCK), &lockp)) != 0) {
778 				__dbj_throw(jenv, alloc_err, NULL, NULL,
779 				    jdbenv);
780 				goto err;
781 			}
782 
783 			*lockp = lockreq[i].lock;
784 			*(DB_LOCK **)(void *)&jlockp = lockp;
785 
786 			jlockreq = (*jenv)->GetObjectArrayElement(jenv,
787 			    list, i + offset);
788 			jlock = (*jenv)->NewObject(jenv, lock_class,
789 			    lock_construct, jlockp, JNI_TRUE);
790 			if (jlock == NULL)
791 				goto err; /* An exception is pending */
792 			(*jenv)->SetLongField(jenv, jlock, lock_cptr_fid,
793 			    jlockp);
794 			(*jenv)->SetObjectField(jenv, jlockreq,
795 			    lockreq_lock_fid, jlock);
796 		}
797 	}
798 
799 	/* If one of the locks was not granted, build the exception now. */
800 	if (ret == DB_LOCK_NOTGRANTED && i < count) {
801 		jlockreq = (*jenv)->GetObjectArrayElement(jenv, list,
802 		    i + offset);
803 		jobj = (*jenv)->GetObjectField(jenv, jlockreq, lockreq_obj_fid);
804 		jlock = (*jenv)->GetObjectField(jenv, jlockreq,
805 		    lockreq_lock_fid);
806 		(*jenv)->Throw(jenv,
807 		    (*jenv)->NewObject(jenv, lockex_class, lockex_construct,
808 		    (*jenv)->NewStringUTF(jenv, "DbEnv.lock_vec incomplete"),
809 		    lockreq[i].op, lockreq[i].mode, jobj, jlock, i, jdbenv));
810 	} else if (ret != 0)
811 		__dbj_throw(jenv, ret, NULL, NULL, jdbenv);
812 
813 err:	for (i = 0, prereq = &lockreq[0]; i < count; i++, prereq++)
814 		if (prereq->op == DB_LOCK_GET_TIMEOUT ||
815 		    prereq->op == DB_LOCK_GET ||
816 		    prereq->op == DB_LOCK_PUT_OBJ) {
817 			jlockreq = (*jenv)->GetObjectArrayElement(jenv,
818 			    list, i + offset);
819 			jobj = (*jenv)->GetObjectField(jenv,
820 			    jlockreq, lockreq_obj_fid);
821 			__dbt_userfree(env, prereq->obj, NULL, NULL);
822 			__dbj_dbt_release(jenv, jobj, prereq->obj, &locked_dbts[i]);
823 	}
824 	if (locked_dbts != NULL)
825 		__os_free(env, locked_dbts);
826 	if (lockreq != NULL)
827 		__os_free(env, lockreq);
828 }
829 %}
830 
831 %native(DbTxn_commit) void DbTxn_commit(DB_TXN *txn, u_int32_t flags);
832 %{
833 SWIGEXPORT void JNICALL
Java_com_sleepycat_db_internal_db_1javaJNI_DbTxn_1commit(JNIEnv * jenv,jclass jcls,jlong jarg1,jobject jarg1_,jint jarg2)834 Java_com_sleepycat_db_internal_db_1javaJNI_DbTxn_1commit(JNIEnv *jenv,
835     jclass jcls, jlong jarg1, jobject jarg1_, jint jarg2) {
836   struct DbTxn *txn = (struct DbTxn *) 0 ;
837   ENV *env = (ENV *) 0 ;
838   u_int32_t flags;
839   DB_TXN_TOKEN token;
840   db_ret_t result;
841   db_ret_t result1;
842   int is_nested, is_logging_enabled, is_rep_client, commit_token_enabled;
843 
844   (void)jcls;
845   txn = *(struct DbTxn **)&jarg1;
846   flags = (u_int32_t)jarg2;
847 
848   if (jarg1 == 0) {
849      __dbj_throw(jenv, EINVAL, "call on closed handle", NULL, NULL);
850   return ;
851   }
852 
853   /*
854    * The Java API uses set_commit_token in a different way to the C API.
855    * In Java a commit token is always generated, unless doing so would
856    * generate an error from the C API.
857    * The checks below are based on those in place in the implementation
858    * of set_commit_token in the C API. It is invalid to set a commit
859    * token for a subtransaction, or if logging is disabled, or on a rep
860    * client node.
861    */
862   env = txn->mgrp->env;
863   is_nested = (txn->parent != NULL);
864   is_logging_enabled = env->lg_handle != NULL;
865   is_rep_client = (env->rep_handle != NULL &&
866                    env->rep_handle->region != NULL &&
867                    F_ISSET((env->rep_handle->region), REP_F_CLIENT));
868   commit_token_enabled = (!is_nested && is_logging_enabled && !is_rep_client);
869 
870   if (commit_token_enabled) {
871     result1 = (db_ret_t)txn->set_commit_token(txn, &token);
872   }
873 
874   result = (db_ret_t)txn->commit(txn, flags);
875   if (!DB_RETOK_STD(result)) {
876      __dbj_throw(jenv, result, NULL, NULL, NULL);
877   }
878 
879   /*
880    * Set the commit token in the Java Transaction class object only if
881    * the Core has generated a valid token for this transaction
882    */
883   if (commit_token_enabled && DB_RETOK_STD(result1)) {
884      jbyteArray newarr = (*jenv)->NewByteArray(jenv, (jsize)DB_TXN_TOKEN_SIZE);
885      if (newarr == NULL) {
886         return; /* An exception is pending */
887      }
888      (*jenv)->SetByteArrayRegion(jenv, newarr, 0, (jsize)DB_TXN_TOKEN_SIZE,
889         (jbyte *)&token);
890      (*jenv)->SetObjectField(jenv, jarg1_, txn_commit_token, newarr);
891   }
892 }
893 %}
894 
895 JAVA_TYPEMAP(struct __db_repmgr_site_address,
896     com.sleepycat.db.ReplicationHostAddress, jobject)
897 %typemap(out) struct __db_repmgr_site_address
898 {
899 	jstring addr_host;
900 	if ($1.host == NULL)
901 		return $null;
902 	addr_host = (*jenv)->NewStringUTF(jenv, $1.host);
903 	if (addr_host == NULL)
904 		return $null; /* An exception is pending. */
905 	$result = (*jenv)->NewObject(jenv,
906 	    rephost_class, rephost_construct, addr_host, $1.port);
907 	if ($result == NULL)
908 		return $null; /* An exception is pending */
909 }
910 
911 JAVA_TYPEMAP(struct __db_repmgr_sites,
912     com.sleepycat.db.ReplicationManagerSiteInfo[], jobjectArray)
913 %typemap(out) struct __db_repmgr_sites
914 {
915 	int i, len;
916 	jobject jrep_addr, jrep_info;
917 
918 	len = $1.nsites;
919 	$result = (*jenv)->NewObjectArray(jenv, (jsize)len, repmgr_siteinfo_class,
920 	    NULL);
921 	if ($result == NULL)
922 		return $null; /* an exception is pending */
923 	for (i = 0; i < len; i++) {
924 		jstring addr_host = (*jenv)->NewStringUTF(jenv, $1.sites[i].host);
925 		if (addr_host == NULL)
926 			return $null; /* An exception is pending */
927 		jrep_addr = (*jenv)->NewObject(jenv,
928 		    rephost_class, rephost_construct, addr_host, $1.sites[i].port);
929 		if (jrep_addr == NULL)
930 			return $null; /* An exception is pending */
931 
932 		jrep_info = (*jenv)->NewObject(jenv,
933 		    repmgr_siteinfo_class, repmgr_siteinfo_construct, jrep_addr, $1.sites[i].eid);
934 		if (jrep_info == NULL)
935 			return $null; /* An exception is pending */
936 		(*jenv)->SetIntField(jenv, jrep_info, repmgr_siteinfo_flags_fid,
937 		    $1.sites[i].flags);
938 		(*jenv)->SetIntField(jenv, jrep_info, repmgr_siteinfo_status_fid,
939 		    $1.sites[i].status);
940 
941 		(*jenv)->SetObjectArrayElement(jenv, $result, i, jrep_info);
942 	}
943 	__os_ufree(NULL, $1.sites);
944 }
945 
946 JAVA_TYPEMAP(void *, Object, jobject)
947 
948 JAVA_TYPEMAP(DBT *chan_msgs, com.sleepycat.db.DatabaseEntry[], jobjectArray)
949 %typemap(in) DBT *chan_msgs {
950 	DBT_LOCKED lresult;
951 	int count, i, ret;
952 
953 	count = (*jenv)->GetArrayLength(jenv, $input);
954 	if ((ret = __os_malloc(NULL, count * sizeof(DBT), &$1)) != 0) {
955 		__dbj_throw(jenv, ret, NULL, NULL, NULL);
956 		return $null;
957 	}
958 	memset($1, 0, count * sizeof(DBT));
959 	for (i = 0; i < count; i++) {
960 		jobject jresult = (*jenv)->GetObjectArrayElement(jenv, $input, i);
961 		if ((ret =
962 		    __dbj_dbt_copyin(jenv, &lresult, NULL, jresult, 0)) != 0) {
963 			return $null; /* An exception will be pending. */
964 		}
965 		if (lresult.dbt.size != 0) {
966 			/* If there's data, we need to take a copy of it.  */
967 			$1[i].size = lresult.dbt.size;
968 			if ((ret = __os_malloc(
969 			    NULL, $1[i].size, $1[i].data)) != 0) {
970 				__dbj_throw(jenv, ret, NULL, NULL, NULL);
971 				return $null;
972 			}
973 
974 			if ((ret = __dbj_dbt_memcopy(&lresult.dbt, 0,
975 			    $1[i].data, $1[i].size, DB_USERCOPY_GETDATA)) != 0) {
976 				__dbj_throw(jenv, ret, NULL, NULL, NULL);
977 				return $null;
978 			}
979 
980 			__dbj_dbt_release(jenv, jresult, &lresult.dbt, &lresult);
981 			(*jenv)->DeleteLocalRef(jenv, lresult.jarr);
982 		}
983 		(*jenv)->DeleteLocalRef(jenv, jresult);
984 	}
985 }
986 
987 %typemap(freearg) DBT *chan_msgs %{
988 {
989 	int count, i;
990 
991 	count = (*jenv)->GetArrayLength(jenv, $input);
992 	for (i = 0; i < count; i++)
993 		__os_free(NULL, $1[i].data);
994 	__os_free(NULL, $1);
995 }
996 %}
997 
998