diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml index a8f65f4884..42efd391f7 100644 --- a/.github/workflows/ci-workflow.yml +++ b/.github/workflows/ci-workflow.yml @@ -34,6 +34,9 @@ jobs: - name: Node.js test run: CC=gcc CXX=g++ make nodejstest NUM_THREADS=32 + - name: Java test + run: CC=gcc CXX=g++ make javatest NUM_THREADS=32 + - name: Rust test run: CC=gcc CXX=g++ make rusttest NUM_THREADS=32 @@ -109,6 +112,9 @@ jobs: - name: Node.js test run: CC=clang-14 CXX=clang++-14 make nodejstest NUM_THREADS=32 + + - name: Java test + run: CC=clang-14 CXX=clang++-14 make javatest NUM_THREADS=32 msvc-build-test: name: msvc build & test diff --git a/.gitignore b/.gitignore index 500d622988..01c1f62d2c 100644 --- a/.gitignore +++ b/.gitignore @@ -41,21 +41,8 @@ scripts/pre-compiled-bins/lib* scripts/pre-compiled-bins/kuzu* # Java API -tools/java_api/CMakeFiles/ -tools/java_api/Testing/ -tools/java_api/testdb/ -tools/java_api/testdb/ -tools/java_api_falied/ -tools/test_java_api/ -tools/java_api/cmake_install.cmake -tools/java_api/Notes.txt -tools/java_api/CMakeCache.txt -tools/java_api/CTestTestfile.cmake -tools/java_api/*.log +tools/java_api/build +tools/java_api/test_db/ tools/java_api/*.jar -tools/java_api/*.dylib -tools/java_api/test.java tools/java_api/*.class -tools/java_api/KuzuNative.h -tools/java_api/error.txt -tools/java_api/Makefile \ No newline at end of file +tools/java_api/*.log diff --git a/CMakeLists.txt b/CMakeLists.txt index 639365e32e..6f32f79e98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,28 @@ set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) set(CMAKE_POSITION_INDEPENDENT_CODE ON) +# Detect OS and architecture, copied from DuckDB +set(OS_NAME "unknown") +set(OS_ARCH "amd64") + +string(REGEX MATCH "(arm64|aarch64)" IS_ARM "${CMAKE_SYSTEM_PROCESSOR}") +if(IS_ARM) + set(OS_ARCH "arm64") +elseif(FORCE_32_BIT) + set(OS_ARCH "i386") +endif() + +if(APPLE) + set(OS_NAME "osx") +endif() +if(WIN32) + set(OS_NAME "windows") +endif() +if(UNIX AND NOT APPLE) + set(OS_NAME "linux") # sorry BSD +endif() + + if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) endif() diff --git a/Makefile b/Makefile index be75b7ec57..d65bfb9106 100644 --- a/Makefile +++ b/Makefile @@ -94,6 +94,11 @@ nodejs: arrow cmake $(GENERATOR) $(FORCE_COLOR) $(SANITIZER_FLAG) -DCMAKE_BUILD_TYPE=Release -DBUILD_NODEJS=TRUE ../.. && \ cmake --build . --config Release -- -j $(NUM_THREADS) +java: + $(call mkdirp,build/release) && cd build/release && \ + cmake $(GENERATOR) $(FORCE_COLOR) $(SANITIZER_FLAG) -DCMAKE_BUILD_TYPE=Release -DBUILD_JAVA=TRUE ../.. && \ + cmake --build . --config Release -- -j $(NUM_THREADS) + test: arrow $(call mkdirp,build/release) && cd build/release && \ cmake $(GENERATOR) $(FORCE_COLOR) $(SANITIZER_FLAG) -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTS=TRUE ../.. && \ @@ -118,6 +123,19 @@ nodejstest: arrow cd $(ROOT_DIR)/tools/nodejs_api/ && \ npm test +javatest: arrow +ifeq ($(OS),Windows_NT) + $(MAKE) java + $(call mkdirp,tools/java_api/build/test) && cd tools/java_api/ && \ + javac -d build/test -cp ".;build/kuzu_java.jar;third_party/junit-platform-console-standalone-1.9.3.jar" -sourcepath src/test/java/com/kuzudb/test/*.java && \ + java -jar third_party/junit-platform-console-standalone-1.9.3.jar -cp ".;build/kuzu_java.jar;build/test/" --scan-classpath --include-package=com.kuzudb.java_test --details=verbose +else + $(MAKE) java + $(call mkdirp,tools/java_api/build/test) && cd tools/java_api/ && \ + javac -d build/test -cp ".:build/kuzu_java.jar:third_party/junit-platform-console-standalone-1.9.3.jar" -sourcepath src/test/java/com/kuzudb/test/*.java && \ + java -jar third_party/junit-platform-console-standalone-1.9.3.jar -cp ".:build/kuzu_java.jar:build/test/" --scan-classpath --include-package=com.kuzudb.java_test --details=verbose +endif + rusttest: ifeq ($(OS),Windows_NT) cd $(ROOT_DIR)/tools/rust_api && \ @@ -137,6 +155,13 @@ else rm -rf tools/python_api/build endif +clean-java: +ifeq ($(OS),Windows_NT) + if exist tools\java_api\build rmdir /s /q tools\java_api\build +else + rm -rf tools/java_api/build +endif + clean-external: ifeq ($(OS),Windows_NT) if exist external\build rmdir /s /q external\build @@ -144,7 +169,7 @@ else rm -rf external/build endif -clean: clean-python-api +clean: clean-python-api clean-java ifeq ($(OS),Windows_NT) if exist build rmdir /s /q build else diff --git a/scripts/dockerized-ci-tests-runner/Dockerfile b/scripts/dockerized-ci-tests-runner/Dockerfile index 1b21272ed0..bf978463da 100644 --- a/scripts/dockerized-ci-tests-runner/Dockerfile +++ b/scripts/dockerized-ci-tests-runner/Dockerfile @@ -4,8 +4,9 @@ ENV DEBIAN_FRONTEND=noninteractive # Install dependencies RUN apt-get update && apt-get install -y --no-install-recommends apt-utils curl ca-certificates apt-transport-https gnupg software-properties-common RUN curl -fsSL https://deb.nodesource.com/setup_20.x | bash - -RUN apt-get update && apt-get install -y g++ gcc clang-14 python3-dev python3-pip python-is-python3 cmake nodejs jq curl sudo git clang-format-11 lsb-release wget lcov libssl-dev libcurl4-openssl-dev rustfmt rustc cargo +RUN apt-get update && apt-get install -y g++ gcc clang-14 python3-dev python3-pip python-is-python3 cmake nodejs jq curl sudo git clang-format-11 lsb-release wget lcov libssl-dev libcurl4-openssl-dev rustfmt rustc cargo openjdk-17-jdk +ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64 RUN useradd --create-home runner USER runner diff --git a/third_party/antlr4_runtime/CMakeLists.txt b/third_party/antlr4_runtime/CMakeLists.txt index cab849c81b..8684bd167c 100644 --- a/third_party/antlr4_runtime/CMakeLists.txt +++ b/third_party/antlr4_runtime/CMakeLists.txt @@ -320,6 +320,7 @@ if (WIN32) -DANTLR4CPP_EXPORTS -DANTLR4CPP_STATIC ) + set_property(TARGET ${ANTLR4_RUNTIME} PROPERTY CXX_STANDARD 17) endif() diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index ce3775d142..24bff91b11 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -1,4 +1,7 @@ add_subdirectory(shell) +if(${BUILD_JAVA}) + add_subdirectory(java_api) +endif() if(${BUILD_NODEJS}) add_subdirectory(nodejs_api) endif() diff --git a/tools/java_api/CMakeLists.txt b/tools/java_api/CMakeLists.txt index 1d2a9df0e3..baa4ee51a9 100644 --- a/tools/java_api/CMakeLists.txt +++ b/tools/java_api/CMakeLists.txt @@ -12,47 +12,38 @@ find_package(JNI REQUIRED) if (JNI_FOUND) message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}") message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}") +else() + message (FATAL_ERROR "Java/JNI not found") endif() include(UseJava) -enable_testing() - -file(GLOB JAVA_SRC_FILES *.java) +file(GLOB JAVA_SRC_FILES src/main/java/com/kuzudb/*.java) set(CMAKE_JAVA_COMPILE_FLAGS -source 1.8 -target 1.8 -encoding utf-8) -add_jar(kuzu_java ${JAVA_SRC_FILES}) +add_jar(kuzu_java ${JAVA_SRC_FILES} + OUTPUT_DIR "${PROJECT_SOURCE_DIR}/build" + GENERATE_NATIVE_HEADERS kuzu_native_header) get_target_property(_jarFile kuzu_java JAR_FILE) get_target_property(_classDir kuzu_java CLASSDIR) set (_stubDir "${CMAKE_CURRENT_BINARY_DIR}") -add_custom_command( - OUTPUT KuzuNative.h - COMMAND ${Java_JAVAC_EXECUTABLE} - -h . - ${JAVA_SRC_FILES} -) - -# generate libfoo.jnilib -include_directories(${JNI_INCLUDE_DIRS} ${_classDir} ${_stubDir} ../../src/include) -include_directories(../../third_party/antlr4_cypher/include) -include_directories(../../third_party/antlr4_runtime/src) -include_directories(../../third_party/spdlog) -include_directories(../../third_party/nlohmann_json) -include_directories(../../third_party/pyparse) -include_directories(../../third_party/utf8proc/include) -include_directories(../../third_party/pybind11/include) -include_directories(../../third_party/re2/include) -include_directories(../../third_party/concurrentqueue) - -find_library(KUZU NAMES kuzu PATHS ../../build/release/src) - -add_library(kuzu_java_native MODULE kuzu_java.cpp KuzuNative.h) -set_target_properties(kuzu_java_native PROPERTIES SUFFIX ".dylib") -target_link_libraries(kuzu_java_native ${JNI_LIBRARIES} ${KUZU}) - -# add test to run JNIFoo -add_test(NAME Test - COMMAND ${Java_JAVA_EXECUTABLE} - -ea - -Djava.library.path=${CMAKE_CURRENT_BINARY_DIR} - -cp ${_jarFile} tools.java_api.test) \ No newline at end of file + +include_directories(${JNI_INCLUDE_DIRS} ${_classDir} ${_stubDir}) +add_library(kuzu_java_native SHARED src/jni/kuzu_java.cpp) +target_link_libraries(kuzu_java_native PRIVATE kuzu_native_header kuzu) + +string(JOIN "_" LIB_SUFFIX ".so" ${OS_NAME} ${OS_ARCH}) +set_target_properties(kuzu_java_native PROPERTIES SUFFIX ${LIB_SUFFIX}) +set_target_properties(kuzu_java_native PROPERTIES PREFIX "lib") +set_target_properties(kuzu_java_native + PROPERTIES + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build" + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build" + ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_SOURCE_DIR}/build") + +add_custom_command(OUTPUT dummy_jar_target + DEPENDS kuzu_java_native kuzu_java + COMMAND ${Java_JAR_EXECUTABLE} uf ${_jarFile} -C + $ $) + +add_custom_target(kuzu_java_api ALL DEPENDS dummy_jar_target) diff --git a/tools/java_api/README.md b/tools/java_api/README.md new file mode 100644 index 0000000000..29db23fa4e --- /dev/null +++ b/tools/java_api/README.md @@ -0,0 +1,24 @@ +# Kùzu Java API + +## Requirements +Java 11 or higher + +## Build + +``` +cd ../.. && make java NUM_THREADS=X +``` + +## Run test + +``` +cd ../.. && make javatest NUM_THREADS=X +``` + +## Run `test.java` example + +First, build the Java API as described above. Then, run the following command: + +``` +java -cp ".:build/kuzu_java.jar" test.java +``` diff --git a/tools/java_api/kuzu_java.cpp b/tools/java_api/kuzu_java.cpp deleted file mode 100644 index 5255423b6f..0000000000 --- a/tools/java_api/kuzu_java.cpp +++ /dev/null @@ -1,1210 +0,0 @@ -#include -#include -#include "KuzuNative.h" -#include "main/kuzu.h" -#include "binder/bound_statement_result.h" -#include "planner/logical_plan/logical_plan.h" -#include "common/exception.h" -#include "common/types/value.h" -#include "main/query_summary.h" -#include "json.hpp" - -using namespace kuzu::main; -using namespace kuzu::common; -using namespace kuzu::processor; - - -jobject createJavaObject (JNIEnv * env, void * memAddress, std::string classPath, std::string refFieldName) { - uint64_t address = reinterpret_cast(memAddress); - jlong ref = static_cast(address); - - jclass javaClass = env->FindClass(classPath.c_str()); - jobject newObject = env->AllocObject(javaClass); - jfieldID refID = env->GetFieldID(javaClass , refFieldName.c_str(), "J"); - env->SetLongField(newObject, refID, ref); - return newObject; -} - -Database* getDatabase (JNIEnv * env, jobject thisDB) { - jclass javaDBClass = env->GetObjectClass(thisDB); - jfieldID fieldID = env->GetFieldID(javaDBClass, "db_ref", "J"); - jlong fieldValue = env->GetLongField(thisDB, fieldID); - - uint64_t address = static_cast(fieldValue); - Database* db = reinterpret_cast(address); - return db; -} - -Connection* getConnection (JNIEnv * env, jobject thisConn) { - jclass javaConnClass = env->GetObjectClass(thisConn); - jfieldID fieldID = env->GetFieldID(javaConnClass, "conn_ref", "J"); - jlong fieldValue = env->GetLongField(thisConn, fieldID); - - uint64_t address = static_cast(fieldValue); - Connection* conn = reinterpret_cast(address); - return conn; -} - -PreparedStatement* getPreparedStatement(JNIEnv * env, jobject thisPS) { - jclass javaPSClass = env->GetObjectClass(thisPS); - jfieldID fieldID = env->GetFieldID(javaPSClass, "ps_ref", "J"); - jlong fieldValue = env->GetLongField(thisPS, fieldID); - - uint64_t address = static_cast(fieldValue); - PreparedStatement* ps = reinterpret_cast(address); - return ps; -} - - -QueryResult* getQueryResult(JNIEnv * env, jobject thisQR) { - jclass javaQRClass = env->GetObjectClass(thisQR); - jfieldID fieldID = env->GetFieldID(javaQRClass, "qr_ref", "J"); - jlong fieldValue = env->GetLongField(thisQR, fieldID); - - uint64_t address = static_cast(fieldValue); - QueryResult* qr = reinterpret_cast(address); - return qr; -} - - -FlatTuple* getFlatTuple(JNIEnv * env, jobject thisFT) { - jclass javaFTClass = env->GetObjectClass(thisFT); - jfieldID fieldID = env->GetFieldID(javaFTClass, "ft_ref", "J"); - jlong fieldValue = env->GetLongField(thisFT, fieldID); - - uint64_t address = static_cast(fieldValue); - auto ft = reinterpret_cast*>(address); - return ft->get(); -} - -DataType* getDataType (JNIEnv * env, jobject thisDT) { - jclass javaDTClass = env->GetObjectClass(thisDT); - jfieldID fieldID = env->GetFieldID(javaDTClass, "dt_ref", "J"); - jlong fieldValue = env->GetLongField(thisDT, fieldID); - - uint64_t address = static_cast(fieldValue); - DataType* dt = reinterpret_cast(address); - return dt; -} - -Value* getValue (JNIEnv * env, jobject thisValue) { - jclass javaValueClass = env->GetObjectClass(thisValue); - jfieldID fieldID = env->GetFieldID(javaValueClass, "v_ref", "J"); - jlong fieldValue = env->GetLongField(thisValue, fieldID); - - uint64_t address = static_cast(fieldValue); - Value* v = reinterpret_cast(address); - return v; -} - -NodeVal* getNodeVal (JNIEnv * env, jobject thisNodeVal) { - jclass javaValueClass = env->GetObjectClass(thisNodeVal); - jfieldID fieldID = env->GetFieldID(javaValueClass, "nv_ref", "J"); - jlong fieldValue = env->GetLongField(thisNodeVal, fieldID); - - uint64_t address = static_cast(fieldValue); - NodeVal* nv = reinterpret_cast(address); - return nv; -} - -RelVal* getRelVal (JNIEnv * env, jobject thisRelVal) { - jclass javaValueClass = env->GetObjectClass(thisRelVal); - jfieldID fieldID = env->GetFieldID(javaValueClass, "rv_ref", "J"); - jlong fieldValue = env->GetLongField(thisRelVal, fieldID); - - uint64_t address = static_cast(fieldValue); - RelVal* rv = reinterpret_cast(address); - return rv; -} - -internalID_t getInternalID (JNIEnv * env, jobject id) { - jclass javaIDClass = env->GetObjectClass(id); - jfieldID fieldID = env->GetFieldID(javaIDClass, "table_id", "J"); - long table_id = static_cast(env->GetLongField(id, fieldID)); - fieldID = env->GetFieldID(javaIDClass, "offset", "J"); - long offset = static_cast(env->GetLongField(id, fieldID)); - return internalID_t(offset, table_id); -} - -std::string dataTypeIDToString (uint8_t id) { - switch (id) - { - case DataTypeID::ANY: return "ANY"; - case DataTypeID::NODE: return "NODE"; - case DataTypeID::REL: return "REL"; - case DataTypeID::SERIAL: return "SERIAL"; - case DataTypeID::BOOL: return "BOOL"; - case DataTypeID::INT64: return "INT64"; - case DataTypeID::INT32: return "INT32"; - case DataTypeID::INT16: return "INT16"; - case DataTypeID::DOUBLE: return "DOUBLE"; - case DataTypeID::FLOAT: return "FLOAT"; - case DataTypeID::DATE: return "DATE"; - case DataTypeID::TIMESTAMP: return "TIMESTAMP"; - case DataTypeID::INTERVAL: return "INTERVAL"; - case DataTypeID::FIXED_LIST: return "FIXED_LIST"; - case DataTypeID::INTERNAL_ID: return "INTERNAL_ID"; - case DataTypeID::STRING: return "STRING"; - case DataTypeID::VAR_LIST: return "VAR_LIST"; - case DataTypeID::STRUCT: return "STRUCT"; - default: throw std::invalid_argument("Unimplemented item"); - } -} - -void javaMapToCPPMap (JNIEnv * env, jobject javaMap, std::unordered_map>& cppMap) { - - jclass mapClass = env->FindClass("java/util/Map"); - jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); - jobject set = env->CallObjectMethod(javaMap, entrySet); - jclass setClass = env->FindClass("java/util/Set"); - jmethodID iterator = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); - jobject iter = env->CallObjectMethod(set, iterator); - jclass iteratorClass = env->FindClass("java/util/Iterator"); - jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); - jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); - jclass entryClass = env->FindClass("java/util/Map$Entry"); - jmethodID entryGetKey = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); - jmethodID entryGetValue = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); - - while (env->CallBooleanMethod(iter, hasNext)) { - jobject entry = env->CallObjectMethod(iter, next); - jstring key = (jstring) env->CallObjectMethod(entry, entryGetKey); - jobject value = env->CallObjectMethod(entry, entryGetValue); - const char* keyStr = env->GetStringUTFChars(key, NULL); - Value* v = getValue(env, value); - std::shared_ptr value_ptr(v); - cppMap.insert({keyStr, value_ptr}); - - env->DeleteLocalRef(entry); - env->ReleaseStringUTFChars(key, keyStr); - env->DeleteLocalRef(key); - env->DeleteLocalRef(value); - } -} - -/** - * All Database native functions -*/ - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1database_1init - (JNIEnv * env, jclass, jstring database_path, jlong buffer_pool_size) { - - const char* path = env->GetStringUTFChars(database_path, JNI_FALSE); - uint64_t buffer = static_cast(buffer_pool_size); - try { - Database* db = buffer == 0 ? new Database(path) : - new Database(path, SystemConfig(buffer)); - uint64_t address = reinterpret_cast(db); - - env->ReleaseStringUTFChars(database_path, path); - return static_cast(address); - } catch (Exception& e) { - env->ReleaseStringUTFChars(database_path, path); - jclass Exception = env->FindClass("java/lang/Exception"); - env->ThrowNew(Exception, e.what()); - } -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1database_1destroy - (JNIEnv * env, jclass, jobject thisDB) { - Database* db = getDatabase(env, thisDB); - delete db; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1database_1set_1logging_1level - (JNIEnv * env, jclass, jstring logging_level) { - const char * lvl = env->GetStringUTFChars(logging_level, JNI_FALSE); - try{ - Database::setLoggingLevel(lvl); - env->ReleaseStringUTFChars(logging_level, lvl); - } catch (ConversionException e){ - env->ReleaseStringUTFChars(logging_level, lvl); - jclass Exception = env->FindClass("java/lang/Exception"); - env->ThrowNew(Exception,e.what()); - } -} - -/** - * All Connection native functions -*/ - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1init - (JNIEnv *env , jclass, jobject db) { - - try { - Database* conn_db = getDatabase(env, db); - - Connection* conn = new Connection(conn_db); - uint64_t connAddress = reinterpret_cast(conn); - - return static_cast(connAddress); - } catch (Exception& e) { - jclass Exception = env->FindClass("java/lang/Exception"); - env->ThrowNew(Exception, e.what()); - } -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1destroy - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - delete conn; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1begin_1read_1only_1transaction - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - conn->beginReadOnlyTransaction(); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1begin_1write_1transaction - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - conn->beginWriteTransaction(); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1commit - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - conn->commit(); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1rollback - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - conn->rollback(); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1set_1max_1num_1thread_1for_1exec - (JNIEnv * env, jclass, jobject thisConn, jlong num_threads) { - Connection* conn = getConnection(env, thisConn); - uint64_t threads = static_cast(num_threads); - conn->setMaxNumThreadForExec(threads); -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1get_1max_1num_1thread_1for_1exec - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - uint64_t threads = conn->getMaxNumThreadForExec(); - jlong num_threads = static_cast(threads); - return num_threads; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1query - (JNIEnv * env, jclass, jobject thisConn, jstring query) { - Connection* conn = getConnection(env, thisConn); - const char * CPPQuery = env->GetStringUTFChars(query, JNI_FALSE); - auto query_result = conn->query(CPPQuery).release(); - env->ReleaseStringUTFChars(query, CPPQuery); - - uint64_t qrAddress = reinterpret_cast(query_result); - jlong qr_ref = static_cast(qrAddress); - - jclass qrClass = env->FindClass("tools/java_api/KuzuQueryResult"); - jobject newQRObject = env->AllocObject(qrClass); - jfieldID refID = env->GetFieldID(qrClass , "qr_ref", "J"); - env->SetLongField(newQRObject, refID, qr_ref); - return newQRObject; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1prepare - (JNIEnv * env, jclass, jobject thisConn, jstring query) { - Connection* conn = getConnection(env, thisConn); - const char * cppquery = env->GetStringUTFChars(query, JNI_FALSE); - - PreparedStatement* prepared_statement = conn->prepare(cppquery).release(); - env->ReleaseStringUTFChars(query, cppquery); - if (prepared_statement == nullptr) { - return nullptr; - } - - jobject ret = createJavaObject(env, prepared_statement, "tools/java_api/KuzuPreparedStatement", "ps_ref"); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1execute - (JNIEnv * env, jclass, jobject thisConn, jobject preStm, jobject param_map) { - Connection* conn = getConnection(env, thisConn); - PreparedStatement* ps = getPreparedStatement(env, preStm); - - std::unordered_map> param; - javaMapToCPPMap(env, param_map, param); - - for (auto const &pair: param) { - std::cout << "{" << pair.first << ": " << pair.second.get()->toString() << "}\n"; - } - - auto query_result = conn->executeWithParams(ps, param).release(); - if (query_result == nullptr) { - return nullptr; - } - - jobject ret = createJavaObject(env, query_result, "tools/java_api/KuzuQueryResult", "qr_ref"); - return ret; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1get_1node_1table_1names - (JNIEnv * env , jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - jstring result = env->NewStringUTF(conn->getNodeTableNames().c_str()); - return result; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1get_1rel_1table_1names - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - jstring result = env->NewStringUTF(conn->getRelTableNames().c_str()); - return result; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1get_1node_1property_1names - (JNIEnv * env, jclass, jobject thisConn, jstring table_name) { - Connection* conn = getConnection(env, thisConn); - const char * name = env->GetStringUTFChars(table_name, JNI_FALSE); - jstring result = env->NewStringUTF(conn->getNodePropertyNames(name).c_str()); - env->ReleaseStringUTFChars(table_name, name); - return result; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1get_1rel_1property_1names - (JNIEnv * env, jclass, jobject thisConn, jstring table_name) { - Connection* conn = getConnection(env, thisConn); - const char * name = env->GetStringUTFChars(table_name, JNI_FALSE); - jstring result = env->NewStringUTF(conn->getRelPropertyNames(name).c_str()); - env->ReleaseStringUTFChars(table_name, name); - return result; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1interrupt - (JNIEnv * env, jclass, jobject thisConn) { - Connection* conn = getConnection(env, thisConn); - conn->interrupt(); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1connection_1set_1query_1timeout - (JNIEnv * env, jclass, jobject thisConn, jlong timeout_in_ms) { - Connection* conn = getConnection(env, thisConn); - uint64_t timeout = static_cast(timeout_in_ms); - conn->setQueryTimeOut(timeout); -} - -/** - * All PreparedStatement native functions -*/ - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1prepared_1statement_1destroy - (JNIEnv * env, jclass, jobject thisPS) { - PreparedStatement* ps = getPreparedStatement(env, thisPS); - delete ps; -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1prepared_1statement_1allow_1active_1transaction - (JNIEnv * env, jclass, jobject thisPS) { - PreparedStatement* ps = getPreparedStatement(env, thisPS); - return static_cast(ps->allowActiveTransaction()); -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1prepared_1statement_1is_1success - (JNIEnv * env, jclass, jobject thisPS) { - PreparedStatement* ps = getPreparedStatement(env, thisPS); - return static_cast(ps->isSuccess()); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1prepared_1statement_1get_1error_1message - (JNIEnv * env, jclass, jobject thisPS) { - PreparedStatement* ps = getPreparedStatement(env, thisPS); - std::string errorMessage = ps->getErrorMessage(); - jstring msg = env->NewStringUTF(errorMessage.c_str()); - return msg; -} - -/** - * All QueryResult native functions -*/ - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1destroy - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - delete qr; -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1is_1success - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - return static_cast(qr->isSuccess()); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1error_1message - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - std::string errorMessage = qr->getErrorMessage(); - jstring msg = env->NewStringUTF(errorMessage.c_str()); - return msg; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1num_1columns - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - return static_cast(qr->getNumColumns()); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1column_1name - (JNIEnv * env, jclass, jobject thisQR, jlong index) { - QueryResult* qr = getQueryResult(env, thisQR); - auto column_names = qr->getColumnNames(); - uint64_t idx = static_cast(index); - if (idx >= column_names.size()) { - return nullptr; - } - std::string column_name = column_names[idx]; - jstring name = env->NewStringUTF(column_name.c_str()); - return name; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1column_1data_1type - (JNIEnv * env, jclass, jobject thisQR, jlong index) { - QueryResult* qr = getQueryResult(env, thisQR); - auto column_datatypes = qr->getColumnDataTypes(); - uint64_t idx = static_cast(index); - if (idx >= column_datatypes.size()) { - return nullptr; - } - DataType column_datatype = column_datatypes[idx]; - DataType* cdt_copy = new DataType(column_datatype); - - uint64_t dtAddress = reinterpret_cast(cdt_copy); - jlong dt_ref = static_cast(dtAddress); - - jclass dtClass = env->FindClass("tools/java_api/KuzuDataType"); - jobject newDTObject = env->AllocObject(dtClass); - jfieldID refID = env->GetFieldID(dtClass , "dt_ref", "J"); - env->SetLongField(newDTObject, refID, dt_ref); - return newDTObject; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1num_1tuples - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - return static_cast(qr->getNumTuples()); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1query_1summary - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - auto query_summary = qr->getQuerySummary(); - - jdouble cmpTime = static_cast(query_summary->getCompilingTime()); - jdouble exeTime = static_cast(query_summary->getExecutionTime()); - - jclass qsClass = env->FindClass("tools/java_api/KuzuQuerySummary"); - jmethodID ctor = env->GetMethodID(qsClass, "", "(DD)V"); - jobject newQSObject = env->NewObject(qsClass, ctor, cmpTime, exeTime); - return newQSObject; -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1has_1next - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - return static_cast(qr->hasNext()); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1get_1next - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - auto flat_tuple = qr->getNext(); - - auto newFT = new std::shared_ptr(flat_tuple); - uint64_t ftAddress = reinterpret_cast(newFT); - jlong ft_ref = static_cast(ftAddress); - - jclass ftClass = env->FindClass("tools/java_api/KuzuFlatTuple"); - jobject newFTObject = env->AllocObject(ftClass); - jfieldID refID = env->GetFieldID(ftClass , "ft_ref", "J"); - env->SetLongField(newFTObject, refID, ft_ref); - return newFTObject; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1to_1string - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - std::string result_string = qr->toString(); - jstring ret = env->NewStringUTF(result_string.c_str()); - return ret; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1write_1to_1csv - (JNIEnv * env, jclass, jobject thisQR, jstring file_path, jchar delimiter, jchar escape_char, jchar new_line) { - QueryResult* qr = getQueryResult(env, thisQR); - const char * cpp_file_path = env->GetStringUTFChars(file_path, JNI_FALSE); - - // TODO: confirm this convertion is ok to do. - // jchar is 16-bit unicode character so converting to char will lose the higher oreder-bits - char cpp_delimiter = static_cast(delimiter); - char cpp_escape_char = static_cast(escape_char); - char cpp_new_line = static_cast(new_line); - - qr->writeToCSV(cpp_file_path, cpp_delimiter, cpp_escape_char, cpp_new_line); - env->ReleaseStringUTFChars(file_path, cpp_file_path); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1query_1result_1reset_1iterator - (JNIEnv * env, jclass, jobject thisQR) { - QueryResult* qr = getQueryResult(env, thisQR); - qr->resetIterator(); -} - -/** - * All FlatTuple native functions -*/ - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1flat_1tuple_1destroy - (JNIEnv * env, jclass, jobject thisFT) { - jclass javaFTClass = env->GetObjectClass(thisFT); - jfieldID fieldID = env->GetFieldID(javaFTClass, "ft_ref", "J"); - jlong fieldValue = env->GetLongField(thisFT, fieldID); - - uint64_t address = static_cast(fieldValue); - auto flat_tuple_shared_ptr = reinterpret_cast*>(address); - - flat_tuple_shared_ptr->reset(); - delete flat_tuple_shared_ptr; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1flat_1tuple_1get_1value - (JNIEnv * env, jclass, jobject thisFT, jlong index) { - FlatTuple* ft = getFlatTuple(env, thisFT); - uint32_t idx = static_cast(index); - Value* value; - try { - value = ft->getValue(index); - } catch (Exception& e) { return nullptr; } - - jobject v = createJavaObject(env, value, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(v); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(v, fieldID, static_cast(true)); - - return v; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1flat_1tuple_1to_1string - (JNIEnv * env, jclass, jobject thisFT) { - FlatTuple* ft = getFlatTuple(env, thisFT); - std::string result_string = ft->toString(); - jstring ret = env->NewStringUTF(result_string.c_str()); - return ret; -} - -/** - * All DataType native functions -*/ - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1create - (JNIEnv * env, jclass, jobject id, jobject child_type, jlong fixed_num_elements_in_list) { - jclass javaIDClass = env->GetObjectClass(id); - jfieldID fieldID = env->GetFieldID(javaIDClass, "value", "I"); - jint fieldValue = env->GetIntField(id, fieldID); - - uint8_t data_type_id_u8 = static_cast(fieldValue); - DataType* data_type; - if (child_type == nullptr) { - data_type = new DataType(static_cast(data_type_id_u8)); - } else { - auto child_type_pty = std::make_unique(*getDataType(env, child_type)); - uint64_t num = static_cast(fixed_num_elements_in_list); - data_type = num > 0 ? - new DataType(std::move(child_type_pty), num) : - new DataType(std::move(child_type_pty)); - } - uint64_t address = reinterpret_cast(data_type); - return static_cast(address); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1clone - (JNIEnv * env, jclass, jobject thisDT) { - DataType* oldDT = getDataType(env, thisDT); - DataType* newDT = new DataType(*oldDT); - - jobject dt = createJavaObject(env, newDT, "tools/java_api/KuzuDataType", "dt_ref"); - return dt; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1destroy - (JNIEnv * env, jclass, jobject thisDT) { - DataType* dt = getDataType(env, thisDT); - delete dt; -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1equals - (JNIEnv * env, jclass, jobject dt1, jobject dt2) { - DataType* cppdt1 = getDataType(env, dt1); - DataType* cppdt2 = getDataType(env, dt2); - - return static_cast(*cppdt1 == *cppdt2); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1get_1id - (JNIEnv * env, jclass, jobject thisDT) { - - DataType* dt = getDataType(env, thisDT); - uint8_t id_u8 = static_cast(dt->getTypeID()); - std::string id_str = dataTypeIDToString(id_u8); - jclass idClass = env->FindClass("tools/java_api/KuzuDataTypeID"); - jfieldID idField = env->GetStaticFieldID(idClass, id_str.c_str(), "Ltools/java_api/KuzuDataTypeID;"); - jobject id = env->GetStaticObjectField(idClass, idField); - return id; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1get_1child_1type - (JNIEnv * env, jclass, jobject thisDT) { - DataType* parent_type = getDataType(env, thisDT); - if (parent_type->getTypeID() != DataTypeID::FIXED_LIST && - parent_type->getTypeID() != DataTypeID::VAR_LIST) { - return nullptr; - } - DataType* child_type = parent_type->getChildType(); - if (child_type == nullptr) { - return nullptr; - } - - DataType* new_child_type = new DataType(*child_type); - jobject ret = createJavaObject(env, new_child_type, "tools/java_api/KuzuDataType", "dt_ref"); - return ret; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1data_1type_1get_1fixed_1num_1elements_1in_1list - (JNIEnv * env, jclass, jobject thisDT) { - DataType* dt = getDataType(env, thisDT); - if (dt->getTypeID() != DataTypeID::FIXED_LIST) { - return 0; - } - auto extra_info = dt->getExtraTypeInfo(); - if (extra_info == nullptr) { - return 0; - } - auto fixed_list_info = dynamic_cast(extra_info); - return static_cast(fixed_list_info->getFixedNumElementsInList()); -} - -/** - * All Value native functions -*/ - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1create_1null - (JNIEnv * env, jclass) { - Value* v = new Value(Value::createNullValue()); - jobject ret = createJavaObject(env, v, "tools/java_api/KuzuValue", "v_ref"); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1create_1null_1with_1data_1type - (JNIEnv * env, jclass, jobject data_type) { - DataType* dt = getDataType(env, data_type); - Value* v = new Value(Value::createNullValue(*dt)); - jobject ret = createJavaObject(env, v, "tools/java_api/KuzuValue", "v_ref"); - return ret; -} - -JNIEXPORT jboolean JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1is_1null - (JNIEnv * env, jclass, jobject thisV) { - Value* v = getValue(env, thisV); - return static_cast(v->isNull()); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1set_1null - (JNIEnv * env, jclass, jobject thisV, jboolean is_null) { - Value* v = getValue(env, thisV); - v->setNull(static_cast(is_null)); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1create_1default - (JNIEnv * env, jclass, jobject data_type) { - DataType* dt = getDataType(env, data_type); - Value* v = new Value(Value::createDefaultValue(*dt)); - jobject ret = createJavaObject(env, v, "tools/java_api/KuzuValue", "v_ref"); - return ret; -} - - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1create_1value - (JNIEnv * env, jclass, jobject val) { - Value* v; - jclass val_class = env->GetObjectClass(val); - if (env->IsInstanceOf(val, env->FindClass("java/lang/Boolean"))) { - jboolean value = env->CallBooleanMethod(val, env->GetMethodID(val_class, "booleanValue", "()Z")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Short"))) { - jshort value = env->CallShortMethod(val, env->GetMethodID(val_class, "shortValue", "()S")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Integer"))) { - jint value = env->CallIntMethod(val, env->GetMethodID(val_class, "intValue", "()I")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Long"))) { - jlong value = env->CallLongMethod(val, env->GetMethodID(val_class, "longValue", "()J")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Float"))) { - jfloat value = env->CallFloatMethod(val, env->GetMethodID(val_class, "floatValue", "()F")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Double"))) { - jdouble value = env->CallDoubleMethod(val, env->GetMethodID(val_class, "doubleValue", "()D")); - v = new Value(static_cast(value)); - } else if (env->IsInstanceOf(val, env->FindClass("java/lang/String"))) { - jstring value = static_cast(val); - const char * str = env->GetStringUTFChars(value, NULL); - v = new Value(str); - env->ReleaseStringUTFChars(value, str); - } else if (env->IsInstanceOf(val, env->FindClass("tools/java_api/KuzuInternalID"))) { - jfieldID fieldID = env->GetFieldID(val_class, "table_id", "J"); - long table_id = static_cast(env->GetLongField(val, fieldID)); - fieldID = env->GetFieldID(val_class, "offset", "J"); - long offset = static_cast(env->GetLongField(val, fieldID)); - internalID_t id(offset, table_id); - v = new Value(id); - } else if (env->IsInstanceOf(val, env->FindClass("tools/java_api/KuzuNodeValue"))) { - auto node_val = std::make_unique(*getNodeVal(env, val)); - v = new Value(std::move(node_val)); - } else if (env->IsInstanceOf(val, env->FindClass("tools/java_api/KuzuRelValue"))) { - auto rel_val = std::make_unique(*getRelVal(env, val)); - v = new Value(std::move(rel_val)); - } else if (env->IsInstanceOf(val, env->FindClass("java/time/LocalDate"))) { - jmethodID toEpochDay = env->GetMethodID(val_class, "toEpochDay", "()J"); - long days = static_cast(env->CallLongMethod(val, toEpochDay)); - v = new Value(date_t(days)); - } else if (env->IsInstanceOf(val, env->FindClass("java/time/Instant"))) { - // TODO: Need to review this for overflow - jmethodID getEpochSecond = env->GetMethodID(val_class, "getEpochSecond", "()J"); - jmethodID getNano = env->GetMethodID(val_class, "getNano", "()I"); - long seconds = static_cast(env->CallLongMethod(val, getEpochSecond)); - long nano = static_cast(env->CallLongMethod(val, getNano)); - - long micro = (seconds * 1000000L) + (nano / 1000L); - v = new Value(timestamp_t(micro)); - } else if (env->IsInstanceOf(val, env->FindClass("java/time/Duration"))) { - jmethodID toMillis = env->GetMethodID(val_class, "toMillis", "()J"); - long milis = static_cast(env->CallLongMethod(val, toMillis)); - v = new Value(interval_t(0, 0, milis * 1000L)); - } else { - // Throw exception here - return -1; - } - uint64_t address = reinterpret_cast(v); - return static_cast(address); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1clone - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - Value* copy = new Value(*v); - return createJavaObject(env, copy, "tools/java_api/KuzuValue", "v_ref"); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1copy - (JNIEnv * env, jclass, jobject thisValue, jobject otherValue) { - Value* thisV = getValue(env, thisValue); - Value* otherV = getValue(env, otherValue); - thisV->copyValueFrom(*otherV); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1destroy - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - delete v; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1get_1list_1size - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - return static_cast(v->getListValReference().size()); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1get_1list_1element - (JNIEnv * env, jclass, jobject thisValue, jlong index) { - Value* v = getValue(env, thisValue); - uint64_t idx = static_cast(index); - - auto& list_val = v->getListValReference(); - - if (idx >= list_val.size()) { - return nullptr; - } - - auto& list_element = list_val[index]; - auto val = list_element.get(); - - jobject element = createJavaObject(env, val, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(element); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(element, fieldID, static_cast(true)); - return element; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1get_1data_1type - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - DataType* dt = new DataType(v->getDataType()); - return createJavaObject(env, dt, "tools/java_api/KuzuDataType", "dt_ref"); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1get_1value - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - DataType dt = v->getDataType(); - - switch(dt.typeID) { - case DataTypeID::BOOL: - { - jclass retClass = env->FindClass("java/lang/Boolean"); - jmethodID ctor = env->GetMethodID(retClass, "", "(Z)V"); - jboolean val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::INT64: - { - jclass retClass = env->FindClass("java/lang/Long"); - jmethodID ctor = env->GetMethodID(retClass, "", "(J)V"); - jlong val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::INT32: - { - jclass retClass = env->FindClass("java/lang/Integer"); - jmethodID ctor = env->GetMethodID(retClass, "", "(I)V"); - jint val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::INT16: - { - jclass retClass = env->FindClass("java/lang/Short"); - jmethodID ctor = env->GetMethodID(retClass, "", "(S)V"); - jshort val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::DOUBLE: - { - jclass retClass = env->FindClass("java/lang/Double"); - jmethodID ctor = env->GetMethodID(retClass, "", "(D)V"); - jdouble val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::FLOAT: - { - jclass retClass = env->FindClass("java/lang/Float"); - jmethodID ctor = env->GetMethodID(retClass, "", "(F)V"); - jfloat val = static_cast(v->getValue()); - jobject ret = env->NewObject(retClass, ctor, val); - return ret; - } - case DataTypeID::DATE: - { - jclass retClass = env->FindClass("java/time/LocalDate"); - date_t date = v->getValue(); - jclass ldClass = env->FindClass("java/time/LocalDate"); - jmethodID ofEpochDay = env->GetStaticMethodID(ldClass, "ofEpochDay", "(J)Ljava/time/LocalDate;"); - jobject ret = env->CallStaticObjectMethod(ldClass, ofEpochDay, static_cast(date.days)); - return ret; - } - case DataTypeID::TIMESTAMP: - { - timestamp_t ts = v->getValue(); - int64_t seconds = ts.value / 1000000L; - int64_t nano = ts.value % 1000000L * 1000L; - jclass retClass = env->FindClass("java/time/Instant"); - jmethodID ofEpochSecond = env->GetStaticMethodID(retClass, "ofEpochSecond", "(JJ)Ljava/time/Instant;"); - jobject ret = env->CallStaticObjectMethod(retClass, ofEpochSecond, seconds, nano); - return ret; - } - case DataTypeID::INTERVAL: - { - jclass retClass = env->FindClass("java/time/Duration"); - jmethodID ofMillis = env->GetStaticMethodID(retClass, "ofMillis", "(J)Ljava/time/Duration;"); - interval_t in = v->getValue(); - long millis = Interval::getMicro(in) / 1000; - jobject ret = env->CallStaticObjectMethod(retClass, ofMillis, millis); - return ret; - } - case DataTypeID::INTERNAL_ID: - { - jclass retClass = env->FindClass("tools/java_api/KuzuInternalID"); - jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); - internalID_t iid = v->getValue(); - jobject ret = env->NewObject(retClass, ctor, iid.tableID, iid.offset); - return ret; - } - case DataTypeID::STRING: - { - std::string str = v->getValue(); - jstring ret = env->NewStringUTF(str.c_str()); - return ret; - } - case DataTypeID::NODE: - { - auto node_val = v->getValue(); - NodeVal* nv = new NodeVal(node_val); - return createJavaObject(env, nv, "tools/java_api/KuzuNodeValue", "nv_ref"); - } - case DataTypeID::REL: - { - auto rel_val = v->getValue(); - RelVal* nv = new RelVal(rel_val); - return createJavaObject(env, nv, "tools/java_api/KuzuRelValue", "rv_ref"); - } - default: - { - //Throw exception here? - return nullptr; - } - - return nullptr; - } -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1value_1to_1string - (JNIEnv * env, jclass, jobject thisValue) { - Value* v = getValue(env, thisValue); - std::string result_string = v->toString(); - jstring ret = env->NewStringUTF(result_string.c_str()); - return ret; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1create - (JNIEnv * env, jclass, jobject id, jstring label) { - jclass idClass = env->FindClass("tools/java_api/KuzuInternalID"); - jfieldID fieldID = env->GetFieldID(idClass, "table_id", "J"); - long table_id = static_cast(env->GetLongField(id, fieldID)); - fieldID = env->GetFieldID(idClass, "offset", "J"); - long offset = static_cast(env->GetLongField(id, fieldID)); - - auto id_val = std::make_unique(internalID_t(offset, table_id)); - const char * labelstr = env->GetStringUTFChars(label, JNI_FALSE); - auto label_val = std::make_unique(labelstr); - - NodeVal* node_val = new NodeVal(std::move(id_val), std::move(label_val)); - uint64_t address = reinterpret_cast(node_val); - env->ReleaseStringUTFChars(label, labelstr); - return static_cast(address); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1clone - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - NodeVal* newNV = new NodeVal(*nv); - return createJavaObject(env, newNV, "tools/java_api/KuzuNodeValue", "nv_ref"); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1destroy - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - delete nv; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1id_1val - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - auto idVal = nv->getNodeIDVal(); - - jobject ret = createJavaObject(env, idVal, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1label_1val - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - auto labelVal = nv->getNodeIDVal(); - - jobject ret = createJavaObject(env, labelVal, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1id - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - auto id = nv->getNodeID(); - - jclass retClass = env->FindClass("tools/java_api/KuzuInternalID"); - jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); - jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); - return ret; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1label_1name - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - return env->NewStringUTF(nv->getLabelName().c_str()); -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1property_1size - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - return static_cast(nv->getProperties().size()); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1property_1name_1at - (JNIEnv * env, jclass, jobject thisNV, jlong index) { - NodeVal* nv = getNodeVal(env, thisNV); - uint64_t idx = static_cast(index); - return env->NewStringUTF(nv->getProperties().at(idx).first.c_str()); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1get_1property_1value_1at - (JNIEnv * env, jclass, jobject thisNV, jlong index) { - NodeVal* nv = getNodeVal(env, thisNV); - uint64_t idx = static_cast(index); - Value* val = nv->getProperties().at(idx).second.get(); - - jobject ret = createJavaObject(env, val, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1add_1property - (JNIEnv * env, jclass, jobject thisNV, jstring key, jobject value) { - NodeVal* nv = getNodeVal(env, thisNV); - const char * k = env->GetStringUTFChars(key, JNI_FALSE); - auto v = std::make_unique(*getValue(env, value)); - nv->addProperty(k, std::move(v)); - env->ReleaseStringUTFChars(key, k); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1node_1val_1to_1string - (JNIEnv * env, jclass, jobject thisNV) { - NodeVal* nv = getNodeVal(env, thisNV); - std::string result_string = nv->toString(); - jstring ret = env->NewStringUTF(result_string.c_str()); - return ret; -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1create - (JNIEnv * env, jclass, jobject src_id, jobject dst_id, jstring label) { - internalID_t cpp_src_id = getInternalID(env, src_id); - internalID_t cpp_dst_id = getInternalID(env, dst_id); - auto src_id_val = std::make_unique(internalID_t(cpp_src_id.offset, cpp_src_id.tableID)); - auto dst_id_val = std::make_unique(internalID_t(cpp_dst_id.offset, cpp_dst_id.tableID)); - const char * lablestr = env->GetStringUTFChars(label, JNI_FALSE); - auto label_val = std::make_unique(lablestr); - RelVal* rv = new RelVal(std::move(src_id_val), std::move(dst_id_val), std::move(label_val)); - - uint64_t address = reinterpret_cast(rv); - env->ReleaseStringUTFChars(label, lablestr); - return static_cast(address); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1clone - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - RelVal* newRV = new RelVal(*rv); - return createJavaObject(env, newRV, "tools/java_api/KuzuRelValue", "rv_ref"); -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1destroy - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - delete rv; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1src_1id_1val - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - auto idVal = rv->getSrcNodeIDVal(); - - jobject ret = createJavaObject(env, idVal, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1dst_1id_1val - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - auto idVal = rv->getDstNodeIDVal(); - - jobject ret = createJavaObject(env, idVal, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1src_1id - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - internalID_t id = rv->getSrcNodeID(); - - jclass retClass = env->FindClass("tools/java_api/KuzuInternalID"); - jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); - jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); - return ret; -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1dst_1id - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - internalID_t id = rv->getDstNodeID(); - - jclass retClass = env->FindClass("tools/java_api/KuzuInternalID"); - jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); - jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); - return ret; -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1label_1name - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - return env->NewStringUTF(rv->getLabelName().c_str()); -} - -JNIEXPORT jlong JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1property_1size - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - return static_cast(rv->getProperties().size()); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1property_1name_1at - (JNIEnv * env, jclass, jobject thisRV, jlong index) { - RelVal* rv = getRelVal(env, thisRV); - auto& name = rv->getProperties().at(index).first; - return env->NewStringUTF(name.c_str()); -} - -JNIEXPORT jobject JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1get_1property_1value_1at - (JNIEnv * env, jclass, jobject thisRV, jlong index) { - RelVal* rv = getRelVal(env, thisRV); - uint64_t idx = static_cast(index); - Value* val = rv->getProperties().at(idx).second.get(); - - jobject ret = createJavaObject(env, val, "tools/java_api/KuzuValue", "v_ref"); - jclass clazz = env->GetObjectClass(ret); - jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); - env->SetBooleanField(ret, fieldID, static_cast(true)); - return ret; -} - -JNIEXPORT void JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1add_1property - (JNIEnv * env, jclass, jobject thisRV, jstring key, jobject value) { - RelVal* rv = getRelVal(env, thisRV); - const char * k = env->GetStringUTFChars(key, JNI_FALSE); - auto v = std::make_unique(*getValue(env, value)); - rv->addProperty(k, std::move(v)); - - env->ReleaseStringUTFChars(key, k); -} - -JNIEXPORT jstring JNICALL Java_tools_java_1api_KuzuNative_kuzu_1rel_1val_1to_1string - (JNIEnv * env, jclass, jobject thisRV) { - RelVal* rv = getRelVal(env, thisRV); - std::string result_string = rv->toString(); - jstring ret = env->NewStringUTF(result_string.c_str()); - return ret; -} diff --git a/tools/java_api/src/jni/kuzu_java.cpp b/tools/java_api/src/jni/kuzu_java.cpp new file mode 100644 index 0000000000..a90ce5b763 --- /dev/null +++ b/tools/java_api/src/jni/kuzu_java.cpp @@ -0,0 +1,1222 @@ +#include +#include + +#include "binder/bound_statement_result.h" +// This header is generated at build time. See CMakeLists.txt. +#include "com_kuzudb_KuzuNative.h" +#include "common/exception.h" +#include "common/types/types.h" +#include "common/types/value.h" +#include "json.hpp" +#include "main/kuzu.h" +#include "main/query_summary.h" +#include "planner/logical_plan/logical_plan.h" +#include + +using namespace kuzu::main; +using namespace kuzu::common; +using namespace kuzu::processor; + +jobject createJavaObject( + JNIEnv* env, void* memAddress, std::string classPath, std::string refFieldName) { + auto address = reinterpret_cast(memAddress); + auto ref = static_cast(address); + + jclass javaClass = env->FindClass(classPath.c_str()); + jobject newObject = env->AllocObject(javaClass); + jfieldID refID = env->GetFieldID(javaClass, refFieldName.c_str(), "J"); + env->SetLongField(newObject, refID, ref); + return newObject; +} + +Database* getDatabase(JNIEnv* env, jobject thisDB) { + jclass javaDBClass = env->GetObjectClass(thisDB); + jfieldID fieldID = env->GetFieldID(javaDBClass, "db_ref", "J"); + jlong fieldValue = env->GetLongField(thisDB, fieldID); + + uint64_t address = static_cast(fieldValue); + Database* db = reinterpret_cast(address); + return db; +} + +Connection* getConnection(JNIEnv* env, jobject thisConn) { + jclass javaConnClass = env->GetObjectClass(thisConn); + jfieldID fieldID = env->GetFieldID(javaConnClass, "conn_ref", "J"); + jlong fieldValue = env->GetLongField(thisConn, fieldID); + + uint64_t address = static_cast(fieldValue); + Connection* conn = reinterpret_cast(address); + return conn; +} + +PreparedStatement* getPreparedStatement(JNIEnv* env, jobject thisPS) { + jclass javaPSClass = env->GetObjectClass(thisPS); + jfieldID fieldID = env->GetFieldID(javaPSClass, "ps_ref", "J"); + jlong fieldValue = env->GetLongField(thisPS, fieldID); + + uint64_t address = static_cast(fieldValue); + PreparedStatement* ps = reinterpret_cast(address); + return ps; +} + +QueryResult* getQueryResult(JNIEnv* env, jobject thisQR) { + jclass javaQRClass = env->GetObjectClass(thisQR); + jfieldID fieldID = env->GetFieldID(javaQRClass, "qr_ref", "J"); + jlong fieldValue = env->GetLongField(thisQR, fieldID); + + uint64_t address = static_cast(fieldValue); + QueryResult* qr = reinterpret_cast(address); + return qr; +} + +FlatTuple* getFlatTuple(JNIEnv* env, jobject thisFT) { + jclass javaFTClass = env->GetObjectClass(thisFT); + jfieldID fieldID = env->GetFieldID(javaFTClass, "ft_ref", "J"); + jlong fieldValue = env->GetLongField(thisFT, fieldID); + + uint64_t address = static_cast(fieldValue); + auto ft = reinterpret_cast*>(address); + return ft->get(); +} + +LogicalType* getDataType(JNIEnv* env, jobject thisDT) { + jclass javaDTClass = env->GetObjectClass(thisDT); + jfieldID fieldID = env->GetFieldID(javaDTClass, "dt_ref", "J"); + jlong fieldValue = env->GetLongField(thisDT, fieldID); + + uint64_t address = static_cast(fieldValue); + auto* dt = reinterpret_cast(address); + return dt; +} + +Value* getValue(JNIEnv* env, jobject thisValue) { + jclass javaValueClass = env->GetObjectClass(thisValue); + jfieldID fieldID = env->GetFieldID(javaValueClass, "v_ref", "J"); + jlong fieldValue = env->GetLongField(thisValue, fieldID); + + uint64_t address = static_cast(fieldValue); + Value* v = reinterpret_cast(address); + return v; +} + +NodeVal* getNodeVal(JNIEnv* env, jobject thisNodeVal) { + jclass javaValueClass = env->GetObjectClass(thisNodeVal); + jfieldID fieldID = env->GetFieldID(javaValueClass, "nv_ref", "J"); + jlong fieldValue = env->GetLongField(thisNodeVal, fieldID); + + uint64_t address = static_cast(fieldValue); + NodeVal* nv = reinterpret_cast(address); + return nv; +} + +RelVal* getRelVal(JNIEnv* env, jobject thisRelVal) { + jclass javaValueClass = env->GetObjectClass(thisRelVal); + jfieldID fieldID = env->GetFieldID(javaValueClass, "rv_ref", "J"); + jlong fieldValue = env->GetLongField(thisRelVal, fieldID); + + uint64_t address = static_cast(fieldValue); + RelVal* rv = reinterpret_cast(address); + return rv; +} + +internalID_t getInternalID(JNIEnv* env, jobject id) { + jclass javaIDClass = env->GetObjectClass(id); + jfieldID fieldID = env->GetFieldID(javaIDClass, "table_id", "J"); + long table_id = static_cast(env->GetLongField(id, fieldID)); + fieldID = env->GetFieldID(javaIDClass, "offset", "J"); + long offset = static_cast(env->GetLongField(id, fieldID)); + return internalID_t(offset, table_id); +} + +std::string dataTypeToString(const LogicalType& dataType) { + switch (dataType.getLogicalTypeID()) { + case LogicalTypeID::ANY: + return "ANY"; + case LogicalTypeID::NODE: + return "NODE"; + case LogicalTypeID::REL: + return "REL"; + case LogicalTypeID::SERIAL: + return "SERIAL"; + case LogicalTypeID::BOOL: + return "BOOL"; + case LogicalTypeID::INT64: + return "INT64"; + case LogicalTypeID::INT32: + return "INT32"; + case LogicalTypeID::INT16: + return "INT16"; + case LogicalTypeID::DOUBLE: + return "DOUBLE"; + case LogicalTypeID::FLOAT: + return "FLOAT"; + case LogicalTypeID::DATE: + return "DATE"; + case LogicalTypeID::TIMESTAMP: + return "TIMESTAMP"; + case LogicalTypeID::INTERVAL: + return "INTERVAL"; + case LogicalTypeID::FIXED_LIST: + return "FIXED_LIST"; + case LogicalTypeID::INTERNAL_ID: + return "INTERNAL_ID"; + case LogicalTypeID::STRING: + return "STRING"; + case LogicalTypeID::VAR_LIST: + return "VAR_LIST"; + case LogicalTypeID::STRUCT: + return "STRUCT"; + default: + throw std::invalid_argument("Unimplemented item"); + } +} + +void javaMapToCPPMap( + JNIEnv* env, jobject javaMap, std::unordered_map>& cppMap) { + + jclass mapClass = env->FindClass("java/util/Map"); + jmethodID entrySet = env->GetMethodID(mapClass, "entrySet", "()Ljava/util/Set;"); + jobject set = env->CallObjectMethod(javaMap, entrySet); + jclass setClass = env->FindClass("java/util/Set"); + jmethodID iterator = env->GetMethodID(setClass, "iterator", "()Ljava/util/Iterator;"); + jobject iter = env->CallObjectMethod(set, iterator); + jclass iteratorClass = env->FindClass("java/util/Iterator"); + jmethodID hasNext = env->GetMethodID(iteratorClass, "hasNext", "()Z"); + jmethodID next = env->GetMethodID(iteratorClass, "next", "()Ljava/lang/Object;"); + jclass entryClass = env->FindClass("java/util/Map$Entry"); + jmethodID entryGetKey = env->GetMethodID(entryClass, "getKey", "()Ljava/lang/Object;"); + jmethodID entryGetValue = env->GetMethodID(entryClass, "getValue", "()Ljava/lang/Object;"); + + while (env->CallBooleanMethod(iter, hasNext)) { + jobject entry = env->CallObjectMethod(iter, next); + jstring key = (jstring)env->CallObjectMethod(entry, entryGetKey); + jobject value = env->CallObjectMethod(entry, entryGetValue); + const char* keyStr = env->GetStringUTFChars(key, NULL); + Value* v = getValue(env, value); + std::shared_ptr value_ptr(v); + cppMap.insert({keyStr, value_ptr}); + + env->DeleteLocalRef(entry); + env->ReleaseStringUTFChars(key, keyStr); + env->DeleteLocalRef(key); + env->DeleteLocalRef(value); + } +} + +/** + * All Database native functions + */ + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1database_1init( + JNIEnv* env, jclass, jstring database_path, jlong buffer_pool_size) { + + const char* path = env->GetStringUTFChars(database_path, JNI_FALSE); + uint64_t buffer = static_cast(buffer_pool_size); + try { + Database* db = buffer == 0 ? new Database(path) : new Database(path, SystemConfig(buffer)); + uint64_t address = reinterpret_cast(db); + + env->ReleaseStringUTFChars(database_path, path); + return static_cast(address); + } catch (Exception& e) { + env->ReleaseStringUTFChars(database_path, path); + jclass Exception = env->FindClass("java/lang/Exception"); + env->ThrowNew(Exception, e.what()); + } + return 0; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1database_1destroy( + JNIEnv* env, jclass, jobject thisDB) { + Database* db = getDatabase(env, thisDB); + delete db; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1database_1set_1logging_1level( + JNIEnv* env, jclass, jstring logging_level) { + const char* lvl = env->GetStringUTFChars(logging_level, JNI_FALSE); + try { + Database::setLoggingLevel(lvl); + env->ReleaseStringUTFChars(logging_level, lvl); + } catch (ConversionException e) { + env->ReleaseStringUTFChars(logging_level, lvl); + jclass Exception = env->FindClass("java/lang/Exception"); + env->ThrowNew(Exception, e.what()); + } +} + +/** + * All Connection native functions + */ + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1init( + JNIEnv* env, jclass, jobject db) { + + try { + Database* conn_db = getDatabase(env, db); + + Connection* conn = new Connection(conn_db); + uint64_t connAddress = reinterpret_cast(conn); + + return static_cast(connAddress); + } catch (Exception& e) { + jclass Exception = env->FindClass("java/lang/Exception"); + env->ThrowNew(Exception, e.what()); + } + return 0; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1destroy( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + delete conn; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1begin_1read_1only_1transaction( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + conn->beginReadOnlyTransaction(); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1begin_1write_1transaction( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + conn->beginWriteTransaction(); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1commit( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + conn->commit(); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1rollback( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + conn->rollback(); +} + +JNIEXPORT void JNICALL +Java_com_kuzudb_KuzuNative_kuzu_1connection_1set_1max_1num_1thread_1for_1exec( + JNIEnv* env, jclass, jobject thisConn, jlong num_threads) { + Connection* conn = getConnection(env, thisConn); + uint64_t threads = static_cast(num_threads); + conn->setMaxNumThreadForExec(threads); +} + +JNIEXPORT jlong JNICALL +Java_com_kuzudb_KuzuNative_kuzu_1connection_1get_1max_1num_1thread_1for_1exec( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + uint64_t threads = conn->getMaxNumThreadForExec(); + jlong num_threads = static_cast(threads); + return num_threads; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1query( + JNIEnv* env, jclass, jobject thisConn, jstring query) { + Connection* conn = getConnection(env, thisConn); + const char* CPPQuery = env->GetStringUTFChars(query, JNI_FALSE); + auto query_result = conn->query(CPPQuery).release(); + env->ReleaseStringUTFChars(query, CPPQuery); + + uint64_t qrAddress = reinterpret_cast(query_result); + jlong qr_ref = static_cast(qrAddress); + + jclass qrClass = env->FindClass("com/kuzudb/KuzuQueryResult"); + jobject newQRObject = env->AllocObject(qrClass); + jfieldID refID = env->GetFieldID(qrClass, "qr_ref", "J"); + env->SetLongField(newQRObject, refID, qr_ref); + return newQRObject; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1prepare( + JNIEnv* env, jclass, jobject thisConn, jstring query) { + Connection* conn = getConnection(env, thisConn); + const char* cppquery = env->GetStringUTFChars(query, JNI_FALSE); + + PreparedStatement* prepared_statement = conn->prepare(cppquery).release(); + env->ReleaseStringUTFChars(query, cppquery); + if (prepared_statement == nullptr) { + return nullptr; + } + + jobject ret = + createJavaObject(env, prepared_statement, "com/kuzudb/KuzuPreparedStatement", "ps_ref"); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1execute( + JNIEnv* env, jclass, jobject thisConn, jobject preStm, jobject param_map) { + Connection* conn = getConnection(env, thisConn); + PreparedStatement* ps = getPreparedStatement(env, preStm); + + std::unordered_map> param; + javaMapToCPPMap(env, param_map, param); + + for (auto const& pair : param) { + std::cout << "{" << pair.first << ": " << pair.second.get()->toString() << "}\n"; + } + + auto query_result = conn->executeWithParams(ps, param).release(); + if (query_result == nullptr) { + return nullptr; + } + + jobject ret = createJavaObject(env, query_result, "com/kuzudb/KuzuQueryResult", "qr_ref"); + return ret; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1get_1node_1table_1names( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + jstring result = env->NewStringUTF(conn->getNodeTableNames().c_str()); + return result; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1get_1rel_1table_1names( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + jstring result = env->NewStringUTF(conn->getRelTableNames().c_str()); + return result; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1get_1node_1property_1names( + JNIEnv* env, jclass, jobject thisConn, jstring table_name) { + Connection* conn = getConnection(env, thisConn); + const char* name = env->GetStringUTFChars(table_name, JNI_FALSE); + jstring result = env->NewStringUTF(conn->getNodePropertyNames(name).c_str()); + env->ReleaseStringUTFChars(table_name, name); + return result; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1get_1rel_1property_1names( + JNIEnv* env, jclass, jobject thisConn, jstring table_name) { + Connection* conn = getConnection(env, thisConn); + const char* name = env->GetStringUTFChars(table_name, JNI_FALSE); + jstring result = env->NewStringUTF(conn->getRelPropertyNames(name).c_str()); + env->ReleaseStringUTFChars(table_name, name); + return result; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1interrupt( + JNIEnv* env, jclass, jobject thisConn) { + Connection* conn = getConnection(env, thisConn); + conn->interrupt(); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1connection_1set_1query_1timeout( + JNIEnv* env, jclass, jobject thisConn, jlong timeout_in_ms) { + Connection* conn = getConnection(env, thisConn); + uint64_t timeout = static_cast(timeout_in_ms); + conn->setQueryTimeOut(timeout); +} + +/** + * All PreparedStatement native functions + */ + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1prepared_1statement_1destroy( + JNIEnv* env, jclass, jobject thisPS) { + PreparedStatement* ps = getPreparedStatement(env, thisPS); + delete ps; +} + +JNIEXPORT jboolean JNICALL +Java_com_kuzudb_KuzuNative_kuzu_1prepared_1statement_1allow_1active_1transaction( + JNIEnv* env, jclass, jobject thisPS) { + PreparedStatement* ps = getPreparedStatement(env, thisPS); + return static_cast(ps->allowActiveTransaction()); +} + +JNIEXPORT jboolean JNICALL Java_com_kuzudb_KuzuNative_kuzu_1prepared_1statement_1is_1success( + JNIEnv* env, jclass, jobject thisPS) { + PreparedStatement* ps = getPreparedStatement(env, thisPS); + return static_cast(ps->isSuccess()); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1prepared_1statement_1get_1error_1message( + JNIEnv* env, jclass, jobject thisPS) { + PreparedStatement* ps = getPreparedStatement(env, thisPS); + std::string errorMessage = ps->getErrorMessage(); + jstring msg = env->NewStringUTF(errorMessage.c_str()); + return msg; +} + +/** + * All QueryResult native functions + */ + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1destroy( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + delete qr; +} + +JNIEXPORT jboolean JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1is_1success( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + return static_cast(qr->isSuccess()); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1error_1message( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + std::string errorMessage = qr->getErrorMessage(); + jstring msg = env->NewStringUTF(errorMessage.c_str()); + return msg; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1num_1columns( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + return static_cast(qr->getNumColumns()); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1column_1name( + JNIEnv* env, jclass, jobject thisQR, jlong index) { + QueryResult* qr = getQueryResult(env, thisQR); + auto column_names = qr->getColumnNames(); + uint64_t idx = static_cast(index); + if (idx >= column_names.size()) { + return nullptr; + } + std::string column_name = column_names[idx]; + jstring name = env->NewStringUTF(column_name.c_str()); + return name; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1column_1data_1type( + JNIEnv* env, jclass, jobject thisQR, jlong index) { + QueryResult* qr = getQueryResult(env, thisQR); + auto column_datatypes = qr->getColumnDataTypes(); + uint64_t idx = static_cast(index); + if (idx >= column_datatypes.size()) { + return nullptr; + } + auto column_datatype = column_datatypes[idx]; + auto* cdt_copy = new LogicalType(column_datatype); + + uint64_t dtAddress = reinterpret_cast(cdt_copy); + jlong dt_ref = static_cast(dtAddress); + + jclass dtClass = env->FindClass("com/kuzudb/KuzuDataType"); + jobject newDTObject = env->AllocObject(dtClass); + jfieldID refID = env->GetFieldID(dtClass, "dt_ref", "J"); + env->SetLongField(newDTObject, refID, dt_ref); + return newDTObject; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1num_1tuples( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + return static_cast(qr->getNumTuples()); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1query_1summary( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + auto query_summary = qr->getQuerySummary(); + + jdouble cmpTime = static_cast(query_summary->getCompilingTime()); + jdouble exeTime = static_cast(query_summary->getExecutionTime()); + + jclass qsClass = env->FindClass("com/kuzudb/KuzuQuerySummary"); + jmethodID ctor = env->GetMethodID(qsClass, "", "(DD)V"); + jobject newQSObject = env->NewObject(qsClass, ctor, cmpTime, exeTime); + return newQSObject; +} + +JNIEXPORT jboolean JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1has_1next( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + return static_cast(qr->hasNext()); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1get_1next( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + auto flat_tuple = qr->getNext(); + + auto newFT = new std::shared_ptr(flat_tuple); + uint64_t ftAddress = reinterpret_cast(newFT); + jlong ft_ref = static_cast(ftAddress); + + jclass ftClass = env->FindClass("com/kuzudb/KuzuFlatTuple"); + jobject newFTObject = env->AllocObject(ftClass); + jfieldID refID = env->GetFieldID(ftClass, "ft_ref", "J"); + env->SetLongField(newFTObject, refID, ft_ref); + return newFTObject; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1to_1string( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + std::string result_string = qr->toString(); + jstring ret = env->NewStringUTF(result_string.c_str()); + return ret; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1write_1to_1csv(JNIEnv* env, + jclass, jobject thisQR, jstring file_path, jchar delimiter, jchar escape_char, jchar new_line) { + QueryResult* qr = getQueryResult(env, thisQR); + const char* cpp_file_path = env->GetStringUTFChars(file_path, JNI_FALSE); + + // TODO: confirm this convertion is ok to do. + // jchar is 16-bit unicode character so converting to char will lose the higher oreder-bits + char cpp_delimiter = static_cast(delimiter); + char cpp_escape_char = static_cast(escape_char); + char cpp_new_line = static_cast(new_line); + + qr->writeToCSV(cpp_file_path, cpp_delimiter, cpp_escape_char, cpp_new_line); + env->ReleaseStringUTFChars(file_path, cpp_file_path); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1query_1result_1reset_1iterator( + JNIEnv* env, jclass, jobject thisQR) { + QueryResult* qr = getQueryResult(env, thisQR); + qr->resetIterator(); +} + +/** + * All FlatTuple native functions + */ + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1flat_1tuple_1destroy( + JNIEnv* env, jclass, jobject thisFT) { + jclass javaFTClass = env->GetObjectClass(thisFT); + jfieldID fieldID = env->GetFieldID(javaFTClass, "ft_ref", "J"); + jlong fieldValue = env->GetLongField(thisFT, fieldID); + + uint64_t address = static_cast(fieldValue); + auto flat_tuple_shared_ptr = reinterpret_cast*>(address); + + flat_tuple_shared_ptr->reset(); + delete flat_tuple_shared_ptr; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1flat_1tuple_1get_1value( + JNIEnv* env, jclass, jobject thisFT, jlong index) { + FlatTuple* ft = getFlatTuple(env, thisFT); + uint32_t idx = static_cast(index); + Value* value; + try { + value = ft->getValue(index); + } catch (Exception& e) { return nullptr; } + + jobject v = createJavaObject(env, value, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(v); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(v, fieldID, static_cast(true)); + + return v; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1flat_1tuple_1to_1string( + JNIEnv* env, jclass, jobject thisFT) { + FlatTuple* ft = getFlatTuple(env, thisFT); + std::string result_string = ft->toString(); + jstring ret = env->NewStringUTF(result_string.c_str()); + return ret; +} + +/** + * All DataType native functions + */ + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1create( + JNIEnv* env, jclass, jobject id, jobject child_type, jlong fixed_num_elements_in_list) { + jclass javaIDClass = env->GetObjectClass(id); + jfieldID fieldID = env->GetFieldID(javaIDClass, "value", "I"); + jint fieldValue = env->GetIntField(id, fieldID); + + uint8_t data_type_id_u8 = static_cast(fieldValue); + LogicalType* data_type; + auto logicalTypeID = static_cast(data_type_id_u8); + if (child_type == nullptr) { + data_type = new LogicalType(logicalTypeID); + } else { + auto child_type_pty = std::make_unique(*getDataType(env, child_type)); + auto extraTypeInfo = fixed_num_elements_in_list > 0 ? + std::make_unique( + std::move(child_type_pty), fixed_num_elements_in_list) : + std::make_unique(std::move(child_type_pty)); + data_type = new LogicalType(logicalTypeID, std::move(extraTypeInfo)); + } + uint64_t address = reinterpret_cast(data_type); + return static_cast(address); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1clone( + JNIEnv* env, jclass, jobject thisDT) { + auto* oldDT = getDataType(env, thisDT); + auto* newDT = new LogicalType(*oldDT); + + jobject dt = createJavaObject(env, newDT, "com/kuzudb/KuzuDataType", "dt_ref"); + return dt; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1destroy( + JNIEnv* env, jclass, jobject thisDT) { + auto* dt = getDataType(env, thisDT); + delete dt; +} + +JNIEXPORT jboolean JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1equals( + JNIEnv* env, jclass, jobject dt1, jobject dt2) { + auto* cppdt1 = getDataType(env, dt1); + auto* cppdt2 = getDataType(env, dt2); + + return static_cast(*cppdt1 == *cppdt2); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1get_1id( + JNIEnv* env, jclass, jobject thisDT) { + + auto* dt = getDataType(env, thisDT); + std::string id_str = dataTypeToString(*dt); + jclass idClass = env->FindClass("com/kuzudb/KuzuDataTypeID"); + jfieldID idField = + env->GetStaticFieldID(idClass, id_str.c_str(), "Lcom/kuzudb/KuzuDataTypeID;"); + jobject id = env->GetStaticObjectField(idClass, idField); + return id; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1get_1child_1type( + JNIEnv* env, jclass, jobject thisDT) { + auto* parent_type = getDataType(env, thisDT); + LogicalType* child_type; + if (parent_type->getLogicalTypeID() == LogicalTypeID::FIXED_LIST) { + child_type = FixedListType::getChildType(parent_type); + } else if (parent_type->getLogicalTypeID() == LogicalTypeID::VAR_LIST) { + child_type = VarListType::getChildType(parent_type); + } else { + return nullptr; + } + auto* new_child_type = new LogicalType(*child_type); + jobject ret = createJavaObject(env, new_child_type, "com/kuzudb/KuzuDataType", "dt_ref"); + return ret; +} + +JNIEXPORT jlong JNICALL +Java_com_kuzudb_KuzuNative_kuzu_1data_1type_1get_1fixed_1num_1elements_1in_1list( + JNIEnv* env, jclass, jobject thisDT) { + auto* dt = getDataType(env, thisDT); + if (dt->getLogicalTypeID() != LogicalTypeID::FIXED_LIST) { + return 0; + } + return static_cast(FixedListType::getNumElementsInList(dt)); +} + +/** + * All Value native functions + */ + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1create_1null( + JNIEnv* env, jclass) { + Value* v = new Value(Value::createNullValue()); + jobject ret = createJavaObject(env, v, "com/kuzudb/KuzuValue", "v_ref"); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1create_1null_1with_1data_1type( + JNIEnv* env, jclass, jobject data_type) { + auto* dt = getDataType(env, data_type); + Value* v = new Value(Value::createNullValue(*dt)); + jobject ret = createJavaObject(env, v, "com/kuzudb/KuzuValue", "v_ref"); + return ret; +} + +JNIEXPORT jboolean JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1is_1null( + JNIEnv* env, jclass, jobject thisV) { + Value* v = getValue(env, thisV); + return static_cast(v->isNull()); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1set_1null( + JNIEnv* env, jclass, jobject thisV, jboolean is_null) { + Value* v = getValue(env, thisV); + v->setNull(static_cast(is_null)); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1create_1default( + JNIEnv* env, jclass, jobject data_type) { + auto* dt = getDataType(env, data_type); + Value* v = new Value(Value::createDefaultValue(*dt)); + jobject ret = createJavaObject(env, v, "com/kuzudb/KuzuValue", "v_ref"); + return ret; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1create_1value( + JNIEnv* env, jclass, jobject val) { + Value* v; + jclass val_class = env->GetObjectClass(val); + if (env->IsInstanceOf(val, env->FindClass("java/lang/Boolean"))) { + jboolean value = + env->CallBooleanMethod(val, env->GetMethodID(val_class, "booleanValue", "()Z")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Short"))) { + jshort value = env->CallShortMethod(val, env->GetMethodID(val_class, "shortValue", "()S")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Integer"))) { + jint value = env->CallIntMethod(val, env->GetMethodID(val_class, "intValue", "()I")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Long"))) { + jlong value = env->CallLongMethod(val, env->GetMethodID(val_class, "longValue", "()J")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Float"))) { + jfloat value = env->CallFloatMethod(val, env->GetMethodID(val_class, "floatValue", "()F")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/Double"))) { + jdouble value = + env->CallDoubleMethod(val, env->GetMethodID(val_class, "doubleValue", "()D")); + v = new Value(static_cast(value)); + } else if (env->IsInstanceOf(val, env->FindClass("java/lang/String"))) { + jstring value = static_cast(val); + const char* str = env->GetStringUTFChars(value, NULL); + v = new Value(str); + env->ReleaseStringUTFChars(value, str); + } else if (env->IsInstanceOf(val, env->FindClass("com/kuzudb/KuzuInternalID"))) { + jfieldID fieldID = env->GetFieldID(val_class, "table_id", "J"); + long table_id = static_cast(env->GetLongField(val, fieldID)); + fieldID = env->GetFieldID(val_class, "offset", "J"); + long offset = static_cast(env->GetLongField(val, fieldID)); + internalID_t id(offset, table_id); + v = new Value(id); + } else if (env->IsInstanceOf(val, env->FindClass("com/kuzudb/KuzuNodeValue"))) { + auto node_val = std::make_unique(*getNodeVal(env, val)); + v = new Value(std::move(node_val)); + } else if (env->IsInstanceOf(val, env->FindClass("com/kuzudb/KuzuRelValue"))) { + auto rel_val = std::make_unique(*getRelVal(env, val)); + v = new Value(std::move(rel_val)); + } else if (env->IsInstanceOf(val, env->FindClass("java/time/LocalDate"))) { + jmethodID toEpochDay = env->GetMethodID(val_class, "toEpochDay", "()J"); + long days = static_cast(env->CallLongMethod(val, toEpochDay)); + v = new Value(date_t(days)); + } else if (env->IsInstanceOf(val, env->FindClass("java/time/Instant"))) { + // TODO: Need to review this for overflow + jmethodID getEpochSecond = env->GetMethodID(val_class, "getEpochSecond", "()J"); + jmethodID getNano = env->GetMethodID(val_class, "getNano", "()I"); + long seconds = static_cast(env->CallLongMethod(val, getEpochSecond)); + long nano = static_cast(env->CallLongMethod(val, getNano)); + + long micro = (seconds * 1000000L) + (nano / 1000L); + v = new Value(timestamp_t(micro)); + } else if (env->IsInstanceOf(val, env->FindClass("java/time/Duration"))) { + jmethodID toMillis = env->GetMethodID(val_class, "toMillis", "()J"); + auto milis = env->CallLongMethod(val, toMillis); + v = new Value(interval_t(0, 0, milis * 1000L)); + } else { + // Throw exception here + return -1; + } + uint64_t address = reinterpret_cast(v); + return static_cast(address); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1clone( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + Value* copy = new Value(*v); + return createJavaObject(env, copy, "com/kuzudb/KuzuValue", "v_ref"); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1copy( + JNIEnv* env, jclass, jobject thisValue, jobject otherValue) { + Value* thisV = getValue(env, thisValue); + Value* otherV = getValue(env, otherValue); + thisV->copyValueFrom(*otherV); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1destroy( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + delete v; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1list_1size( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + return static_cast(v->getListValReference().size()); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1list_1element( + JNIEnv* env, jclass, jobject thisValue, jlong index) { + Value* v = getValue(env, thisValue); + uint64_t idx = static_cast(index); + + auto& list_val = v->getListValReference(); + + if (idx >= list_val.size()) { + return nullptr; + } + + auto& list_element = list_val[index]; + auto val = list_element.get(); + + jobject element = createJavaObject(env, val, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(element); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(element, fieldID, static_cast(true)); + return element; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1data_1type( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + auto* dt = new LogicalType(v->getDataType()); + return createJavaObject(env, dt, "com/kuzudb/KuzuDataType", "dt_ref"); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1get_1value( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + auto dt = v->getDataType(); + + switch (dt.getLogicalTypeID()) { + case LogicalTypeID::BOOL: { + jclass retClass = env->FindClass("java/lang/Boolean"); + jmethodID ctor = env->GetMethodID(retClass, "", "(Z)V"); + jboolean val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::INT64: { + jclass retClass = env->FindClass("java/lang/Long"); + jmethodID ctor = env->GetMethodID(retClass, "", "(J)V"); + jlong val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::INT32: { + jclass retClass = env->FindClass("java/lang/Integer"); + jmethodID ctor = env->GetMethodID(retClass, "", "(I)V"); + jint val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::INT16: { + jclass retClass = env->FindClass("java/lang/Short"); + jmethodID ctor = env->GetMethodID(retClass, "", "(S)V"); + jshort val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::DOUBLE: { + jclass retClass = env->FindClass("java/lang/Double"); + jmethodID ctor = env->GetMethodID(retClass, "", "(D)V"); + jdouble val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::FLOAT: { + jclass retClass = env->FindClass("java/lang/Float"); + jmethodID ctor = env->GetMethodID(retClass, "", "(F)V"); + jfloat val = static_cast(v->getValue()); + jobject ret = env->NewObject(retClass, ctor, val); + return ret; + } + case LogicalTypeID::DATE: { + jclass retClass = env->FindClass("java/time/LocalDate"); + date_t date = v->getValue(); + jclass ldClass = env->FindClass("java/time/LocalDate"); + jmethodID ofEpochDay = + env->GetStaticMethodID(ldClass, "ofEpochDay", "(J)Ljava/time/LocalDate;"); + jobject ret = + env->CallStaticObjectMethod(ldClass, ofEpochDay, static_cast(date.days)); + return ret; + } + case LogicalTypeID::TIMESTAMP: { + timestamp_t ts = v->getValue(); + int64_t seconds = ts.value / 1000000L; + int64_t nano = ts.value % 1000000L * 1000L; + jclass retClass = env->FindClass("java/time/Instant"); + jmethodID ofEpochSecond = + env->GetStaticMethodID(retClass, "ofEpochSecond", "(JJ)Ljava/time/Instant;"); + jobject ret = env->CallStaticObjectMethod(retClass, ofEpochSecond, seconds, nano); + return ret; + } + case LogicalTypeID::INTERVAL: { + jclass retClass = env->FindClass("java/time/Duration"); + jmethodID ofMillis = + env->GetStaticMethodID(retClass, "ofMillis", "(J)Ljava/time/Duration;"); + interval_t in = v->getValue(); + long millis = Interval::getMicro(in) / 1000; + jobject ret = env->CallStaticObjectMethod(retClass, ofMillis, millis); + return ret; + } + case LogicalTypeID::INTERNAL_ID: { + jclass retClass = env->FindClass("com/kuzudb/KuzuInternalID"); + jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); + internalID_t iid = v->getValue(); + jobject ret = env->NewObject(retClass, ctor, iid.tableID, iid.offset); + return ret; + } + case LogicalTypeID::STRING: { + std::string str = v->getValue(); + jstring ret = env->NewStringUTF(str.c_str()); + return ret; + } + case LogicalTypeID::NODE: { + auto node_val = v->getValue(); + NodeVal* nv = new NodeVal(node_val); + return createJavaObject(env, nv, "com/kuzudb/KuzuNodeValue", "nv_ref"); + } + case LogicalTypeID::REL: { + auto rel_val = v->getValue(); + RelVal* nv = new RelVal(rel_val); + return createJavaObject(env, nv, "com/kuzudb/KuzuRelValue", "rv_ref"); + } + default: { + // Throw exception here? + return nullptr; + } + } +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1value_1to_1string( + JNIEnv* env, jclass, jobject thisValue) { + Value* v = getValue(env, thisValue); + std::string result_string = v->toString(); + jstring ret = env->NewStringUTF(result_string.c_str()); + return ret; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1create( + JNIEnv* env, jclass, jobject id, jstring label) { + jclass idClass = env->FindClass("com/kuzudb/KuzuInternalID"); + jfieldID fieldID = env->GetFieldID(idClass, "table_id", "J"); + long table_id = static_cast(env->GetLongField(id, fieldID)); + fieldID = env->GetFieldID(idClass, "offset", "J"); + long offset = static_cast(env->GetLongField(id, fieldID)); + + auto id_val = std::make_unique(internalID_t(offset, table_id)); + const char* labelstr = env->GetStringUTFChars(label, JNI_FALSE); + auto label_val = std::make_unique(labelstr); + + NodeVal* node_val = new NodeVal(std::move(id_val), std::move(label_val)); + uint64_t address = reinterpret_cast(node_val); + env->ReleaseStringUTFChars(label, labelstr); + return static_cast(address); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1clone( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + NodeVal* newNV = new NodeVal(*nv); + return createJavaObject(env, newNV, "com/kuzudb/KuzuNodeValue", "nv_ref"); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1destroy( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + delete nv; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1id_1val( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + auto idVal = nv->getNodeIDVal(); + + jobject ret = createJavaObject(env, idVal, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1label_1val( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + auto labelVal = nv->getNodeIDVal(); + + jobject ret = createJavaObject(env, labelVal, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1id( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + auto id = nv->getNodeID(); + + jclass retClass = env->FindClass("com/kuzudb/KuzuInternalID"); + jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); + jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); + return ret; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1label_1name( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + return env->NewStringUTF(nv->getLabelName().c_str()); +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1property_1size( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + return static_cast(nv->getProperties().size()); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1property_1name_1at( + JNIEnv* env, jclass, jobject thisNV, jlong index) { + NodeVal* nv = getNodeVal(env, thisNV); + uint64_t idx = static_cast(index); + return env->NewStringUTF(nv->getProperties().at(idx).first.c_str()); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1get_1property_1value_1at( + JNIEnv* env, jclass, jobject thisNV, jlong index) { + NodeVal* nv = getNodeVal(env, thisNV); + uint64_t idx = static_cast(index); + Value* val = nv->getProperties().at(idx).second.get(); + + jobject ret = createJavaObject(env, val, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1add_1property( + JNIEnv* env, jclass, jobject thisNV, jstring key, jobject value) { + NodeVal* nv = getNodeVal(env, thisNV); + const char* k = env->GetStringUTFChars(key, JNI_FALSE); + auto v = std::make_unique(*getValue(env, value)); + nv->addProperty(k, std::move(v)); + env->ReleaseStringUTFChars(key, k); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1node_1val_1to_1string( + JNIEnv* env, jclass, jobject thisNV) { + NodeVal* nv = getNodeVal(env, thisNV); + std::string result_string = nv->toString(); + jstring ret = env->NewStringUTF(result_string.c_str()); + return ret; +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1create( + JNIEnv* env, jclass, jobject src_id, jobject dst_id, jstring label) { + internalID_t cpp_src_id = getInternalID(env, src_id); + internalID_t cpp_dst_id = getInternalID(env, dst_id); + auto src_id_val = std::make_unique(internalID_t(cpp_src_id.offset, cpp_src_id.tableID)); + auto dst_id_val = std::make_unique(internalID_t(cpp_dst_id.offset, cpp_dst_id.tableID)); + const char* lablestr = env->GetStringUTFChars(label, JNI_FALSE); + auto label_val = std::make_unique(lablestr); + RelVal* rv = new RelVal(std::move(src_id_val), std::move(dst_id_val), std::move(label_val)); + + uint64_t address = reinterpret_cast(rv); + env->ReleaseStringUTFChars(label, lablestr); + return static_cast(address); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1clone( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + RelVal* newRV = new RelVal(*rv); + return createJavaObject(env, newRV, "com/kuzudb/KuzuRelValue", "rv_ref"); +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1destroy( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + delete rv; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1src_1id_1val( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + auto idVal = rv->getSrcNodeIDVal(); + + jobject ret = createJavaObject(env, idVal, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1dst_1id_1val( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + auto idVal = rv->getDstNodeIDVal(); + + jobject ret = createJavaObject(env, idVal, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1src_1id( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + internalID_t id = rv->getSrcNodeID(); + + jclass retClass = env->FindClass("com/kuzudb/KuzuInternalID"); + jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); + jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); + return ret; +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1dst_1id( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + internalID_t id = rv->getDstNodeID(); + + jclass retClass = env->FindClass("com/kuzudb/KuzuInternalID"); + jmethodID ctor = env->GetMethodID(retClass, "", "(JJ)V"); + jobject ret = env->NewObject(retClass, ctor, id.tableID, id.offset); + return ret; +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1label_1name( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + return env->NewStringUTF(rv->getLabelName().c_str()); +} + +JNIEXPORT jlong JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1property_1size( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + return static_cast(rv->getProperties().size()); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1property_1name_1at( + JNIEnv* env, jclass, jobject thisRV, jlong index) { + RelVal* rv = getRelVal(env, thisRV); + auto& name = rv->getProperties().at(index).first; + return env->NewStringUTF(name.c_str()); +} + +JNIEXPORT jobject JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1get_1property_1value_1at( + JNIEnv* env, jclass, jobject thisRV, jlong index) { + RelVal* rv = getRelVal(env, thisRV); + uint64_t idx = static_cast(index); + Value* val = rv->getProperties().at(idx).second.get(); + + jobject ret = createJavaObject(env, val, "com/kuzudb/KuzuValue", "v_ref"); + jclass clazz = env->GetObjectClass(ret); + jfieldID fieldID = env->GetFieldID(clazz, "isOwnedByCPP", "Z"); + env->SetBooleanField(ret, fieldID, static_cast(true)); + return ret; +} + +JNIEXPORT void JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1add_1property( + JNIEnv* env, jclass, jobject thisRV, jstring key, jobject value) { + RelVal* rv = getRelVal(env, thisRV); + const char* k = env->GetStringUTFChars(key, JNI_FALSE); + auto v = std::make_unique(*getValue(env, value)); + rv->addProperty(k, std::move(v)); + + env->ReleaseStringUTFChars(key, k); +} + +JNIEXPORT jstring JNICALL Java_com_kuzudb_KuzuNative_kuzu_1rel_1val_1to_1string( + JNIEnv* env, jclass, jobject thisRV) { + RelVal* rv = getRelVal(env, thisRV); + std::string result_string = rv->toString(); + jstring ret = env->NewStringUTF(result_string.c_str()); + return ret; +} diff --git a/tools/java_api/KuzuConnection.java b/tools/java_api/src/main/java/com/kuzudb/KuzuConnection.java similarity index 70% rename from tools/java_api/KuzuConnection.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuConnection.java index 2ced41ac65..37ccadb647 100644 --- a/tools/java_api/KuzuConnection.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuConnection.java @@ -1,4 +1,5 @@ -package tools.java_api; +package com.kuzudb; + import java.util.Map; public class KuzuConnection { @@ -6,20 +7,20 @@ public class KuzuConnection { long conn_ref; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuConnection(KuzuDatabase db) { + assert db != null : "Cannot create connection, database is null."; + conn_ref = KuzuNative.kuzu_connection_init(db); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuConnection has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } - - public KuzuConnection(KuzuDatabase db) { - assert db != null: "Cannot create connection, database is null."; - conn_ref = KuzuNative.kuzu_connection_init(db); - } + destroy(); + } public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); @@ -47,57 +48,57 @@ public void rollback() throws KuzuObjectRefDestroyedException { KuzuNative.kuzu_connection_rollback(this); } - public void setMaxNumThreadForExec(long num_threads) throws KuzuObjectRefDestroyedException { + public long getMaxNumThreadForExec() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); - KuzuNative.kuzu_connection_set_max_num_thread_for_exec(this, num_threads); + return KuzuNative.kuzu_connection_get_max_num_thread_for_exec(this); } - public long getMaxNumThreadForExec () throws KuzuObjectRefDestroyedException { + public void setMaxNumThreadForExec(long num_threads) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); - return KuzuNative.kuzu_connection_get_max_num_thread_for_exec(this); + KuzuNative.kuzu_connection_set_max_num_thread_for_exec(this, num_threads); } - public KuzuQueryResult query (String queryStr) throws KuzuObjectRefDestroyedException { + public KuzuQueryResult query(String queryStr) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_query(this, queryStr); } - public KuzuPreparedStatement prepare (String queryStr) throws KuzuObjectRefDestroyedException { + public KuzuPreparedStatement prepare(String queryStr) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_prepare(this, queryStr); } - public KuzuQueryResult execute (KuzuPreparedStatement ps, Map m) throws KuzuObjectRefDestroyedException { + public KuzuQueryResult execute(KuzuPreparedStatement ps, Map m) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_execute(this, ps, m); } - public String getNodeTableNames () throws KuzuObjectRefDestroyedException { + public String getNodeTableNames() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_get_node_table_names(this); } - public String getRelTableNames () throws KuzuObjectRefDestroyedException { + public String getRelTableNames() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_get_rel_table_names(this); } - public String getNodePropertyNames (String table_name) throws KuzuObjectRefDestroyedException { + public String getNodePropertyNames(String table_name) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_get_node_property_names(this, table_name); } - public String getRelPropertyNames (String table_name) throws KuzuObjectRefDestroyedException { + public String getRelPropertyNames(String table_name) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_connection_get_rel_property_names(this, table_name); } - public void interrupt () throws KuzuObjectRefDestroyedException { + public void interrupt() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_connection_interrupt(this); } - public void setQueryTimeout (long timeout_in_ms) throws KuzuObjectRefDestroyedException { + public void setQueryTimeout(long timeout_in_ms) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_connection_set_query_timeout(this, timeout_in_ms); } diff --git a/tools/java_api/KuzuDataType.java b/tools/java_api/src/main/java/com/kuzudb/KuzuDataType.java similarity index 64% rename from tools/java_api/KuzuDataType.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuDataType.java index d7846e7755..46a4d74cd2 100644 --- a/tools/java_api/KuzuDataType.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuDataType.java @@ -1,18 +1,27 @@ -package tools.java_api; +package com.kuzudb; public class KuzuDataType { long dt_ref; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuDataType(KuzuDataTypeID id) { + dt_ref = KuzuNative.kuzu_data_type_create(id, null, 0); + } + + public KuzuDataType + (KuzuDataTypeID id, KuzuDataType child_type, long fixed_num_elements_in_list) { + dt_ref = KuzuNative.kuzu_data_type_create(id, child_type, fixed_num_elements_in_list); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuDatabase has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { destroy(); - } + } public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); @@ -20,38 +29,29 @@ public void destroy() throws KuzuObjectRefDestroyedException { destroyed = true; } - public KuzuDataType (KuzuDataTypeID id) { - dt_ref = KuzuNative.kuzu_data_type_create(id, null, 0); - } - - public KuzuDataType - (KuzuDataTypeID id, KuzuDataType child_type, long fixed_num_elements_in_list) { - dt_ref = KuzuNative.kuzu_data_type_create(id, child_type, fixed_num_elements_in_list); - } - public KuzuDataType clone() { - if(destroyed) + if (destroyed) return null; else return KuzuNative.kuzu_data_type_clone(this); } - public boolean equals (KuzuDataType other) throws KuzuObjectRefDestroyedException { + public boolean equals(KuzuDataType other) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_data_type_equals(this, other); } - public KuzuDataTypeID getID () throws KuzuObjectRefDestroyedException { + public KuzuDataTypeID getID() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_data_type_get_id(this); } - public KuzuDataType getChildType () throws KuzuObjectRefDestroyedException { + public KuzuDataType getChildType() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_data_type_get_child_type(this); } - public long getFixedNumElementsInList () throws KuzuObjectRefDestroyedException { + public long getFixedNumElementsInList() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_data_type_get_fixed_num_elements_in_list(this); } diff --git a/tools/java_api/KuzuDataTypeID.java b/tools/java_api/src/main/java/com/kuzudb/KuzuDataTypeID.java similarity index 94% rename from tools/java_api/KuzuDataTypeID.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuDataTypeID.java index b7b7bebea0..3d12454439 100644 --- a/tools/java_api/KuzuDataTypeID.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuDataTypeID.java @@ -1,4 +1,4 @@ -package tools.java_api; +package com.kuzudb; public enum KuzuDataTypeID { ANY(0), diff --git a/tools/java_api/KuzuDatabase.java b/tools/java_api/src/main/java/com/kuzudb/KuzuDatabase.java similarity index 78% rename from tools/java_api/KuzuDatabase.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuDatabase.java index 29b7a32fd3..7868be163f 100644 --- a/tools/java_api/KuzuDatabase.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuDatabase.java @@ -1,4 +1,4 @@ -package tools.java_api; +package com.kuzudb; public class KuzuDatabase { @@ -7,20 +7,24 @@ public class KuzuDatabase { long buffer_size; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuDatabase(String database_path, long buffer_pool_size) { + this.db_path = database_path; + this.buffer_size = buffer_pool_size; + db_ref = KuzuNative.kuzu_database_init(database_path, buffer_pool_size); + } + + public static void setLoggingLevel(String logging_level) { + KuzuNative.kuzu_database_set_logging_level(logging_level); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuDatabase has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } - - public KuzuDatabase (String database_path, long buffer_pool_size) { - this.db_path = database_path; - this.buffer_size = buffer_pool_size; - db_ref = KuzuNative.kuzu_database_init(database_path, buffer_pool_size); + destroy(); } public void destroy() throws KuzuObjectRefDestroyedException { @@ -28,8 +32,4 @@ public void destroy() throws KuzuObjectRefDestroyedException { KuzuNative.kuzu_database_destroy(this); destroyed = true; } - - public static void setLoggingLevel(String logging_level) { - KuzuNative.kuzu_database_set_logging_level(logging_level); - } } diff --git a/tools/java_api/KuzuFlatTuple.java b/tools/java_api/src/main/java/com/kuzudb/KuzuFlatTuple.java similarity index 66% rename from tools/java_api/KuzuFlatTuple.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuFlatTuple.java index 247e743d99..7f68ed5633 100644 --- a/tools/java_api/KuzuFlatTuple.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuFlatTuple.java @@ -1,31 +1,31 @@ -package tools.java_api; +package com.kuzudb; public class KuzuFlatTuple { long ft_ref; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuFlatTuple has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } + destroy(); + } - public void destroy () throws KuzuObjectRefDestroyedException { + public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_flat_tuple_destroy(this); destroyed = true; } - public KuzuValue getValue (long index) throws KuzuObjectRefDestroyedException { + public KuzuValue getValue(long index) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_flat_tuple_get_value(this, index); } - public String toString () { + public String toString() { if (destroyed) return "KuzuFlatTuple has been destroyed."; else diff --git a/tools/java_api/KuzuInternalID.java b/tools/java_api/src/main/java/com/kuzudb/KuzuInternalID.java similarity index 65% rename from tools/java_api/KuzuInternalID.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuInternalID.java index 33841943ce..4b3c32281c 100644 --- a/tools/java_api/KuzuInternalID.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuInternalID.java @@ -1,10 +1,10 @@ -package tools.java_api; +package com.kuzudb; public class KuzuInternalID { public long table_id; public long offset; - public KuzuInternalID (long table_id, long offset) { + public KuzuInternalID(long table_id, long offset) { this.table_id = table_id; this.offset = offset; } diff --git a/tools/java_api/KuzuNative.java b/tools/java_api/src/main/java/com/kuzudb/KuzuNative.java similarity index 72% rename from tools/java_api/KuzuNative.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuNative.java index 11a9043264..bd3205ecb5 100644 --- a/tools/java_api/KuzuNative.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuNative.java @@ -1,94 +1,194 @@ -package tools.java_api; +package com.kuzudb; import java.util.Map; +import java.io.File; +import java.io.IOException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.sql.SQLException; +import java.util.Properties; + public class KuzuNative { static { - System.loadLibrary("kuzu_java_native"); + try { + String os_name = ""; + String os_arch; + String os_name_detect = System.getProperty("os.name").toLowerCase().trim(); + String os_arch_detect = System.getProperty("os.arch").toLowerCase().trim(); + switch (os_arch_detect) { + case "x86_64": + case "amd64": + os_arch = "amd64"; + break; + case "aarch64": + case "arm64": + os_arch = "arm64"; + break; + case "i386": + os_arch = "i386"; + break; + default: + throw new IllegalStateException("Unsupported system architecture"); + } + if (os_name_detect.startsWith("windows")) { + os_name = "windows"; + } else if (os_name_detect.startsWith("mac")) { + os_name = "osx"; + } else if (os_name_detect.startsWith("linux")) { + os_name = "linux"; + } + String lib_res_name = "/libkuzu_java_native.so" + "_" + os_name + "_" + os_arch; + + Path lib_file = Files.createTempFile("libkuzu_java_native", ".so"); + URL lib_res = KuzuNative.class.getResource(lib_res_name); + if (lib_res == null) { + throw new IOException(lib_res_name + " not found"); + } + Files.copy(lib_res.openStream(), lib_file, StandardCopyOption.REPLACE_EXISTING); + new File(lib_file.toString()).deleteOnExit(); + System.load(lib_file.toAbsolutePath().toString()); + } catch (IOException e) { + e.printStackTrace(); + } } // Database protected static native long kuzu_database_init(String database_path, long buffer_pool_size); + protected static native void kuzu_database_destroy(KuzuDatabase db); + protected static native void kuzu_database_set_logging_level(String logging_level); // Connection protected static native long kuzu_connection_init(KuzuDatabase database); + protected static native void kuzu_connection_destroy(KuzuConnection connection); + protected static native void kuzu_connection_begin_read_only_transaction(KuzuConnection connection); + protected static native void kuzu_connection_begin_write_transaction(KuzuConnection connection); + protected static native void kuzu_connection_commit(KuzuConnection connection); + protected static native void kuzu_connection_rollback(KuzuConnection connection); + protected static native void kuzu_connection_set_max_num_thread_for_exec( - KuzuConnection connection, long num_threads); + KuzuConnection connection, long num_threads); + protected static native long kuzu_connection_get_max_num_thread_for_exec(KuzuConnection connection); + protected static native KuzuQueryResult kuzu_connection_query(KuzuConnection connection, String query); + protected static native KuzuPreparedStatement kuzu_connection_prepare( - KuzuConnection connection, String query); + KuzuConnection connection, String query); + protected static native KuzuQueryResult kuzu_connection_execute( - KuzuConnection connection, KuzuPreparedStatement prepared_statement, Map param); + KuzuConnection connection, KuzuPreparedStatement prepared_statement, Map param); + protected static native String kuzu_connection_get_node_table_names(KuzuConnection connection); + protected static native String kuzu_connection_get_rel_table_names(KuzuConnection connection); + protected static native String kuzu_connection_get_node_property_names( - KuzuConnection connection, String table_name); + KuzuConnection connection, String table_name); + protected static native String kuzu_connection_get_rel_property_names( - KuzuConnection connection, String table_name); + KuzuConnection connection, String table_name); + protected static native void kuzu_connection_interrupt(KuzuConnection connection); + protected static native void kuzu_connection_set_query_timeout( - KuzuConnection connection, long timeout_in_ms); + KuzuConnection connection, long timeout_in_ms); // PreparedStatement protected static native void kuzu_prepared_statement_destroy(KuzuPreparedStatement prepared_statement); + protected static native boolean kuzu_prepared_statement_allow_active_transaction( - KuzuPreparedStatement prepared_statement); + KuzuPreparedStatement prepared_statement); + protected static native boolean kuzu_prepared_statement_is_success(KuzuPreparedStatement prepared_statement); + protected static native String kuzu_prepared_statement_get_error_message( - KuzuPreparedStatement prepared_statement); - + KuzuPreparedStatement prepared_statement); + // QueryResult protected static native void kuzu_query_result_destroy(KuzuQueryResult query_result); + protected static native boolean kuzu_query_result_is_success(KuzuQueryResult query_result); + protected static native String kuzu_query_result_get_error_message(KuzuQueryResult query_result); + protected static native long kuzu_query_result_get_num_columns(KuzuQueryResult query_result); + protected static native String kuzu_query_result_get_column_name(KuzuQueryResult query_result, long index); + protected static native KuzuDataType kuzu_query_result_get_column_data_type( - KuzuQueryResult query_result, long index); + KuzuQueryResult query_result, long index); + protected static native long kuzu_query_result_get_num_tuples(KuzuQueryResult query_result); + protected static native KuzuQuerySummary kuzu_query_result_get_query_summary(KuzuQueryResult query_result); + protected static native boolean kuzu_query_result_has_next(KuzuQueryResult query_result); + protected static native KuzuFlatTuple kuzu_query_result_get_next(KuzuQueryResult query_result); + protected static native String kuzu_query_result_to_string(KuzuQueryResult query_result); + protected static native void kuzu_query_result_write_to_csv(KuzuQueryResult query_result, - String file_path, char delimiter, char escape_char, char new_line); + String file_path, char delimiter, char escape_char, char new_line); + protected static native void kuzu_query_result_reset_iterator(KuzuQueryResult query_result); // FlatTuple protected static native void kuzu_flat_tuple_destroy(KuzuFlatTuple flat_tuple); + protected static native KuzuValue kuzu_flat_tuple_get_value(KuzuFlatTuple flat_tuple, long index); + protected static native String kuzu_flat_tuple_to_string(KuzuFlatTuple flat_tuple); // DataType protected static native long kuzu_data_type_create( - KuzuDataTypeID id, KuzuDataType child_type, long fixed_num_elements_in_list); + KuzuDataTypeID id, KuzuDataType child_type, long fixed_num_elements_in_list); + protected static native KuzuDataType kuzu_data_type_clone(KuzuDataType data_type); + protected static native void kuzu_data_type_destroy(KuzuDataType data_type); + protected static native boolean kuzu_data_type_equals(KuzuDataType data_type1, KuzuDataType data_type2); + protected static native KuzuDataTypeID kuzu_data_type_get_id(KuzuDataType data_type); + protected static native KuzuDataType kuzu_data_type_get_child_type(KuzuDataType data_type); + protected static native long kuzu_data_type_get_fixed_num_elements_in_list(KuzuDataType data_type); // Value protected static native KuzuValue kuzu_value_create_null(); + protected static native KuzuValue kuzu_value_create_null_with_data_type(KuzuDataType data_type); + protected static native boolean kuzu_value_is_null(KuzuValue value); + protected static native void kuzu_value_set_null(KuzuValue value, boolean is_null); + protected static native KuzuValue kuzu_value_create_default(KuzuDataType data_type); + protected static native long kuzu_value_create_value(T val); - + protected static native KuzuValue kuzu_value_clone(KuzuValue value); + protected static native void kuzu_value_copy(KuzuValue value, KuzuValue other); + protected static native void kuzu_value_destroy(KuzuValue value); + protected static native long kuzu_value_get_list_size(KuzuValue value); + protected static native KuzuValue kuzu_value_get_list_element(KuzuValue value, long index); + protected static native KuzuDataType kuzu_value_get_data_type(KuzuValue value); protected static native T kuzu_value_get_value(KuzuValue value); @@ -96,32 +196,55 @@ protected static native long kuzu_data_type_create( protected static native String kuzu_value_to_string(KuzuValue value); protected static native long kuzu_node_val_create(KuzuInternalID id, String label); + protected static native KuzuNodeValue kuzu_node_val_clone(KuzuNodeValue node_val); + protected static native void kuzu_node_val_destroy(KuzuNodeValue node_val); + protected static native KuzuValue kuzu_node_val_get_id_val(KuzuNodeValue node_val); + protected static native KuzuValue kuzu_node_val_get_label_val(KuzuNodeValue node_val); + protected static native KuzuInternalID kuzu_node_val_get_id(KuzuNodeValue node_val); + protected static native String kuzu_node_val_get_label_name(KuzuNodeValue node_val); + protected static native long kuzu_node_val_get_property_size(KuzuNodeValue node_val); + protected static native String kuzu_node_val_get_property_name_at(KuzuNodeValue node_val, long index); + protected static native KuzuValue kuzu_node_val_get_property_value_at(KuzuNodeValue node_val, long index); + protected static native void kuzu_node_val_add_property( - KuzuNodeValue node_val, String key, KuzuValue value); + KuzuNodeValue node_val, String key, KuzuValue value); + protected static native String kuzu_node_val_to_string(KuzuNodeValue node_val); protected static native long kuzu_rel_val_create( - KuzuInternalID src_id, KuzuInternalID dst_id, String label); + KuzuInternalID src_id, KuzuInternalID dst_id, String label); + protected static native KuzuRelValue kuzu_rel_val_clone(KuzuRelValue rel_val); + protected static native void kuzu_rel_val_destroy(KuzuRelValue rel_val); + protected static native KuzuValue kuzu_rel_val_get_src_id_val(KuzuRelValue rel_val); + protected static native KuzuValue kuzu_rel_val_get_dst_id_val(KuzuRelValue rel_val); + protected static native KuzuInternalID kuzu_rel_val_get_src_id(KuzuRelValue rel_val); + protected static native KuzuInternalID kuzu_rel_val_get_dst_id(KuzuRelValue rel_val); + protected static native String kuzu_rel_val_get_label_name(KuzuRelValue rel_val); + protected static native long kuzu_rel_val_get_property_size(KuzuRelValue rel_val); + protected static native String kuzu_rel_val_get_property_name_at(KuzuRelValue rel_val, long index); + protected static native KuzuValue kuzu_rel_val_get_property_value_at(KuzuRelValue rel_val, long index); + protected static native void kuzu_rel_val_add_property(KuzuRelValue rel_val, String key, KuzuValue value); + protected static native String kuzu_rel_val_to_string(KuzuRelValue rel_val); } diff --git a/tools/java_api/KuzuNodeValue.java b/tools/java_api/src/main/java/com/kuzudb/KuzuNodeValue.java similarity index 94% rename from tools/java_api/KuzuNodeValue.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuNodeValue.java index 6aababa4cb..2673721923 100644 --- a/tools/java_api/KuzuNodeValue.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuNodeValue.java @@ -1,22 +1,22 @@ -package tools.java_api; +package com.kuzudb; public class KuzuNodeValue { long nv_ref; boolean destroyed = false; boolean isOwnedByCPP = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuNodeValue(KuzuInternalID id, String label) { + nv_ref = KuzuNative.kuzu_node_val_create(id, label); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuNodeValue has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } - - public KuzuNodeValue(KuzuInternalID id, String label) { - nv_ref = KuzuNative.kuzu_node_val_create(id, label); + destroy(); } public KuzuNodeValue clone() { diff --git a/tools/java_api/KuzuObjectRefDestroyedException.java b/tools/java_api/src/main/java/com/kuzudb/KuzuObjectRefDestroyedException.java similarity index 87% rename from tools/java_api/KuzuObjectRefDestroyedException.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuObjectRefDestroyedException.java index d32d1e6871..54e2e478f0 100644 --- a/tools/java_api/KuzuObjectRefDestroyedException.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuObjectRefDestroyedException.java @@ -1,4 +1,4 @@ -package tools.java_api; +package com.kuzudb; public class KuzuObjectRefDestroyedException extends Exception { public KuzuObjectRefDestroyedException(String errorMessage) { diff --git a/tools/java_api/KuzuPreparedStatement.java b/tools/java_api/src/main/java/com/kuzudb/KuzuPreparedStatement.java similarity index 87% rename from tools/java_api/KuzuPreparedStatement.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuPreparedStatement.java index 375a8f3ad1..9bcf3417e4 100644 --- a/tools/java_api/KuzuPreparedStatement.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuPreparedStatement.java @@ -1,18 +1,18 @@ -package tools.java_api; +package com.kuzudb; public class KuzuPreparedStatement { long ps_ref; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuPreparedStatement has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } + destroy(); + } public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); diff --git a/tools/java_api/KuzuQueryResult.java b/tools/java_api/src/main/java/com/kuzudb/KuzuQueryResult.java similarity index 61% rename from tools/java_api/KuzuQueryResult.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuQueryResult.java index 7f18ab4caa..59ca609550 100644 --- a/tools/java_api/KuzuQueryResult.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuQueryResult.java @@ -1,83 +1,83 @@ -package tools.java_api; +package com.kuzudb; public class KuzuQueryResult { long qr_ref; boolean destroyed = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuQueryResult has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } + destroy(); + } - public void destroy () throws KuzuObjectRefDestroyedException { + public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_query_result_destroy(this); destroyed = true; } - public boolean isSuccess () throws KuzuObjectRefDestroyedException { + public boolean isSuccess() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_is_success(this); } - public String getErrorMessage () throws KuzuObjectRefDestroyedException { + public String getErrorMessage() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_error_message(this); } - public long getNumColumns () throws KuzuObjectRefDestroyedException { + public long getNumColumns() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_num_columns(this); } - public String getColumnName (long index) throws KuzuObjectRefDestroyedException { + public String getColumnName(long index) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_column_name(this, index); } - public KuzuDataType getColumnDataType (long index) throws KuzuObjectRefDestroyedException { + public KuzuDataType getColumnDataType(long index) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_column_data_type(this, index); } - public long getNumTuples () throws KuzuObjectRefDestroyedException { + public long getNumTuples() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_num_tuples(this); } - public KuzuQuerySummary getQuerySummary () throws KuzuObjectRefDestroyedException { + public KuzuQuerySummary getQuerySummary() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_query_summary(this); } - public boolean hasNext () throws KuzuObjectRefDestroyedException { + public boolean hasNext() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_has_next(this); } - public KuzuFlatTuple getNext () throws KuzuObjectRefDestroyedException { + public KuzuFlatTuple getNext() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_query_result_get_next(this); } - public String toString () { + public String toString() { if (destroyed) return "KuzuQueryResult has been destroyed."; else return KuzuNative.kuzu_query_result_to_string(this); } - public void writeToCsv (String file_path, char delimiter, char escape_char, char new_line) throws KuzuObjectRefDestroyedException { + public void writeToCsv(String file_path, char delimiter, char escape_char, char new_line) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_query_result_write_to_csv(this, file_path, delimiter, escape_char, new_line); } - public void resetIterator () throws KuzuObjectRefDestroyedException { + public void resetIterator() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_query_result_reset_iterator(this); } diff --git a/tools/java_api/KuzuQuerySummary.java b/tools/java_api/src/main/java/com/kuzudb/KuzuQuerySummary.java similarity index 93% rename from tools/java_api/KuzuQuerySummary.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuQuerySummary.java index 3db7be98c1..31c2a18ddc 100644 --- a/tools/java_api/KuzuQuerySummary.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuQuerySummary.java @@ -1,4 +1,4 @@ -package tools.java_api; +package com.kuzudb; public class KuzuQuerySummary { diff --git a/tools/java_api/KuzuRelValue.java b/tools/java_api/src/main/java/com/kuzudb/KuzuRelValue.java similarity index 94% rename from tools/java_api/KuzuRelValue.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuRelValue.java index a7809cf765..d6b7c91a9a 100644 --- a/tools/java_api/KuzuRelValue.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuRelValue.java @@ -1,22 +1,22 @@ -package tools.java_api; +package com.kuzudb; public class KuzuRelValue { long rv_ref; boolean destroyed = false; boolean isOwnedByCPP = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuRelValue(KuzuInternalID src_id, KuzuInternalID dst_id, String label) { + rv_ref = KuzuNative.kuzu_rel_val_create(src_id, dst_id, label); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuRelValue has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } - - public KuzuRelValue(KuzuInternalID src_id, KuzuInternalID dst_id, String label) { - rv_ref = KuzuNative.kuzu_rel_val_create(src_id, dst_id, label); + destroy(); } public KuzuRelValue clone() { diff --git a/tools/java_api/KuzuValue.java b/tools/java_api/src/main/java/com/kuzudb/KuzuValue.java similarity index 68% rename from tools/java_api/KuzuValue.java rename to tools/java_api/src/main/java/com/kuzudb/KuzuValue.java index 6c21498eb5..8a6b6da695 100644 --- a/tools/java_api/KuzuValue.java +++ b/tools/java_api/src/main/java/com/kuzudb/KuzuValue.java @@ -1,30 +1,42 @@ -package tools.java_api; +package com.kuzudb; public class KuzuValue { long v_ref; boolean destroyed = false; boolean isOwnedByCPP = false; - private void checkNotDestroyed () throws KuzuObjectRefDestroyedException { + public KuzuValue(T val) throws KuzuObjectRefDestroyedException { + checkNotDestroyed(); + v_ref = KuzuNative.kuzu_value_create_value(val); + } + + public static KuzuValue createNull() { + return KuzuNative.kuzu_value_create_null(); + } + + public static KuzuValue createNullWithDataType(KuzuDataType data_type) { + return KuzuNative.kuzu_value_create_null_with_data_type(data_type); + } + + public static KuzuValue createDefault(KuzuDataType data_type) { + return KuzuNative.kuzu_value_create_default(data_type); + } + + private void checkNotDestroyed() throws KuzuObjectRefDestroyedException { if (destroyed) throw new KuzuObjectRefDestroyedException("KuzuValue has been destroyed."); } - @Override + @Override protected void finalize() throws KuzuObjectRefDestroyedException { - destroy(); - } + destroy(); + } public boolean isOwnedByCPP() { return isOwnedByCPP; } - public KuzuValue (T val) throws KuzuObjectRefDestroyedException { - checkNotDestroyed(); - v_ref = KuzuNative.kuzu_value_create_value(val); - } - - public void destroy () throws KuzuObjectRefDestroyedException { + public void destroy() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); if (!isOwnedByCPP) { KuzuNative.kuzu_value_destroy(this); @@ -32,61 +44,49 @@ public void destroy () throws KuzuObjectRefDestroyedException { } } - public static KuzuValue createNull() { - return KuzuNative.kuzu_value_create_null(); - } - - public static KuzuValue createNullWithDataType(KuzuDataType data_type) { - return KuzuNative.kuzu_value_create_null_with_data_type(data_type); - } - - public static KuzuValue createDefault(KuzuDataType data_type) { - return KuzuNative.kuzu_value_create_default(data_type); - } - - public boolean isNull () throws KuzuObjectRefDestroyedException { + public boolean isNull() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_value_is_null(this); } - public void setNull (boolean flag) throws KuzuObjectRefDestroyedException { + public void setNull(boolean flag) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_value_set_null(this, flag); } - public void copy (KuzuValue other) throws KuzuObjectRefDestroyedException { + public void copy(KuzuValue other) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); KuzuNative.kuzu_value_copy(this, other); } - public KuzuValue clone () { + public KuzuValue clone() { if (destroyed) return null; - else + else return KuzuNative.kuzu_value_clone(this); } - public T getValue () throws KuzuObjectRefDestroyedException{ + public T getValue() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_value_get_value(this); } - public long getListSize () throws KuzuObjectRefDestroyedException { + public long getListSize() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_value_get_list_size(this); } - public KuzuValue getListElement (long index) throws KuzuObjectRefDestroyedException { + public KuzuValue getListElement(long index) throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_value_get_list_element(this, index); } - public KuzuDataType getDataType () throws KuzuObjectRefDestroyedException { + public KuzuDataType getDataType() throws KuzuObjectRefDestroyedException { checkNotDestroyed(); return KuzuNative.kuzu_value_get_data_type(this); } - public String toString () { + public String toString() { if (destroyed) return "KuzuValue has been destroyed."; else diff --git a/tools/java_api/java_test/ConnectionTest.java b/tools/java_api/src/test/java/com/kuzudb/test/ConnectionTest.java similarity index 83% rename from tools/java_api/java_test/ConnectionTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/ConnectionTest.java index fbcd39b01f..6973ea7daa 100644 --- a/tools/java_api/java_test/ConnectionTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/ConnectionTest.java @@ -1,9 +1,10 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.MethodOrderer; + import static org.junit.jupiter.api.Assertions.*; import java.util.Map; @@ -18,25 +19,25 @@ public class ConnectionTest extends TestBase { @Test void ConnCreationAndDestroy() { - try{ + try { KuzuConnection conn = new KuzuConnection(db); conn.destroy(); - }catch(AssertionError e) { + } catch (AssertionError e) { fail("ConnCreationAndDestroy failed: "); System.out.println(e.toString()); - }catch(KuzuObjectRefDestroyedException e) { + } catch (KuzuObjectRefDestroyedException e) { fail("ConnCreationAndDestroy failed: "); System.out.println(e.toString()); } System.out.println("ConnCreationAndDestroy passed"); } - @Test + @Test void ConnInvalidDB() { - try{ + try { KuzuConnection conn = new KuzuConnection(null); fail("DBInvalidPath did not throw KuzuObjectRefDestroyedException as expected."); - }catch(AssertionError e) { + } catch (AssertionError e) { } System.out.println("ConnInvalidDB passed"); } @@ -79,7 +80,7 @@ void ConnPrepareBool() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 3); + assertEquals(((long) tuple.getValue(0).getValue()), 3); statement.destroy(); result.destroy(); System.out.println("ConnPrepare passed"); @@ -89,9 +90,9 @@ void ConnPrepareBool() throws KuzuObjectRefDestroyedException { void ConnPrepareInt64() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:person) WHERE a.age > $1 RETURN COUNT(*)"; Map m = new HashMap(); - - m.put("1", new KuzuValue((long)30)); - + + m.put("1", new KuzuValue((long) 30)); + KuzuPreparedStatement statement = conn.prepare(query); assertNotNull(statement); KuzuQueryResult result = conn.execute(statement, m); @@ -102,7 +103,7 @@ void ConnPrepareInt64() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 4); + assertEquals(((long) tuple.getValue(0).getValue()), 4); statement.destroy(); result.destroy(); System.out.println("ConnPrepareInt64 passed"); @@ -112,7 +113,7 @@ void ConnPrepareInt64() throws KuzuObjectRefDestroyedException { void ConnPrepareInt32() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:movies) WHERE a.length > $1 RETURN COUNT(*)"; Map m = new HashMap(); - m.put("1", new KuzuValue((int)200)); + m.put("1", new KuzuValue((int) 200)); KuzuPreparedStatement statement = conn.prepare(query); assertNotNull(statement); KuzuQueryResult result = conn.execute(statement, m); @@ -123,7 +124,7 @@ void ConnPrepareInt32() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 2); + assertEquals(((long) tuple.getValue(0).getValue()), 2); statement.destroy(); result.destroy(); System.out.println("ConnPrepareInt32 passed"); @@ -133,7 +134,7 @@ void ConnPrepareInt32() throws KuzuObjectRefDestroyedException { void ConnPrepareInt16() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:person) -[s:studyAt]-> (b:organisation) WHERE s.length > $1 RETURN COUNT(*)"; Map m = new HashMap(); - m.put("1", new KuzuValue((short)10)); + m.put("1", new KuzuValue((short) 10)); KuzuPreparedStatement statement = conn.prepare(query); assertNotNull(statement); KuzuQueryResult result = conn.execute(statement, m); @@ -144,7 +145,7 @@ void ConnPrepareInt16() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 2); + assertEquals(((long) tuple.getValue(0).getValue()), 2); statement.destroy(); result.destroy(); System.out.println("ConnPrepareInt16 passed"); @@ -154,7 +155,7 @@ void ConnPrepareInt16() throws KuzuObjectRefDestroyedException { void ConnPrepareDouble() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:person) WHERE a.eyeSight > $1 RETURN COUNT(*)"; Map m = new HashMap(); - m.put("1", new KuzuValue((double)4.5)); + m.put("1", new KuzuValue((double) 4.5)); KuzuPreparedStatement statement = conn.prepare(query); assertNotNull(statement); KuzuQueryResult result = conn.execute(statement, m); @@ -165,7 +166,7 @@ void ConnPrepareDouble() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 7); + assertEquals(((long) tuple.getValue(0).getValue()), 7); statement.destroy(); result.destroy(); System.out.println("ConnPrepareDouble passed"); @@ -175,7 +176,7 @@ void ConnPrepareDouble() throws KuzuObjectRefDestroyedException { void ConnPrepareFloat() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:person) WHERE a.height < $1 RETURN COUNT(*)"; Map m = new HashMap(); - m.put("1", new KuzuValue((float)1.0)); + m.put("1", new KuzuValue((float) 1.0)); KuzuPreparedStatement statement = conn.prepare(query); assertNotNull(statement); KuzuQueryResult result = conn.execute(statement, m); @@ -186,7 +187,7 @@ void ConnPrepareFloat() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 1); + assertEquals(((long) tuple.getValue(0).getValue()), 1); statement.destroy(); result.destroy(); System.out.println("ConnPrepareFloat passed"); @@ -207,7 +208,7 @@ void ConnPrepareString() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 1); + assertEquals(((long) tuple.getValue(0).getValue()), 1); statement.destroy(); result.destroy(); System.out.println("ConnPrepareString passed"); @@ -228,7 +229,7 @@ void ConnPrepareDate() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 4); + assertEquals(((long) tuple.getValue(0).getValue()), 4); statement.destroy(); result.destroy(); System.out.println("ConnPrepareDate passed"); @@ -249,7 +250,7 @@ void ConnPrepareTimeStamp() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 7); + assertEquals(((long) tuple.getValue(0).getValue()), 7); statement.destroy(); result.destroy(); System.out.println("ConnPrepareTimeStamp passed"); @@ -270,7 +271,7 @@ void ConnPrepareInterval() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 3); + assertEquals(((long) tuple.getValue(0).getValue()), 3); statement.destroy(); result.destroy(); System.out.println("ConnPrepareInterval passed"); @@ -292,24 +293,24 @@ void ConnPrepareMultiParam() throws KuzuObjectRefDestroyedException { assertEquals(result.getNumTuples(), 1); assertEquals(result.getNumColumns(), 1); KuzuFlatTuple tuple = result.getNext(); - assertEquals(((long)tuple.getValue(0).getValue()), 1); + assertEquals(((long) tuple.getValue(0).getValue()), 1); statement.destroy(); result.destroy(); System.out.println("ConnPrepareMultiParam passed"); } - + @Test void ConnGetNodeTableNames() throws KuzuObjectRefDestroyedException { String result = conn.getNodeTableNames(); assertNotNull(result); - assertTrue(result.equals("Node tables: \n" + - "\torganisation\n" + - "\tperson\n" + - "\tmovies\n") || - result.equals("Node tables: \n" + - "\tmovies\n" + - "\tperson\n" + - "\torganisation\n")); + assertTrue(result.equals("Node tables: \n" + + "\torganisation\n" + + "\tperson\n" + + "\tmovies\n") || + result.equals("Node tables: \n" + + "\tmovies\n" + + "\tperson\n" + + "\torganisation\n")); System.out.println("ConnGetNodeTableNames passed"); } @@ -318,17 +319,17 @@ void ConnGetRelTableNames() throws KuzuObjectRefDestroyedException { String result = conn.getRelTableNames(); assertNotNull(result); assertTrue(result.equals("Rel tables: \n" + - "\tmeets\n" + - "\tstudyAt\n" + - "\tknows\n" + - "\tworkAt\n" + - "\tmarries\n") || - result.equals("Rel tables: \n" + - "\tmarries\n" + - "\tworkAt\n" + - "\tknows\n" + - "\tstudyAt\n" + - "\tmeets\n")); + "\tmeets\n" + + "\tstudyAt\n" + + "\tknows\n" + + "\tworkAt\n" + + "\tmarries\n") || + result.equals("Rel tables: \n" + + "\tmarries\n" + + "\tworkAt\n" + + "\tknows\n" + + "\tstudyAt\n" + + "\tmeets\n")); System.out.println("ConnGetRelTableNames passed"); } @@ -337,10 +338,10 @@ void ConnGetNodePropertyNames() throws KuzuObjectRefDestroyedException { String result = conn.getNodePropertyNames("movies"); assertNotNull(result); assertTrue(result.equals("movies properties: \n" + - "\tname STRING(PRIMARY KEY)\n" + - "\tlength INT32\n" + - "\tnote STRING\n" + - "\tdescription STRUCT(DOUBLE,INT64,TIMESTAMP,DATE)\n")); + "\tname STRING(PRIMARY KEY)\n" + + "\tlength INT32\n" + + "\tnote STRING\n" + + "\tdescription STRUCT(DOUBLE,INT64,TIMESTAMP,DATE)\n")); System.out.println("ConnGetNodePropertyNames passed"); } @@ -348,11 +349,11 @@ void ConnGetNodePropertyNames() throws KuzuObjectRefDestroyedException { void ConnGetRelPropertyNames() throws KuzuObjectRefDestroyedException { String result = conn.getRelPropertyNames("meets"); assertNotNull(result); - assertTrue(result.equals("meets src node: person\n" + - "meets dst node: person\n" + - "meets properties: \n" + - "\tlocation FLOAT[2]\n" + - "\ttimes INT32\n")); + assertTrue(result.equals("meets src node: person\n" + + "meets dst node: person\n" + + "meets properties: \n" + + "\tlocation FLOAT[2]\n" + + "\ttimes INT32\n")); System.out.println("ConnGetRelPropertyNames passed"); } diff --git a/tools/java_api/java_test/DataTypeTest.java b/tools/java_api/src/test/java/com/kuzudb/test/DataTypeTest.java similarity index 98% rename from tools/java_api/java_test/DataTypeTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/DataTypeTest.java index 1263040d70..a2076088ac 100644 --- a/tools/java_api/java_test/DataTypeTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/DataTypeTest.java @@ -1,7 +1,8 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; @@ -31,7 +32,7 @@ void DataTypeClone() throws KuzuObjectRefDestroyedException { assertEquals(dataTypeClone3.getFixedNumElementsInList(), 100); assertFalse(dataTypeClone2.equals(dataTypeClone3)); - + dataType.destroy(); dataType2.destroy(); dataType3.destroy(); @@ -66,7 +67,7 @@ void DataTypeEquals() throws KuzuObjectRefDestroyedException { assertFalse(dataType.equals(dataType3)); assertFalse(dataType2.equals(dataType3)); assertFalse(dataTypeClone.equals(dataTypeClone3)); - + dataType.destroy(); dataType2.destroy(); dataType3.destroy(); @@ -118,7 +119,7 @@ void DataTypeGetChildType() throws KuzuObjectRefDestroyedException { System.out.println("DataTypeGetChildType passed"); } - @Test + @Test void DataTypeGetFixedNumElementsInList() throws KuzuObjectRefDestroyedException { KuzuDataType dataType = new KuzuDataType(KuzuDataTypeID.INT64, null, 0); assertNotNull(dataType); diff --git a/tools/java_api/java_test/DatabaseTest.java b/tools/java_api/src/test/java/com/kuzudb/test/DatabaseTest.java similarity index 69% rename from tools/java_api/java_test/DatabaseTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/DatabaseTest.java index a8f25c3d19..f4f80765f7 100644 --- a/tools/java_api/java_test/DatabaseTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/DatabaseTest.java @@ -1,18 +1,25 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; +import com.kuzudb.*; +import org.junit.jupiter.api.io.TempDir; +import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; -import org.junit.jupiter.api.Test; -import tools.java_api.*; +import java.nio.file.Path; + +import java.io.IOException; public class DatabaseTest extends TestBase { + @TempDir + static Path tempDir; + @Test void DBCreationAndDestroy() { - String databasePath = System.getProperty("user.dir") + "dbtest"; - try{ - KuzuDatabase database = new KuzuDatabase(databasePath, 0); + try { + String dbPath = tempDir.toFile().getAbsolutePath(); + KuzuDatabase database = new KuzuDatabase(dbPath, 0); database.destroy(); - }catch(Exception e) { + } catch (Exception e) { fail("DBCreationAndDestroy failed: "); System.out.println(e.toString()); } @@ -20,32 +27,32 @@ void DBCreationAndDestroy() { System.out.println("DBCreationAndDestroy passed"); } - @Test + @Test void DBInvalidPath() { - try{ + try { KuzuDatabase database = new KuzuDatabase("", 0); database.destroy(); fail("DBInvalidPath did not throw exception as expected."); - }catch(Exception e) { + } catch (Exception e) { System.out.println("DBInvalidPath passed"); } } @Test void DBSetLoggingLevel() { - try{ + try { KuzuDatabase.setLoggingLevel("debug"); KuzuDatabase.setLoggingLevel("info"); KuzuDatabase.setLoggingLevel("err"); - }catch(Exception e){ + } catch (Exception e) { fail("DBSetLoggingLevel failed: "); System.out.println(e.toString()); } - - try{ + + try { KuzuDatabase.setLoggingLevel("unsupported"); fail("DBSetLoggingLevel did not throw exception as expected."); - }catch(Exception e){ + } catch (Exception e) { } System.out.println("DBSetLoggingLevel passed"); diff --git a/tools/java_api/java_test/FlatTupleTest.java b/tools/java_api/src/test/java/com/kuzudb/test/FlatTupleTest.java similarity index 93% rename from tools/java_api/java_test/FlatTupleTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/FlatTupleTest.java index 295ded556b..668272f1a5 100644 --- a/tools/java_api/java_test/FlatTupleTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/FlatTupleTest.java @@ -1,7 +1,8 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; public class FlatTupleTest extends TestBase { @@ -29,12 +30,12 @@ void FlatTupleGetValue() throws KuzuObjectRefDestroyedException { value = flatTuple.getValue(2); assertNotNull(value); assertEquals(value.getDataType().getID(), KuzuDataTypeID.FLOAT); - assertTrue(value.getValue().equals((float)1.731)); + assertTrue(value.getValue().equals((float) 1.731)); value.destroy(); value = flatTuple.getValue(222); assertNull(value); - + result.destroy(); System.out.println("FlatTupleGetValue passed"); } @@ -46,7 +47,7 @@ void FlatTupleToString() throws KuzuObjectRefDestroyedException { assertTrue(result.hasNext()); KuzuFlatTuple flatTuple = result.getNext(); assertNotNull(flatTuple); - + String str = flatTuple.toString(); assertTrue(str.equals("Alice|35|1.731000\n")); diff --git a/tools/java_api/java_test/PreparedStatementTest.java b/tools/java_api/src/test/java/com/kuzudb/test/PreparedStatementTest.java similarity index 97% rename from tools/java_api/java_test/PreparedStatementTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/PreparedStatementTest.java index cfc035682b..143c1bde5d 100644 --- a/tools/java_api/java_test/PreparedStatementTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/PreparedStatementTest.java @@ -1,12 +1,13 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; public class PreparedStatementTest extends TestBase { - @Test + @Test void PrepStmtIsSuccess() throws KuzuObjectRefDestroyedException { String query = "MATCH (a:person) WHERE a.isStudent = $1 RETURN COUNT(*)"; KuzuPreparedStatement preparedStatement1 = conn.prepare(query); diff --git a/tools/java_api/java_test/QueryResultTest.java b/tools/java_api/src/test/java/com/kuzudb/test/QueryResultTest.java similarity index 86% rename from tools/java_api/java_test/QueryResultTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/QueryResultTest.java index 6912479d56..14e5ef90a9 100644 --- a/tools/java_api/java_test/QueryResultTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/QueryResultTest.java @@ -1,7 +1,9 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; +import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; import java.util.Scanner; @@ -12,6 +14,8 @@ import java.nio.file.Files; public class QueryResultTest extends TestBase { + @TempDir + static Path tempDir; @Test void QueryResultGetErrorMessage() throws KuzuObjectRefDestroyedException { @@ -122,33 +126,30 @@ void QueryResultGetNext() throws KuzuObjectRefDestroyedException { } @Test - void QueryResultWriteToCSV() throws IOException, KuzuObjectRefDestroyedException{ - String newline = "\n"; - String basicOutput = - "Carol,1,5.000000,1940-06-22,1911-08-20 02:32:21,CsWork" + newline + - "Dan,2,4.800000,1950-07-23,2031-11-30 12:25:30,DEsWork" + newline + - "Elizabeth,1,4.700000,1980-10-26,1976-12-23 11:21:42,DEsWork" + newline; + void QueryResultWriteToCSV() throws IOException, KuzuObjectRefDestroyedException { String query = "MATCH (a:person)-[:workAt]->(o:organisation) RETURN a.fName, a.gender," + - "a.eyeSight, a.birthdate, a.registerTime, o.name"; + "a.eyeSight, a.birthdate, a.registerTime, o.name"; KuzuQueryResult result = conn.query(query); assertTrue(result.isSuccess()); - Path tempDir = Files.createTempFile("output_CSV_CAPI", "csv"); - tempDir.toFile().deleteOnExit(); - - String outputPath = "output_CSV_CAPI.csv"; + final Path tempFile = Files.createFile(tempDir.resolve("test.csv")); + String outputPath = tempFile.toFile().getAbsolutePath(); result.writeToCsv(outputPath, ',', '"', '\n'); - + try { File csv = new File(outputPath); - Scanner s = new Scanner(csv); - String content = s.useDelimiter("\\z").next(); - assertTrue(basicOutput.equals(content)); - s.close(); + Scanner scanner = new Scanner(csv); + String line = scanner.nextLine(); + assertEquals(line, "Carol,1,5.000000,1940-06-22,1911-08-20 02:32:21,CsWork"); + line = scanner.nextLine(); + assertEquals(line, "Dan,2,4.800000,1950-07-23,2031-11-30 12:25:30,DEsWork"); + line = scanner.nextLine(); + assertEquals(line, "Elizabeth,1,4.700000,1980-10-26,1976-12-23 11:21:42,DEsWork"); + scanner.close(); System.out.println("QueryResultWriteToCSV passed"); - } catch(FileNotFoundException e) { + } catch (FileNotFoundException e) { fail("QueryResultWriteToCSV failed, csv file not found"); - } + } } @Test diff --git a/tools/java_api/java_test/TestBase.java b/tools/java_api/src/test/java/com/kuzudb/test/TestBase.java similarity index 86% rename from tools/java_api/java_test/TestBase.java rename to tools/java_api/src/test/java/com/kuzudb/test/TestBase.java index 198a35ed01..750db35f82 100644 --- a/tools/java_api/java_test/TestBase.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/TestBase.java @@ -1,23 +1,25 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.io.TempDir; import org.junit.jupiter.api.AfterAll; + import static org.junit.jupiter.api.Assertions.*; + import java.nio.file.Path; import java.io.IOException; public class TestBase { + protected static KuzuDatabase db; + protected static KuzuConnection conn; @TempDir static Path tempDir; - protected static KuzuDatabase db; - protected static KuzuConnection conn; @BeforeAll - static void getDBandConn() throws IOException, KuzuObjectRefDestroyedException{ + static void getDBandConn() throws IOException, KuzuObjectRefDestroyedException { System.out.println("Kuzu test starting, loading data..."); TestHelper.loadData(tempDir.toFile().getAbsolutePath()); db = TestHelper.getDatabase(); @@ -28,14 +30,14 @@ static void getDBandConn() throws IOException, KuzuObjectRefDestroyedException{ @AfterAll static void destroyDBandConn() throws KuzuObjectRefDestroyedException { System.out.println("Kuzu test finished, cleaning up data..."); - try{ + try { db.destroy(); conn.destroy(); - }catch(AssertionError e) { + } catch (AssertionError e) { fail("destroyDBandConn failed: "); System.out.println(e.toString()); } System.out.println("Data cleaned up"); } - + } diff --git a/tools/java_api/java_test/TestHelper.java b/tools/java_api/src/test/java/com/kuzudb/test/TestHelper.java similarity index 58% rename from tools/java_api/java_test/TestHelper.java rename to tools/java_api/src/test/java/com/kuzudb/test/TestHelper.java index 958014426e..4a6c5be82d 100644 --- a/tools/java_api/java_test/TestHelper.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/TestHelper.java @@ -1,4 +1,4 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; import java.io.BufferedReader; import java.io.FileReader; @@ -7,7 +7,7 @@ import java.nio.file.Files; -import tools.java_api.*; +import com.kuzudb.*; public class TestHelper { private static KuzuDatabase db; @@ -22,20 +22,17 @@ public static KuzuConnection getConnection() { } public static void loadData(String dbPath) throws IOException, KuzuObjectRefDestroyedException { - Path tempDir = Files.createTempDirectory("java_api_test_db"); - tempDir.toFile().deleteOnExit(); - BufferedReader reader; db = new KuzuDatabase(dbPath, 0); conn = new KuzuConnection(db); try { - reader = new BufferedReader(new FileReader("./../../dataset/tinysnb/schema.cypher")); - String line = reader.readLine(); + reader = new BufferedReader(new FileReader("./../../dataset/tinysnb/schema.cypher")); + String line = reader.readLine(); - while (line != null) { - conn.query(line); - line = reader.readLine(); - } + while (line != null) { + conn.query(line); + line = reader.readLine(); + } reader.close(); @@ -43,13 +40,14 @@ public static void loadData(String dbPath) throws IOException, KuzuObjectRefDest line = reader.readLine(); while (line != null) { - conn.query(line); - line = reader.readLine(); - } - - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } + line = line.replace("dataset/tinysnb", "../../dataset/tinysnb"); + conn.query(line); + line = reader.readLine(); + } + + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } } } diff --git a/tools/java_api/java_test/ValueTest.java b/tools/java_api/src/test/java/com/kuzudb/test/ValueTest.java similarity index 96% rename from tools/java_api/java_test/ValueTest.java rename to tools/java_api/src/test/java/com/kuzudb/test/ValueTest.java index 2dfe2e4ecd..9fc9ac85c9 100644 --- a/tools/java_api/java_test/ValueTest.java +++ b/tools/java_api/src/test/java/com/kuzudb/test/ValueTest.java @@ -1,8 +1,9 @@ -package tools.java_api.java_test; +package com.kuzudb.java_test; -import tools.java_api.*; +import com.kuzudb.*; import org.junit.jupiter.api.Test; + import static org.junit.jupiter.api.Assertions.*; import java.time.LocalDate; @@ -114,10 +115,10 @@ void ValueCreateBool() throws KuzuObjectRefDestroyedException { @Test void ValueCreateINT16() throws KuzuObjectRefDestroyedException { // INT16 - KuzuValue value = new KuzuValue((short)123); + KuzuValue value = new KuzuValue((short) 123); assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.INT16); - assertTrue(value.getValue().equals((short)123)); + assertTrue(value.getValue().equals((short) 123)); value.destroy(); } @@ -144,24 +145,24 @@ void ValueCreateINT64() throws KuzuObjectRefDestroyedException { @Test void ValueCreateFloat() throws KuzuObjectRefDestroyedException { // float - KuzuValue value = new KuzuValue((float)123.456); + KuzuValue value = new KuzuValue((float) 123.456); assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.FLOAT); - assertTrue(value.getValue().equals((float)123.456)); + assertTrue(value.getValue().equals((float) 123.456)); value.destroy(); } @Test void ValueCreateDouble() throws KuzuObjectRefDestroyedException { // double - KuzuValue value = new KuzuValue((float)123.456); + KuzuValue value = new KuzuValue((float) 123.456); assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.FLOAT); - assertTrue(value.getValue().equals((float)123.456)); + assertTrue(value.getValue().equals((float) 123.456)); value.destroy(); } - @Test + @Test void ValueCreateInternalID() throws KuzuObjectRefDestroyedException { // InternalID KuzuValue value = new KuzuValue(new KuzuInternalID(1, 123)); @@ -226,7 +227,7 @@ void ValueCreateDate() throws KuzuObjectRefDestroyedException { @Test void ValueCreateTimeStamp() throws KuzuObjectRefDestroyedException { // timestamp - KuzuValue value = new KuzuValue(Instant.ofEpochSecond(123/1000000L, 123 % 1000000 * 1000)); // 123 microseconds + KuzuValue value = new KuzuValue(Instant.ofEpochSecond(123 / 1000000L, 123 % 1000000 * 1000)); // 123 microseconds assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.TIMESTAMP); Instant stamp = value.getValue(); @@ -234,7 +235,7 @@ void ValueCreateTimeStamp() throws KuzuObjectRefDestroyedException { assertEquals(stamp.getNano(), 123000); value.destroy(); - value = new KuzuValue(Instant.ofEpochSecond(123123123L/1000000L, 123123123L % 1000000 * 1000)); + value = new KuzuValue(Instant.ofEpochSecond(123123123L / 1000000L, 123123123L % 1000000 * 1000)); assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.TIMESTAMP); stamp = value.getValue(); @@ -246,16 +247,12 @@ void ValueCreateTimeStamp() throws KuzuObjectRefDestroyedException { @Test void ValueCreateInterval() throws KuzuObjectRefDestroyedException { // interval - KuzuValue value = new KuzuValue(Duration.ofMillis(31795200003L)); + Duration inputDuration = Duration.ofMillis(31795200003L); + KuzuValue value = new KuzuValue(inputDuration); assertFalse(value.isOwnedByCPP()); assertEquals(value.getDataType().getID(), KuzuDataTypeID.INTERVAL); Duration interval = value.getValue(); - long month = (long) (interval.toDays() / 30.4167); - long day = interval.toDays() - (long) (month * 30.4167); - long micros = interval.minusDays(interval.toDays()).toMillis() * 1000; - assertEquals(month, 12); - assertEquals(day, 3); - assertEquals(micros, 3000); + assertEquals(interval.toMillis(), inputDuration.toMillis()); value.destroy(); } @@ -270,7 +267,7 @@ void ValueCreateString() throws KuzuObjectRefDestroyedException { value.destroy(); } - @Test + @Test void ValueClone() throws KuzuObjectRefDestroyedException { KuzuValue value = new KuzuValue("abcdefg"); assertFalse(value.isOwnedByCPP()); @@ -319,7 +316,7 @@ void ValueGetListSize() throws KuzuObjectRefDestroyedException { assertTrue(value.isOwnedByCPP()); assertFalse(value.isNull()); assertEquals(value.getListSize(), 2); - + value.destroy(); flatTuple.destroy(); result.destroy(); @@ -445,7 +442,7 @@ void ValueGetINT32() throws KuzuObjectRefDestroyedException { result.destroy(); } - @Test + @Test void ValueGetINT64() throws KuzuObjectRefDestroyedException { // INT64 KuzuQueryResult result = conn.query("MATCH (a:person) RETURN a.ID ORDER BY a.ID"); @@ -473,7 +470,7 @@ void ValueGetFloat() throws KuzuObjectRefDestroyedException { assertTrue(value.isOwnedByCPP()); assertFalse(value.isNull()); - assertTrue(value.getValue().equals((float)1.731)); + assertTrue(value.getValue().equals((float) 1.731)); value.destroy(); flatTuple.destroy(); result.destroy(); @@ -490,7 +487,7 @@ void ValueGetDouble() throws KuzuObjectRefDestroyedException { assertTrue(value.isOwnedByCPP()); assertFalse(value.isNull()); - assertTrue(value.getValue().equals((double)5.0)); + assertTrue(value.getValue().equals((double) 5.0)); value.destroy(); flatTuple.destroy(); result.destroy(); @@ -541,7 +538,7 @@ void ValueGetRelVal() throws KuzuObjectRefDestroyedException { assertTrue(label.equals("knows")); long size = rel.getPropertySize(); assertEquals(size, 5); - + rel.destroy(); value.destroy(); flatTuple.destroy(); @@ -560,7 +557,7 @@ void ValueGetDate() throws KuzuObjectRefDestroyedException { assertFalse(value.isNull()); LocalDate date = value.getValue(); - assertEquals((long)date.toEpochDay(), -25567L); + assertEquals((long) date.toEpochDay(), -25567L); value.destroy(); flatTuple.destroy(); result.destroy(); diff --git a/tools/java_api/test.java b/tools/java_api/test.java index 1edcac8adf..23ed8c87e8 100644 --- a/tools/java_api/test.java +++ b/tools/java_api/test.java @@ -1,4 +1,5 @@ package tools.java_api; +import com.kuzudb.*; import java.time.*; import java.io.BufferedReader; @@ -26,49 +27,50 @@ public static void deleteFolder(File folder) { } public static void main(String[] args) throws KuzuObjectRefDestroyedException { - + String db_path = "./test_db"; + deleteFolder(new File(db_path)); BufferedReader reader; - KuzuDatabase db = new KuzuDatabase("./nope/java_api_test_db", 0); + KuzuDatabase db = new KuzuDatabase(db_path, 0); KuzuConnection conn = new KuzuConnection(db); try { - reader = new BufferedReader(new FileReader("./../../dataset/tinysnb/schema.cypher")); + reader = new BufferedReader(new FileReader("../../dataset/tinysnb/schema.cypher")); String line = reader.readLine(); - while (line != null) { + System.out.println(line); conn.query(line); line = reader.readLine(); } reader.close(); - reader = new BufferedReader(new FileReader("./../../dataset/tinysnb/copy.cypher")); + reader = new BufferedReader(new FileReader("../../dataset/tinysnb/copy.cypher")); line = reader.readLine(); - while (line != null) { + line = line.replace("dataset/tinysnb", "../../dataset/tinysnb"); + System.out.println(line); conn.query(line); line = reader.readLine(); } - reader.close(); } catch (IOException e) { e.printStackTrace(); } - KuzuQueryResult result = conn.query("MATCH (a:person) RETURN a.fName, a.age ORDER BY a.fName"); + String query = "MATCH (a:person) RETURN a.fName, a.age ORDER BY a.fName"; + System.out.println(query); - KuzuFlatTuple row = result.getNext(); - System.out.println(row); - row.destroy(); + KuzuQueryResult result = conn.query(query); + System.out.println("error: " + result.getErrorMessage()); + System.out.println("tuples: " + result.getNumTuples()); - row = result.getNext(); - row.destroy(); - - result.destroy(); - - - KuzuValue value = new KuzuValue(Duration.ofMillis(31800000003L)); - Duration interval = value.getValue(); + while (result.hasNext()) { + KuzuFlatTuple row = result.getNext(); + System.out.println("row: " + row); + row.destroy(); + } + result.destroy(); + } } diff --git a/tools/java_api/third_party/junit-platform-console-standalone-1.9.3.jar b/tools/java_api/third_party/junit-platform-console-standalone-1.9.3.jar new file mode 100644 index 0000000000..f072f7a9b9 Binary files /dev/null and b/tools/java_api/third_party/junit-platform-console-standalone-1.9.3.jar differ