java_typemaps.i   [plain text]


/* Typemaps */
%define JAVA_TYPEMAP(_ctype, _jtype, _jnitype)
%typemap(jstype) _ctype #_jtype
%typemap(jtype) _ctype #_jtype
%typemap(jni) _ctype #_jnitype
%typemap(out) _ctype %{ $result = (_jnitype)$1; %}
%typemap(javain) _ctype "$javainput"
%typemap(javaout) _ctype { return $jnicall; }
%enddef

JAVA_TYPEMAP(int32_t, int, jint)
JAVA_TYPEMAP(u_int32_t, int, jint)
JAVA_TYPEMAP(u_int32_t pagesize, long, jlong)
JAVA_TYPEMAP(long, long, jlong)
JAVA_TYPEMAP(db_seq_t, long, jlong)
JAVA_TYPEMAP(pid_t, long, jlong)
#ifndef SWIGJAVA
JAVA_TYPEMAP(db_threadid_t, long, jlong)
#endif
JAVA_TYPEMAP(db_timeout_t, long, jlong)
JAVA_TYPEMAP(size_t, long, jlong)
JAVA_TYPEMAP(db_ret_t, void, void)
%typemap(javaout) db_ret_t { $jnicall; }
%typemap(out) db_ret_t ""

JAVA_TYPEMAP(int_bool, boolean, jboolean)
%typemap(in) int_bool %{ $1 = ($input == JNI_TRUE); %}
%typemap(out) int_bool %{ $result = ($1) ? JNI_TRUE : JNI_FALSE; %}

/* Dbt handling */
JAVA_TYPEMAP(DBT *, com.sleepycat.db.DatabaseEntry, jobject)

%{
typedef struct __dbt_locked {
	JNIEnv *jenv;
	jobject jdbt;
	DBT dbt;
	jobject jdata_nio;
	jbyteArray jarr;
	jint offset;
	int reuse;
	u_int32_t orig_size;
	jsize array_len;
} DBT_LOCKED;

static int __dbj_dbt_memcopy(DBT *dbt, u_int32_t offset, void *buf, u_int32_t size, u_int32_t flags) {
	DBT_LOCKED *ldbt = dbt->app_data;
	JNIEnv *jenv = ldbt->jenv;

	if (size == 0)
		return (0);
	else if (!F_ISSET(dbt, DB_DBT_USERCOPY)) {
		/*
		  * For simplicity, the Java API calls this function directly,
		  * so it needs to work with regular DBTs.
		  */
		switch (flags) {
		case DB_USERCOPY_GETDATA:
			memcpy(buf, (u_int8_t *)dbt->data + offset, size);
			return (0);
		case DB_USERCOPY_SETDATA:
			memcpy((u_int8_t *)dbt->data + offset, buf, size);
			return (0);
		default:
			return (EINVAL);
		}
	}

	switch (flags) {
	case DB_USERCOPY_GETDATA:
		(*jenv)->GetByteArrayRegion(jenv, ldbt->jarr, ldbt->offset +
					    offset, size, buf);
		break;
	case DB_USERCOPY_SETDATA:
		/*
		 * Check whether this is the first time through the callback by relying
		 * on the offset being zero.
		 */
		if (offset == 0 && (!ldbt->reuse ||
		    (jsize)(ldbt->offset + dbt->size) > ldbt->array_len)) {
			if (ldbt->jarr != NULL)
				(*jenv)->DeleteLocalRef(jenv, ldbt->jarr);
			ldbt->jarr = (*jenv)->NewByteArray(jenv, (jsize)dbt->size);
			if (ldbt->jarr == NULL)
				return (ENOMEM);
			(*jenv)->SetObjectField(jenv, ldbt->jdbt, dbt_data_fid, ldbt->jarr);
			/* We've allocated a new array, start from the beginning. */
			ldbt->offset = 0;
		}
		(*jenv)->SetByteArrayRegion(jenv, ldbt->jarr, ldbt->offset +
					    offset, size, buf);
		break;
	default:
		return (EINVAL);
	}
	return ((*jenv)->ExceptionOccurred(jenv) ? EINVAL : 0);
}

static void __dbj_dbt_copyout(
    JNIEnv *jenv, const DBT *dbt, jbyteArray *jarr, jobject jdbt)
{
	jbyteArray newarr = (*jenv)->NewByteArray(jenv, (jsize)dbt->size);
	if (newarr == NULL)
		return; /* An exception is pending */
	(*jenv)->SetByteArrayRegion(jenv, newarr, 0, (jsize)dbt->size,
	    (jbyte *)dbt->data);
	(*jenv)->SetObjectField(jenv, jdbt, dbt_data_fid, newarr);
	(*jenv)->SetIntField(jenv, jdbt, dbt_offset_fid, 0);
	(*jenv)->SetIntField(jenv, jdbt, dbt_size_fid, (jint)dbt->size);
	if (jarr != NULL)
		*jarr = newarr;
	else
		(*jenv)->DeleteLocalRef(jenv, newarr);
}

static int __dbj_dbt_copyin(
    JNIEnv *jenv, DBT_LOCKED *ldbt, DBT **dbtp, jobject jdbt, int allow_null)
{
	DBT *dbt;
	jlong capacity;

	memset(ldbt, 0, sizeof (*ldbt));
	ldbt->jenv = jenv;
	ldbt->jdbt = jdbt;

	if (jdbt == NULL) {
		if (allow_null) {
			*dbtp = NULL;
			return (0);
		} else {
			return (__dbj_throw(jenv, EINVAL,
			    "DatabaseEntry must not be null", NULL, NULL));
		}
	}

	dbt = &ldbt->dbt;
	if (dbtp != NULL)
		*dbtp = dbt;

	ldbt->jdata_nio = (*jenv)->GetObjectField(jenv, jdbt, dbt_data_nio_fid);
	if (ldbt->jdata_nio != NULL)
		F_SET(dbt, DB_DBT_USERMEM);
	else
		ldbt->jarr = (jbyteArray)(*jenv)->GetObjectField(jenv, jdbt, dbt_data_fid);
	ldbt->offset = (*jenv)->GetIntField(jenv, jdbt, dbt_offset_fid);
	dbt->size = (*jenv)->GetIntField(jenv, jdbt, dbt_size_fid);
	ldbt->orig_size = dbt->size;
	dbt->flags = (*jenv)->GetIntField(jenv, jdbt, dbt_flags_fid);

	if (F_ISSET(dbt, DB_DBT_USERMEM))
		dbt->ulen = (*jenv)->GetIntField(jenv, jdbt, dbt_ulen_fid);
	if (F_ISSET(dbt, DB_DBT_PARTIAL)) {
		dbt->dlen = (*jenv)->GetIntField(jenv, jdbt, dbt_dlen_fid);
		dbt->doff = (*jenv)->GetIntField(jenv, jdbt, dbt_doff_fid);

		if ((jint)dbt->doff < 0)
			return (__dbj_throw(jenv, EINVAL, "DatabaseEntry doff illegal",
			    NULL, NULL));
	}

	/*
	 * We don't support DB_DBT_REALLOC - map anything that's not USERMEM to
	 * MALLOC.
	 */
	if (!F_ISSET(dbt, DB_DBT_USERMEM)) {
		ldbt->reuse = !F_ISSET(dbt, DB_DBT_MALLOC);
		F_CLR(dbt, DB_DBT_MALLOC | DB_DBT_REALLOC);
	}

	/* Verify parameters before allocating or locking data. */
	if (ldbt->jdata_nio != NULL) {
		capacity = (*jenv)->GetDirectBufferCapacity(jenv,
				ldbt->jdata_nio);
		if (capacity > (jlong)UINT32_MAX)
			return (__dbj_throw(jenv, EINVAL,
			    "DirectBuffer may not be larger than 4GB",
			    NULL, NULL));
		ldbt->array_len = (u_int32_t)capacity;
	} else if (ldbt->jarr == NULL) {
		/*
		 * Some code makes the assumption that if a DBT's size or ulen
		 * is non-zero, there is data to copy from dbt->data.
		 *
		 * Clean up the dbt fields so we don't run into trouble.
		 * (Note that doff, dlen, and flags all may contain
		 * meaningful values.)
		 */
		dbt->data = NULL;
		ldbt->array_len = ldbt->offset = dbt->size = dbt->ulen = 0;
	} else
		ldbt->array_len = (*jenv)->GetArrayLength(jenv, ldbt->jarr);

	if (F_ISSET(dbt, DB_DBT_USERMEM)) {
		if (ldbt->offset < 0)
			return (__dbj_throw(jenv, EINVAL,
			    "offset cannot be negative",
			    NULL, NULL));
		if (dbt->size > dbt->ulen)
			return (__dbj_throw(jenv, EINVAL,
			    "size must be less than or equal to ulen",
			    NULL, NULL));
		if ((jsize)(ldbt->offset + dbt->ulen) > ldbt->array_len)
			return (__dbj_throw(jenv, EINVAL,
			    "offset + ulen greater than array length",
			    NULL, NULL));
	}

	if (ldbt->jdata_nio) {
		dbt->data = (*jenv)->GetDirectBufferAddress(jenv,
				ldbt->jdata_nio);
		dbt->data = (u_int8_t *)dbt->data + ldbt->offset;
	} else if (F_ISSET(dbt, DB_DBT_USERMEM)) {
		if (ldbt->jarr != NULL &&
		    (dbt->data = (*jenv)->GetByteArrayElements(jenv,
		    ldbt->jarr, NULL)) == NULL)
			return (EINVAL); /* an exception will be pending */
		dbt->data = (u_int8_t *)dbt->data + ldbt->offset;
	} else
		F_SET(dbt, DB_DBT_USERCOPY);
	dbt->app_data = ldbt;

	return (0);
}

static void __dbj_dbt_release(
    JNIEnv *jenv, jobject jdbt, DBT *dbt, DBT_LOCKED *ldbt) {
	jthrowable t;

	if (dbt == NULL)
		return;

	if (dbt->size != ldbt->orig_size)
		(*jenv)->SetIntField(jenv, jdbt, dbt_size_fid, (jint)dbt->size);

	if (F_ISSET(dbt, DB_DBT_USERMEM)) {
		if (ldbt->jarr != NULL)
			(*jenv)->ReleaseByteArrayElements(jenv, ldbt->jarr,
			    (jbyte *)dbt->data - ldbt->offset, 0);

		if (dbt->size > dbt->ulen &&
		    (t = (*jenv)->ExceptionOccurred(jenv)) != NULL &&
		    (*jenv)->IsInstanceOf(jenv, t, memex_class)) {
			(*jenv)->CallNonvirtualVoidMethod(jenv, t, memex_class,
			    memex_update_method, jdbt);
			/*
			 * We have to rethrow the exception because calling
			 * into Java clears it.
			 */
			(*jenv)->Throw(jenv, t);
		}
	}
}
%}

%typemap(in) DBT * (DBT_LOCKED ldbt) %{
	if (__dbj_dbt_copyin(jenv, &ldbt, &$1, $input, 0) != 0) {
		return $null; /* An exception will be pending. */
	}%}

/* Special cases for DBTs that may be null: DbEnv.rep_start and Db.compact */
%typemap(in) DBT *data_or_null (DBT_LOCKED ldbt) %{
	if (__dbj_dbt_copyin(jenv, &ldbt, &$1, $input, 1) != 0) {
		return $null; /* An exception will be pending. */
	}%}

%apply DBT *data_or_null {DBT *cdata, DBT *start, DBT *stop, DBT *end};

%typemap(freearg) DBT * %{ __dbj_dbt_release(jenv, $input, $1, &ldbt$argnum); %}

/* DbLsn handling */
JAVA_TYPEMAP(DB_LSN *, com.sleepycat.db.LogSequenceNumber, jobject)

%typemap(check) DB_LSN *lsn_or_null ""

%typemap(check) DB_LSN * %{
	if ($1 == NULL) {
		__dbj_throw(jenv, EINVAL, "null LogSequenceNumber", NULL, NULL);
		return $null;
	}
%}

%typemap(in) DB_LSN * (DB_LSN lsn) %{
	if ($input == NULL) {
		$1 = NULL;
	} else {
		$1 = &lsn;
		$1->file = (*jenv)->GetIntField(jenv, $input, dblsn_file_fid);
		$1->offset = (*jenv)->GetIntField(jenv, $input,
		    dblsn_offset_fid);
	}
%}

%typemap(freearg) DB_LSN * %{
	if ($input != NULL) {
		(*jenv)->SetIntField(jenv, $input, dblsn_file_fid, $1->file);
		(*jenv)->SetIntField(jenv, $input,
		    dblsn_offset_fid, $1->offset);
	}
%}

/* Various typemaps */
JAVA_TYPEMAP(time_t, long, jlong)
JAVA_TYPEMAP(time_t *, long, jlong)
%typemap(in) time_t * (time_t time) %{
	time = (time_t)$input;
	$1 = &time;
%}

JAVA_TYPEMAP(DB_KEY_RANGE *, com.sleepycat.db.KeyRange, jobject)
%typemap(in) DB_KEY_RANGE * (DB_KEY_RANGE range) {
	$1 = &range;
}
%typemap(argout) DB_KEY_RANGE * {
	(*jenv)->SetDoubleField(jenv, $input, kr_less_fid, $1->less);
	(*jenv)->SetDoubleField(jenv, $input, kr_equal_fid, $1->equal);
	(*jenv)->SetDoubleField(jenv, $input, kr_greater_fid, $1->greater);
}

JAVA_TYPEMAP(DBC **, Dbc[], jobjectArray)
%typemap(in) DBC ** {
	int i, count, err;

	count = (*jenv)->GetArrayLength(jenv, $input);
	if ((err = __os_malloc(NULL, (count + 1) * sizeof(DBC *), &$1)) != 0) {
		__dbj_throw(jenv, err, NULL, NULL, DB2JDBENV);
		return $null;
	}
	for (i = 0; i < count; i++) {
		jobject jobj = (*jenv)->GetObjectArrayElement(jenv, $input, i);
		/*
		 * A null in the array is treated as an endpoint.
		 */
		if (jobj == NULL) {
			$1[i] = NULL;
			break;
		} else {
			jlong jptr = (*jenv)->GetLongField(jenv, jobj,
			    dbc_cptr_fid);
			$1[i] = *(DBC **)(void *)&jptr;
		}
	}
	$1[count] = NULL;
}

%typemap(freearg) DBC ** %{
	__os_free(NULL, $1);
%}

JAVA_TYPEMAP(u_int8_t *gid, byte[], jbyteArray)
%typemap(check) u_int8_t *gid %{
	if ((*jenv)->GetArrayLength(jenv, $input) < DB_XIDDATASIZE) {
		__dbj_throw(jenv, EINVAL,
		    "DbTxn.prepare gid array must be >= 128 bytes", NULL,
		    TXN2JDBENV);
		return $null;
	}
%}

%typemap(in) u_int8_t *gid %{
	$1 = (u_int8_t *)(*jenv)->GetByteArrayElements(jenv, $input, NULL);
%}

%typemap(freearg) u_int8_t *gid %{
	(*jenv)->ReleaseByteArrayElements(jenv, $input, (jbyte *)$1, 0);
%}

%define STRING_ARRAY_OUT
	int i, len;

	len = 0;
	while ($1[len] != NULL)
		len++;
	if (($result = (*jenv)->NewObjectArray(jenv, (jsize)len, string_class,
	    NULL)) == NULL)
		return $null; /* an exception is pending */
	for (i = 0; i < len; i++) {
		jstring str = (*jenv)->NewStringUTF(jenv, $1[i]);
		(*jenv)->SetObjectArrayElement(jenv, $result, (jsize)i, str);
	}
%enddef

JAVA_TYPEMAP(char **, String[], jobjectArray)
%typemap(out) const char ** {
	if ($1 != NULL) {
		STRING_ARRAY_OUT
	}
}
%typemap(out) char ** {
	if ($1 != NULL) {
		STRING_ARRAY_OUT
		__os_ufree(NULL, $1);
	}
}

JAVA_TYPEMAP(struct __db_lk_conflicts, byte[][], jobjectArray)
%typemap(in) struct __db_lk_conflicts {
	int i, len, err;
	size_t bytesize;

	len = $1.lk_modes = (*jenv)->GetArrayLength(jenv, $input);
	bytesize = sizeof(u_char) * len * len;

	if ((err = __os_malloc(NULL, bytesize, &$1.lk_conflicts)) != 0) {
		__dbj_throw(jenv, err, NULL, NULL, JDBENV);
		return $null;
	}

	for (i = 0; i < len; i++) {
		jobject sub_array = (*jenv)->GetObjectArrayElement(jenv,
		    $input, i);
		(*jenv)->GetByteArrayRegion(jenv,(jbyteArray)sub_array, 0, len,
		    (jbyte *)&$1.lk_conflicts[i * len]);
	}
}

%typemap(freearg) struct __db_lk_conflicts %{
	__os_free(NULL, $1.lk_conflicts);
%}

%typemap(out) struct __db_lk_conflicts {
	int i;
	jbyteArray bytes;

	$result = (*jenv)->NewObjectArray(jenv,
	    (jsize)$1.lk_modes, bytearray_class, NULL);
	if ($result == NULL)
		return $null; /* an exception is pending */
	for (i = 0; i < $1.lk_modes; i++) {
		bytes = (*jenv)->NewByteArray(jenv, (jsize)$1.lk_modes);
		if (bytes == NULL)
			return $null; /* an exception is pending */
		(*jenv)->SetByteArrayRegion(jenv, bytes, 0, (jsize)$1.lk_modes,
		    (jbyte *)($1.lk_conflicts + i * $1.lk_modes));
		(*jenv)->SetObjectArrayElement(jenv, $result, (jsize)i, bytes);
	}
}

%{
struct __dbj_verify_data {
	JNIEnv *jenv;
	jobject streamobj;
	jbyteArray bytes;
	int nbytes;
};

static int __dbj_verify_callback(void *handle, const void *str_arg) {
	char *str;
	struct __dbj_verify_data *vd;
	int len;
	JNIEnv *jenv;

	str = (char *)str_arg;
	vd = (struct __dbj_verify_data *)handle;
	jenv = vd->jenv;
	len = strlen(str) + 1;
	if (len > vd->nbytes) {
		vd->nbytes = len;
		if (vd->bytes != NULL)
			(*jenv)->DeleteLocalRef(jenv, vd->bytes);
		if ((vd->bytes = (*jenv)->NewByteArray(jenv, (jsize)len))
		    == NULL)
			return (ENOMEM);
	}

	if (vd->bytes != NULL) {
		(*jenv)->SetByteArrayRegion(jenv, vd->bytes, 0, (jsize)len,
		    (jbyte*)str);
		(*jenv)->CallVoidMethod(jenv, vd->streamobj,
		    outputstream_write_method, vd->bytes, 0, len - 1);
	}

	if ((*jenv)->ExceptionOccurred(jenv) != NULL)
		return (EIO);

	return (0);
}
%}

JAVA_TYPEMAP(struct __db_out_stream, java.io.OutputStream, jobject)
%typemap(in) struct __db_out_stream (struct __dbj_verify_data data) {
	data.jenv = jenv;
	data.streamobj = $input;
	data.bytes = NULL;
	data.nbytes = 0;
	$1.handle = &data;
	$1.callback = __dbj_verify_callback;
}

JAVA_TYPEMAP(DB_PREPLIST *, com.sleepycat.db.PreparedTransaction[],
    jobjectArray)
%typemap(out) DB_PREPLIST * {
	int i, len;

	len = 0;
	while ($1[len].txn != NULL)
		len++;
	$result = (*jenv)->NewObjectArray(jenv, (jsize)len, dbpreplist_class,
	    NULL);
	if ($result == NULL)
		return $null; /* an exception is pending */
	for (i = 0; i < len; i++) {
		jobject jtxn = (*jenv)->NewObject(jenv, dbtxn_class,
		    dbtxn_construct, $1[i].txn, JNI_FALSE);
		jobject bytearr = (*jenv)->NewByteArray(jenv,
		    (jsize)sizeof($1[i].gid));
		jobject obj = (*jenv)->NewObject(jenv, dbpreplist_class,
		    dbpreplist_construct, jtxn, bytearr);

		if (jtxn == NULL || bytearr == NULL || obj == NULL)
			return $null; /* An exception is pending */

		(*jenv)->SetByteArrayRegion(jenv, bytearr, 0,
		    (jsize)sizeof($1[i].gid), (jbyte *)$1[i].gid);
		(*jenv)->SetObjectArrayElement(jenv, $result, i, obj);
	}
	__os_ufree(NULL, $1);
}

JAVA_TYPEMAP(DB_LOCKREQ *, com.sleepycat.db.LockRequest[], jobjectArray)

%native(DbEnv_lock_vec) void DbEnv_lock_vec(DB_ENV *dbenv, u_int32_t locker,
    u_int32_t flags, DB_LOCKREQ *list, int offset, int nlist);
%{
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) {
	DB_ENV *dbenv;
	DB_LOCKREQ *lockreq;
	DB_LOCKREQ *prereq;	/* preprocessed requests */
	DB_LOCKREQ *failedreq;
	DB_LOCK *lockp;
	DBT_LOCKED *locked_dbts;
	DBT *obj;
	ENV *env;
	int err, alloc_err, i;
	size_t bytesize, ldbtsize;
	jobject jlockreq;
	db_lockop_t op;
	jobject jobj, jlock;
	jlong jlockp;
	int completed;

	COMPQUIET(jcls, NULL);
	dbenv = *(DB_ENV **)(void *)&jdbenvp;
	env = dbenv->env;

	if (dbenv == NULL) {
		__dbj_throw(jenv, EINVAL, "null object", NULL, jdbenv);
		return;
	}

	if ((*jenv)->GetArrayLength(jenv, list) < offset + count) {
		__dbj_throw(jenv, EINVAL,
		    "DbEnv.lock_vec array not large enough", NULL, jdbenv);
		goto out0;
	}

	bytesize = sizeof(DB_LOCKREQ) * count;
	if ((err = __os_malloc(env, bytesize, &lockreq)) != 0) {
		__dbj_throw(jenv, err, NULL, NULL, jdbenv);
		goto out0;
	}
	memset(lockreq, 0, bytesize);

	ldbtsize = sizeof(DBT_LOCKED) * count;
	if ((err = __os_malloc(env, ldbtsize, &locked_dbts)) != 0) {
		__dbj_throw(jenv, err, NULL, NULL, jdbenv);
		goto out1;
	}
	memset(locked_dbts, 0, ldbtsize);
	prereq = &lockreq[0];

	/* fill in the lockreq array */
	for (i = 0, prereq = &lockreq[0]; i < count; i++, prereq++) {
		jlockreq = (*jenv)->GetObjectArrayElement(jenv, list,
		    offset + i);
		if (jlockreq == NULL) {
			__dbj_throw(jenv, EINVAL,
			    "DbEnv.lock_vec list entry is null", NULL, jdbenv);
			goto out2;
		}
		op = (*jenv)->GetIntField(jenv, jlockreq, lockreq_op_fid);
		prereq->op = op;

		switch (op) {
		case DB_LOCK_GET_TIMEOUT:
			/* Needed: mode, timeout, obj.  Returned: lock. */
			prereq->op = (*jenv)->GetIntField(jenv, jlockreq,
			    lockreq_timeout_fid);
			/* FALLTHROUGH */
		case DB_LOCK_GET:
			/* Needed: mode, obj.  Returned: lock. */
			prereq->mode = (*jenv)->GetIntField(jenv, jlockreq,
			    lockreq_modeflag_fid);
			jobj = (*jenv)->GetObjectField(jenv, jlockreq,
			    lockreq_obj_fid);
			if ((err = __dbj_dbt_copyin(jenv,
			    &locked_dbts[i], &obj, jobj, 0)) != 0 ||
			    (err =
			    __os_umalloc(env, obj->size, &obj->data)) != 0 ||
			    (err = __dbj_dbt_memcopy(obj, 0,
				obj->data, obj->size, DB_USERCOPY_GETDATA)) != 0)
				goto out2;
			prereq->obj = obj;
			break;
		case DB_LOCK_PUT:
			/* Needed: lock.  Ignored: mode, obj. */
			jlock = (*jenv)->GetObjectField(jenv, jlockreq,
				lockreq_lock_fid);
			if (jlock == NULL ||
			    (jlockp = (*jenv)->GetLongField(jenv, jlock,
			    lock_cptr_fid)) == 0L) {
				__dbj_throw(jenv, EINVAL,
				    "LockRequest lock field is NULL", NULL,
				    jdbenv);
				goto out2;
			}
			lockp = *(DB_LOCK **)(void *)&jlockp;
			prereq->lock = *lockp;
			break;
		case DB_LOCK_PUT_ALL:
		case DB_LOCK_TIMEOUT:
			/* Needed: (none).  Ignored: lock, mode, obj. */
			break;
		case DB_LOCK_PUT_OBJ:
			/* Needed: obj.  Ignored: lock, mode. */
			jobj = (*jenv)->GetObjectField(jenv, jlockreq,
			    lockreq_obj_fid);
			if ((err = __dbj_dbt_copyin(jenv,
			    &locked_dbts[i], &obj, jobj, 0)) != 0 ||
			    (err =
			    __os_umalloc(env, obj->size, &obj->data)) != 0 ||
			    (err = __dbj_dbt_memcopy(obj, 0,
				obj->data, obj->size, DB_USERCOPY_GETDATA)) != 0)
				goto out2;
			prereq->obj = obj;
			break;
		default:
			__dbj_throw(jenv, EINVAL,
			    "DbEnv.lock_vec bad op value", NULL, jdbenv);
			goto out2;
		}
	}

	err = dbenv->lock_vec(dbenv, (u_int32_t)locker, (u_int32_t)flags,
	    lockreq, count, &failedreq);
	if (err == 0)
		completed = count;
	else
		completed = failedreq - lockreq;

	/* do post processing for any and all requests that completed */
	for (i = 0; i < completed; i++) {
		op = lockreq[i].op;
		if (op == DB_LOCK_PUT) {
			/*
			 * After a successful put, the DbLock can no longer be
			 * used, so we release the storage related to it.
			 */
			jlockreq = (*jenv)->GetObjectArrayElement(jenv,
			    list, i + offset);
			jlock = (*jenv)->GetObjectField(jenv, jlockreq,
			    lockreq_lock_fid);
			jlockp = (*jenv)->GetLongField(jenv, jlock,
			    lock_cptr_fid);
			lockp = *(DB_LOCK **)(void *)&jlockp;
			__os_free(NULL, lockp);
			(*jenv)->SetLongField(jenv, jlock, lock_cptr_fid,
			    (jlong)0);
		}
		else if (op == DB_LOCK_GET) {
			/*
			 * Store the lock that was obtained.  We need to create
			 * storage for it since the lockreq array only exists
			 * during this method call.
			 */
			if ((alloc_err =
			    __os_malloc(env, sizeof(DB_LOCK), &lockp)) != 0) {
				__dbj_throw(jenv, alloc_err, NULL, NULL,
				    jdbenv);
				goto out2;
			}

			*lockp = lockreq[i].lock;
			*(DB_LOCK **)(void *)&jlockp = lockp;

			jlockreq = (*jenv)->GetObjectArrayElement(jenv,
			    list, i + offset);
			jlock = (*jenv)->NewObject(jenv, lock_class,
			    lock_construct, jlockp, JNI_TRUE);
			if (jlock == NULL)
				goto out2; /* An exception is pending */
			(*jenv)->SetLongField(jenv, jlock, lock_cptr_fid,
			    jlockp);
			(*jenv)->SetObjectField(jenv, jlockreq,
			    lockreq_lock_fid, jlock);
		}
	}

	/* If one of the locks was not granted, build the exception now. */
	if (err == DB_LOCK_NOTGRANTED && i < count) {
		jlockreq = (*jenv)->GetObjectArrayElement(jenv, list,
		    i + offset);
		jobj = (*jenv)->GetObjectField(jenv, jlockreq,
		    lockreq_obj_fid);
		jlock = (*jenv)->GetObjectField(jenv, jlockreq,
		    lockreq_lock_fid);
		(*jenv)->Throw(jenv,
		    (*jenv)->NewObject(jenv, lockex_class, lockex_construct,
		    (*jenv)->NewStringUTF(jenv, "DbEnv.lock_vec incomplete"),
		    lockreq[i].op, lockreq[i].mode, jobj, jlock, i, jdbenv));
	} else if (err != 0)
		__dbj_throw(jenv, err, NULL, NULL, jdbenv);

out2:	__os_free(env, locked_dbts);
out1:	for (i = 0, prereq = &lockreq[0]; i < count; i++, prereq++)
		if ((prereq->op == DB_LOCK_GET || prereq->op == DB_LOCK_PUT) &&
		    prereq->obj->data != NULL)
			__os_ufree(env, prereq->obj->data);
	__os_free(env, lockreq);
out0:	return;
}
%}

JAVA_TYPEMAP(struct __db_repmgr_sites,
    com.sleepycat.db.ReplicationManagerSiteInfo[], jobjectArray)
%typemap(out) struct __db_repmgr_sites
{
	int i, len;
	jobject jrep_addr, jrep_info;

	len = $1.nsites;
	$result = (*jenv)->NewObjectArray(jenv, (jsize)len, repmgr_siteinfo_class,
	    NULL);
	if ($result == NULL)
		return $null; /* an exception is pending */
	for (i = 0; i < len; i++) {
		jstring addr_host = (*jenv)->NewStringUTF(jenv, $1.sites[i].host);
		if (addr_host == NULL)
			return $null; /* An exception is pending */
		jrep_addr = (*jenv)->NewObject(jenv,
		    rephost_class, rephost_construct, addr_host, $1.sites[i].port);
		if (jrep_addr == NULL)
			return $null; /* An exception is pending */

		jrep_info = (*jenv)->NewObject(jenv,
		    repmgr_siteinfo_class, repmgr_siteinfo_construct, jrep_addr, $1.sites[i].eid);
		(*jenv)->SetIntField(jenv, jrep_info, repmgr_siteinfo_status_fid,
		    $1.sites[i].status);
		if (jrep_info == NULL)
			return $null; /* An exception is pending */

		(*jenv)->SetObjectArrayElement(jenv, $result, i, jrep_info);
	}
	__os_ufree(NULL, $1.sites);
}

JAVA_TYPEMAP(void *, Object, jobject)