📄 jnicli.cpp
字号:
#define _JNI_IMPLEMENTATION_ 1
#include <jni.h>
#include "fastdb.h"
#include "localcli.h"
static cli_var_type const cliTypeMap[] = {
cli_oid,
cli_bool, // TP_BOOL
cli_int2, // TP_CHAR
cli_int1, // TP_INT1
cli_int2, // TP_INT2
cli_int4, // TP_INT4
cli_int8, // TP_INT8
cli_real4, // TP_REAL4
cli_real8, // TP_REAL8
cli_asciiz, // TP_STRING
cli_int8, // TP_DATE
cli_array_of_bool, // TP_BOOL_ARRAY
cli_array_of_int2, // TP_CHAR_ARRAY
cli_array_of_int1, // TP_INT1_ARRAY
cli_array_of_int2, // TP_INT2_ARRAY
cli_array_of_int4, // TP_INT4_ARRAY
cli_array_of_int8, // TP_INT8_ARRAY
cli_array_of_real4, // TP_REAL4_ARRAY
cli_array_of_real8, // TP_REAL8_ARRAY
cli_array_of_string, // TP_STRING_ARRAY
};
typedef char* charptr;
struct _abool { char n; bool v; };
struct _achar { char n; char v; };
struct _ajchar { char n; jchar v; };
struct _ajbyte { char n; jbyte v; };
struct _ajshort { char n; jshort v; };
struct _ajint { char n; jint v; };
struct _ajlong { char n; jlong v; };
struct _ajfloat { char n; jfloat v; };
struct _ajdouble { char n; jdouble v; };
struct _acharptr { char n; charptr v; };
struct _acli_array_t { char n; cli_array_t v; };
#define ALIGNOF(type) offsetof(_a##type, v)
#define SIZE_AND_ALIGNMENT(type) sizeof(type), ALIGNOF(type)
#define APPEND_FIXED(type) appendFixed(SIZE_AND_ALIGNMENT(type))
inline char const* getStringBody(JNIEnv* env, jstring str) {
return env->GetStringUTFChars(str, 0);
}
inline void releaseStringBody(JNIEnv* env, jstring str, char const* body) {
env->ReleaseStringUTFChars(str, body);
}
inline int getStringLength(JNIEnv* env, jstring str) {
return env->GetStringUTFLength(str);
}
inline jstring newString(JNIEnv* env, char const* body) {
return env->NewStringUTF(body);
}
class ClassDescriptor {
public:
int nColumns;
cli_field_descriptor* columns;
char* names;
~ClassDescriptor() {
delete[] columns;
delete[] names;
}
};
const size_t VARYING_BLOCK_SIZE = 1024;
struct VaryingBlock {
VaryingBlock* next;
char data[1];
};
class ObjectBuffer {
dbSmallBuffer fixedPart;
VaryingBlock* varyingPart;
size_t fixedPos;
size_t varyingPos;
public:
void* base() {
return fixedPart.base();
}
ObjectBuffer() {
fixedPos = 0;
varyingPos = 0;
varyingPart = NULL;
}
~ObjectBuffer() {
VaryingBlock *curr, *next;
for (curr = varyingPart; curr != NULL; curr = next) {
next = curr->next;
dbFree(curr);
}
}
void* appendFixed(size_t size, size_t alignment) {
fixedPos = DOALIGN(fixedPos, alignment);
fixedPart.put(fixedPos + size);
void* ptr = fixedPart.base() + fixedPos;
fixedPos += size;
return ptr;
}
void* appendVarying(size_t nElems, size_t elemSize, size_t elemAlignment) {
varyingPos = DOALIGN(varyingPos, elemAlignment);
size_t size = nElems*elemSize;
void* ptr;
if (varyingPart != NULL && varyingPos + size <= VARYING_BLOCK_SIZE) {
ptr = &varyingPart->data[varyingPos];
varyingPos += size;
} else {
VaryingBlock* blk = (VaryingBlock*)
dbMalloc(sizeof(VaryingBlock*) + (size < VARYING_BLOCK_SIZE ? VARYING_BLOCK_SIZE : size));
blk->next = varyingPart;
varyingPart = blk;
ptr = varyingPart->data;
varyingPos = size;
}
return ptr;
}
};
class JniResultSet {
public:
byte* record;
size_t pos;
dbAnyCursor cursor;
bool first;
JniResultSet(dbTableDescriptor* desc)
: record(new byte[desc->size()]), pos(0), cursor(*desc, dbCursorViewOnly, record), first(true)
{
memset(record, 0, desc->size());
cursor.reset();
}
int size() {
return cursor.getNumberOfRecords();
}
oid_t next() {
pos = 0;
if (first) {
if (cursor.isEmpty()) {
delete this;
return 0;
}
first = false;
} else if (!cursor.gotoNext()) {
delete this;
return 0;
}
cursor.fetch();
return cursor.currId;
}
jbyte nextByte() {
return (jbyte)record[pos++];
}
jshort nextShort() {
pos = DOALIGN(pos, ALIGNOF(jshort));
jshort val = *(jshort*)(record + pos);
pos += sizeof(jshort);
return val;
}
jint nextInt() {
pos = DOALIGN(pos, ALIGNOF(jint));
jint val = *(jint*)(record + pos);
pos += sizeof(jint);
return val;
}
jlong nextLong() {
pos = DOALIGN(pos, ALIGNOF(jlong));
jlong val = *(jlong*)(record + pos);
pos += sizeof(jlong);
return val;
}
jstring nextString(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(charptr));
jstring val = newString(env, *(char**)(record + pos));
pos += sizeof(char*);
return val;
}
jbooleanArray nextBoolArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jbooleanArray val = env->NewBooleanArray(arr->size);
env->SetBooleanArrayRegion(val, 0, arr->size, (jboolean*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jcharArray nextCharArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jcharArray val = env->NewCharArray(arr->size);
env->SetCharArrayRegion(val, 0, arr->size, (jchar*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jbyteArray nextByteArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jbyteArray val = env->NewByteArray(arr->size);
env->SetByteArrayRegion(val, 0, arr->size, (jbyte*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jshortArray nextShortArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jshortArray val = env->NewShortArray(arr->size);
env->SetShortArrayRegion(val, 0, arr->size, (jshort*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jintArray nextIntArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jintArray val = env->NewIntArray(arr->size);
env->SetIntArrayRegion(val, 0, arr->size, (jint*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jlongArray nextLongArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jlongArray val = env->NewLongArray(arr->size);
env->SetLongArrayRegion(val, 0, arr->size, (jlong*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jfloatArray nextFloatArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jfloatArray val = env->NewFloatArray(arr->size);
env->SetFloatArrayRegion(val, 0, arr->size, (jfloat*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jdoubleArray nextDoubleArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
jdoubleArray val = env->NewDoubleArray(arr->size);
env->SetDoubleArrayRegion(val, 0, arr->size, (jdouble*)arr->data);
pos += sizeof(cli_array_t);
return val;
}
jobjectArray nextStringArray(JNIEnv* env) {
pos = DOALIGN(pos, ALIGNOF(cli_array_t));
cli_array_t* arr = (cli_array_t*)(record + pos);
int size = (int)arr->size;
jobjectArray val = env->NewObjectArray(size, env->FindClass("java/lang/String"), NULL);
char** spp = (char**)arr->data;
for (int i = 0; i < size; i++) {
env->SetObjectArrayElement(val, i, newString(env, spp[i]));
}
pos += sizeof(cli_array_t);
return val;
}
~JniResultSet() {
delete[] record;
}
};
class JniDatabase : public dbDatabase {
private:
oid_t tableId;
oid_t nextTableId;
JNIEnv* env;
public:
JniDatabase(JNIEnv* env, dbAccessType type, size_t poolSize)
: dbDatabase(type, poolSize)
{
this->env = env;
}
virtual void handleError(dbErrorClass error, char const* msg, int arg = 0) {
jclass cls = env->FindClass("jnicli/CliException");
if (cls != NULL) {
env->ThrowNew(cls, msg);
}
}
void open(char const* databaseName, char const* databasePath, int transactionCommitDelay)
{
if (!dbDatabase::open(databaseName, databasePath, transactionCommitDelay)) {
handleError(dbDatabase::DatabaseOpenError, "Failed to open database");
return;
}
dbTable* table = (dbTable*)getRow(dbMetaTableId);
dbTableDescriptor* metatable = new dbTableDescriptor(table);
linkTable(metatable, dbMetaTableId);
oid_t tid = table->firstRow;
nextTableId = tid;
while (tid != 0) {
table = (dbTable*)getRow(tid);
dbTableDescriptor* desc = new dbTableDescriptor(table);
linkTable(desc, tid);
desc->setFlags();
tid = table->next;
}
}
jstring nextTable() {
tableId = nextTableId;
if (tableId == 0) {
if (!completeDescriptorsInitialization()) {
close();
handleError(dbDatabase::DatabaseOpenError, "Referenced table not found");
}
return NULL;
}
dbTable* table = (dbTable*)getRow(tableId);
jstring name = newString(env, (char*)((byte*)table + table->name.offs));
nextTableId = table->next;
return name;
}
dbTableDescriptor* createTable(char const* name, ClassDescriptor* clsDesc) {
beginTransaction(dbExclusiveLock);
dbTableDescriptor* tableDesc = NULL;
int rc = dbCLI::create_table(this, name, clsDesc->nColumns, clsDesc->columns);
if (rc == cli_unsupported_type) {
handleError(dbDatabase::DatabaseOpenError, "Unsupported table field type");
return NULL;
}
return findTableByName(name);
}
dbTableDescriptor* updateTable(char const* name, ClassDescriptor* clsDesc) {
beginTransaction(dbExclusiveLock);
int rc = dbCLI::alter_table(this, name, clsDesc->nColumns, clsDesc->columns);
if (rc == cli_unsupported_type) {
handleError(dbDatabase::DatabaseOpenError, "Unsupported table field type");
return NULL;
}
return findTableByName(name);
}
oid_t insert(dbTableDescriptor* desc, ObjectBuffer* buf) {
dbAnyReference ref;
char** ptr = (char**)buf->base();
insertRecord(desc, &ref, buf->base());
return ref.getOid();
}
JniResultSet* select(dbTableDescriptor* desc, char const* query) {
JniResultSet* rs = new JniResultSet(desc);
rs->cursor.select(query, dbCursorViewOnly, NULL);
return rs;
}
void update(oid_t oid, dbTableDescriptor* desc, ObjectBuffer* buf) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -