diff --git a/.github/workflows/build-and-deploy.yml b/.github/workflows/build-and-deploy.yml index 307ec7adfe..4197692ece 100644 --- a/.github/workflows/build-and-deploy.yml +++ b/.github/workflows/build-and-deploy.yml @@ -207,9 +207,11 @@ jobs: build-java: if: ${{ github.event_name == 'schedule' || github.event.inputs.skipJava != 'true' }} + needs: [build-precompiled-bin] uses: ./.github/workflows/java-workflow.yml with: isNightly: ${{ github.event_name == 'schedule' || github.event.inputs.isNightly == 'true' }} + precompiledRunId: ${{ github.run_id }} secrets: inherit deploy-java: @@ -264,7 +266,17 @@ jobs: - name: Create Java JAR working-directory: tools/java_api run: | - ./gradlew build + ./gradlew build --stacktrace --info --warning-mode all --no-parallel --max-workers=1 + + - name: Upload Java test diagnostics + if: ${{ always() }} + uses: actions/upload-artifact@v4 + with: + name: java-test-diagnostics + path: | + tools/java_api/build/test-results/test + tools/java_api/build/reports/tests/test + tools/java_api/build/hs_err_pid*.log - name: Upload Java JAR uses: actions/upload-artifact@v4 diff --git a/.github/workflows/java-workflow.yml b/.github/workflows/java-workflow.yml index f746cb5911..d297531df2 100644 --- a/.github/workflows/java-workflow.yml +++ b/.github/workflows/java-workflow.yml @@ -1,24 +1,47 @@ name: Build Java Lib on: workflow_dispatch: + inputs: + precompiledRunId: + description: "Run ID of the precompiled-bin job whose artifacts should be used" + required: true + type: string workflow_call: inputs: isNightly: type: boolean required: true default: false + precompiledRunId: + type: string + required: true env: PIP_BREAK_SYSTEM_PACKAGES: 1 jobs: build-linux-java-x86_64: runs-on: ubuntu-latest + env: + LBUG_LINUX_VARIANT: compat + LBUG_JAVA_PRECOMPILED_DIR: ${{ github.workspace }}/precompiled-liblbug + LBUG_JAVA_PRECOMPILED_LIB_PATH: ${{ github.workspace }}/precompiled-liblbug/liblbug.a steps: - uses: actions/checkout@v4 - name: Update submodules run: git submodule update --init --recursive tools/java_api + - name: Download precompiled liblbug + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LBUG_LIB_KIND: static + LBUG_PRECOMPILED_RUN_ID: ${{ inputs.precompiledRunId }} + LBUG_TARGET_DIR: ${{ env.LBUG_JAVA_PRECOMPILED_DIR }} + run: | + rm -rf "$LBUG_TARGET_DIR" + ./scripts/download-liblbug.sh + - name: Install uv run: python3 -m pip install uv @@ -32,6 +55,8 @@ jobs: working-directory: scripts - name: Build Java lib for Linux + env: + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_JAVA_PRECOMPILED_LIB_PATH }} run: | make GEN=Ninja java @@ -41,13 +66,28 @@ jobs: path: tools/java_api/build/liblbug_java_native* build-linux-java-aarch64: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04-arm + env: + LBUG_LINUX_VARIANT: compat + LBUG_JAVA_PRECOMPILED_DIR: ${{ github.workspace }}/precompiled-liblbug + LBUG_JAVA_PRECOMPILED_LIB_PATH: ${{ github.workspace }}/precompiled-liblbug/liblbug.a steps: - uses: actions/checkout@v4 - name: Update submodules run: git submodule update --init --recursive tools/java_api + - name: Download precompiled liblbug + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LBUG_LIB_KIND: static + LBUG_PRECOMPILED_RUN_ID: ${{ inputs.precompiledRunId }} + LBUG_TARGET_DIR: ${{ env.LBUG_JAVA_PRECOMPILED_DIR }} + run: | + rm -rf "$LBUG_TARGET_DIR" + ./scripts/download-liblbug.sh + - name: Install uv run: python3 -m pip install uv @@ -61,6 +101,8 @@ jobs: working-directory: scripts - name: Build Java lib for Linux + env: + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_JAVA_PRECOMPILED_LIB_PATH }} run: make GEN=Ninja java - uses: actions/upload-artifact@v4 @@ -70,12 +112,26 @@ jobs: build-mac-java-arm: runs-on: macos-latest + env: + LBUG_JAVA_PRECOMPILED_DIR: ${{ github.workspace }}/precompiled-liblbug + LBUG_JAVA_PRECOMPILED_LIB_PATH: ${{ github.workspace }}/precompiled-liblbug/liblbug.a steps: - uses: actions/checkout@v4 - name: Update submodules run: git submodule update --init --recursive tools/java_api + - name: Download precompiled liblbug + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LBUG_LIB_KIND: static + LBUG_PRECOMPILED_RUN_ID: ${{ inputs.precompiledRunId }} + LBUG_TARGET_DIR: ${{ env.LBUG_JAVA_PRECOMPILED_DIR }} + run: | + rm -rf "$LBUG_TARGET_DIR" + ./scripts/download-liblbug.sh + - name: Install uv run: pip3 install uv @@ -89,11 +145,12 @@ jobs: working-directory: scripts - name: Build Java lib for Apple Silicon - run: | - arch -arm64 env JAVA_HOME=$(/usr/libexec/java_home) make GEN=Ninja java env: + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_JAVA_PRECOMPILED_LIB_PATH }} MACOSX_DEPLOYMENT_TARGET: 13.3 ARCHFLAGS: "-arch arm64" + run: | + arch -arm64 env JAVA_HOME=$(/usr/libexec/java_home) make GEN=Ninja java - uses: actions/upload-artifact@v4 with: @@ -102,12 +159,26 @@ jobs: build-windows-java: runs-on: windows-latest + env: + LBUG_JAVA_PRECOMPILED_DIR: ${{ github.workspace }}/precompiled-liblbug + LBUG_JAVA_PRECOMPILED_LIB_PATH: ${{ github.workspace }}/precompiled-liblbug/lbug.lib steps: - uses: actions/checkout@v4 - name: Update submodules run: git submodule update --init --recursive tools/java_api + - name: Download precompiled liblbug + shell: bash + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + LBUG_LIB_KIND: static + LBUG_PRECOMPILED_RUN_ID: ${{ inputs.precompiledRunId }} + LBUG_TARGET_DIR: ${{ env.LBUG_JAVA_PRECOMPILED_DIR }} + run: | + rm -rf "$LBUG_TARGET_DIR" + ./scripts/download-liblbug.sh + - name: Install uv run: pip3 install uv @@ -127,6 +198,8 @@ jobs: - name: Build Java lib for Windows shell: cmd + env: + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_JAVA_PRECOMPILED_LIB_PATH }} run: | powershell.exe -Command "Add-MpPreference -ExclusionPath '${{ github.workspace }}'" call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" @@ -135,4 +208,4 @@ jobs: - uses: actions/upload-artifact@v4 with: name: java-lib-win-x86_64 - path: tools/java_api/build/liblbug_java_native* \ No newline at end of file + path: tools/java_api/build/liblbug_java_native* diff --git a/.github/workflows/nodejs-workflow.yml b/.github/workflows/nodejs-workflow.yml index 5b6c92deb6..7329669f4b 100644 --- a/.github/workflows/nodejs-workflow.yml +++ b/.github/workflows/nodejs-workflow.yml @@ -162,7 +162,7 @@ jobs: if: ${{ matrix.platform == 'win32' }} shell: cmd env: - EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_NODEJS_USE_PRECOMPILED_LIB=TRUE -DLBUG_NODEJS_PRECOMPILED_LIB_PATH=${{ env.LBUG_NODEJS_PRECOMPILED_LIB_PATH }} + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_NODEJS_PRECOMPILED_LIB_PATH }} run: | powershell.exe -Command "Add-MpPreference -ExclusionPath '${{ github.workspace }}'" call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat" @@ -175,7 +175,7 @@ jobs: env: CMAKE_C_COMPILER_LAUNCHER: ccache CMAKE_CXX_COMPILER_LAUNCHER: ccache - EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_NODEJS_USE_PRECOMPILED_LIB=TRUE -DLBUG_NODEJS_PRECOMPILED_LIB_PATH=${{ env.LBUG_NODEJS_PRECOMPILED_LIB_PATH }} + EXTRA_CMAKE_FLAGS: -DBUILD_LBUG=FALSE -DBUILD_SHELL=FALSE -DLBUG_API_USE_PRECOMPILED_LIB=TRUE -DLBUG_API_PRECOMPILED_LIB_PATH=${{ env.LBUG_NODEJS_PRECOMPILED_LIB_PATH }} run: | ccache -s make GEN=Ninja nodejs diff --git a/CMakeLists.txt b/CMakeLists.txt index a4172c1c21..52ecd17d29 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -331,14 +331,26 @@ option(BUILD_PYTHON "Build Python API." FALSE) option(BUILD_SHELL "Build Interactive Shell" TRUE) option(BUILD_SINGLE_FILE_HEADER "Build single file header. Requires Python >= 3.9." TRUE) option(BUILD_LBUG "Build Lbug." TRUE) -option(LBUG_NODEJS_USE_PRECOMPILED_LIB "Link the Node.js addon against a precompiled static liblbug archive." FALSE) -set(LBUG_NODEJS_PRECOMPILED_LIB_PATH "" CACHE FILEPATH "Path to the precompiled static liblbug archive used by the Node.js addon.") +option(LBUG_API_USE_PRECOMPILED_LIB "Link language bindings against a precompiled static liblbug archive." FALSE) +set(LBUG_API_PRECOMPILED_LIB_PATH "" CACHE FILEPATH "Path to the precompiled static liblbug archive used by language bindings.") +option(LBUG_NODEJS_USE_PRECOMPILED_LIB "Deprecated alias for LBUG_API_USE_PRECOMPILED_LIB." FALSE) +set(LBUG_NODEJS_PRECOMPILED_LIB_PATH "" CACHE FILEPATH "Deprecated alias for LBUG_API_PRECOMPILED_LIB_PATH.") option(ENABLE_BACKTRACES "Enable backtrace printing for exceptions and segfaults" FALSE) option(PREFER_SYSTEM_DEPS "Only download certain deps if not found on the system" TRUE) if(LBUG_NODEJS_USE_PRECOMPILED_LIB) + set(LBUG_API_USE_PRECOMPILED_LIB TRUE) +endif() +if(LBUG_NODEJS_PRECOMPILED_LIB_PATH AND NOT LBUG_API_PRECOMPILED_LIB_PATH) + set(LBUG_API_PRECOMPILED_LIB_PATH "${LBUG_NODEJS_PRECOMPILED_LIB_PATH}") +endif() +if(LBUG_API_USE_PRECOMPILED_LIB) + set(LBUG_NODEJS_USE_PRECOMPILED_LIB TRUE CACHE BOOL "Deprecated alias for LBUG_API_USE_PRECOMPILED_LIB." FORCE) set(BUILD_LBUG FALSE CACHE BOOL "Build Lbug." FORCE) endif() +if(LBUG_API_PRECOMPILED_LIB_PATH) + set(LBUG_NODEJS_PRECOMPILED_LIB_PATH "${LBUG_API_PRECOMPILED_LIB_PATH}" CACHE FILEPATH "Deprecated alias for LBUG_API_PRECOMPILED_LIB_PATH." FORCE) +endif() option(BUILD_LCOV "Build coverage report." FALSE) if(${BUILD_LCOV}) @@ -405,7 +417,7 @@ function(add_lbug_api_test TEST_NAME) endfunction() # Windows doesn't support dynamic lookup, so we have to link extensions against lbug. -if (MSVC AND (NOT BUILD_EXTENSIONS EQUAL "") AND NOT LBUG_NODEJS_USE_PRECOMPILED_LIB) +if (MSVC AND (NOT BUILD_EXTENSIONS EQUAL "") AND NOT LBUG_API_USE_PRECOMPILED_LIB) set(BUILD_LBUG TRUE) endif () diff --git a/src/c_api/connection.cpp b/src/c_api/connection.cpp index ab70353174..66e884313f 100644 --- a/src/c_api/connection.cpp +++ b/src/c_api/connection.cpp @@ -1,3 +1,4 @@ +#include "c_api/helpers.h" #include "c_api/lbug.h" #include "common/exception/exception.h" #include "main/lbug.h" @@ -66,6 +67,7 @@ lbug_state lbug_connection_query(lbug_connection* connection, const char* query, return LbugError; } try { + clearLastCAPIErrorMessage(); auto query_result = static_cast(connection->_connection)->query(query).release(); if (query_result == nullptr) { @@ -78,6 +80,7 @@ lbug_state lbug_connection_query(lbug_connection* connection, const char* query, } return LbugSuccess; } catch (Exception& e) { + setLastCAPIErrorMessage(e.what()); return LbugError; } } @@ -88,6 +91,7 @@ lbug_state lbug_connection_prepare(lbug_connection* connection, const char* quer return LbugError; } try { + clearLastCAPIErrorMessage(); auto prepared_statement = static_cast(connection->_connection)->prepare(query).release(); if (prepared_statement == nullptr) { @@ -98,6 +102,7 @@ lbug_state lbug_connection_prepare(lbug_connection* connection, const char* quer new std::unordered_map>; return LbugSuccess; } catch (Exception& e) { + setLastCAPIErrorMessage(e.what()); return LbugError; } return LbugSuccess; @@ -111,6 +116,7 @@ lbug_state lbug_connection_execute(lbug_connection* connection, return LbugError; } try { + clearLastCAPIErrorMessage(); auto prepared_statement_ptr = static_cast(prepared_statement->_prepared_statement); auto bound_values = static_cast>*>( @@ -137,6 +143,7 @@ lbug_state lbug_connection_execute(lbug_connection* connection, } return LbugSuccess; } catch (Exception& e) { + setLastCAPIErrorMessage(e.what()); return LbugError; } } diff --git a/src/c_api/data_type.cpp b/src/c_api/data_type.cpp index 37c57ca848..1110f1368d 100644 --- a/src/c_api/data_type.cpp +++ b/src/c_api/data_type.cpp @@ -55,6 +55,25 @@ lbug_data_type_id lbug_data_type_get_id(lbug_logical_type* data_type) { return static_cast(data_type_id_u8); } +lbug_state lbug_data_type_get_child_type(lbug_logical_type* data_type, + lbug_logical_type* out_result) { + auto* parent_type = static_cast(data_type->_data_type); + try { + switch (parent_type->getLogicalTypeID()) { + case LogicalTypeID::ARRAY: + out_result->_data_type = new LogicalType(ArrayType::getChildType(*parent_type).copy()); + return LbugSuccess; + case LogicalTypeID::LIST: + out_result->_data_type = new LogicalType(ListType::getChildType(*parent_type).copy()); + return LbugSuccess; + default: + return LbugError; + } + } catch (Exception& e) { + return LbugError; + } +} + lbug_state lbug_data_type_get_num_elements_in_array(lbug_logical_type* data_type, uint64_t* out_result) { auto parent_type = static_cast(data_type->_data_type); diff --git a/src/c_api/database.cpp b/src/c_api/database.cpp index 80c60689dd..c759f4caa4 100644 --- a/src/c_api/database.cpp +++ b/src/c_api/database.cpp @@ -1,3 +1,4 @@ +#include "c_api/helpers.h" #include "c_api/lbug.h" #include "common/exception/exception.h" #include "main/lbug.h" @@ -7,10 +8,12 @@ using namespace lbug::common; lbug_state lbug_database_init(const char* database_path, lbug_system_config config, lbug_database* out_database) { try { + clearLastCAPIErrorMessage(); std::string database_path_str = database_path; auto systemConfig = SystemConfig(config.buffer_pool_size, config.max_num_threads, config.enable_compression, config.read_only, config.max_db_size, config.auto_checkpoint, - config.checkpoint_threshold); + config.checkpoint_threshold, true, config.throw_on_wal_replay_failure, + config.enable_checksums); #if defined(__APPLE__) systemConfig.threadQos = config.thread_qos; @@ -18,6 +21,7 @@ lbug_state lbug_database_init(const char* database_path, lbug_system_config conf out_database->_database = new Database(database_path_str, systemConfig); } catch (Exception& e) { out_database->_database = nullptr; + setLastCAPIErrorMessage(e.what()); return LbugError; } return LbugSuccess; @@ -42,6 +46,8 @@ lbug_system_config lbug_default_system_config() { cSystemConfig.max_db_size = config.maxDBSize; cSystemConfig.auto_checkpoint = config.autoCheckpoint; cSystemConfig.checkpoint_threshold = config.checkpointThreshold; + cSystemConfig.throw_on_wal_replay_failure = config.throwOnWalReplayFailure; + cSystemConfig.enable_checksums = config.enableChecksums; #if defined(__APPLE__) cSystemConfig.thread_qos = config.threadQos; #endif diff --git a/src/c_api/helpers.cpp b/src/c_api/helpers.cpp index 4eb8955dd1..9f0ded2b59 100644 --- a/src/c_api/helpers.cpp +++ b/src/c_api/helpers.cpp @@ -2,6 +2,12 @@ #include +#include "c_api/lbug.h" + +namespace { +thread_local std::string lastCAPIErrorMessage; +} + #ifdef _WIN32 const uint64_t NS_TO_SEC = 10000000ULL; const uint64_t SEC_TO_UNIX_EPOCH = 11644473600ULL; @@ -45,6 +51,23 @@ int32_t convertTimeToTm(time_t time, struct tm* out_tm) { } #endif +void setLastCAPIErrorMessage(const std::string& message) { + lastCAPIErrorMessage = message; +} + +void clearLastCAPIErrorMessage() { + lastCAPIErrorMessage.clear(); +} + +char* takeLastCAPIErrorMessage() { + if (lastCAPIErrorMessage.empty()) { + return nullptr; + } + auto* message = convertToOwnedCString(lastCAPIErrorMessage); + lastCAPIErrorMessage.clear(); + return message; +} + char* convertToOwnedCString(const std::string& str) { size_t src_len = str.size(); auto* c_str = (char*)malloc(sizeof(char) * (src_len + 1)); @@ -52,3 +75,7 @@ char* convertToOwnedCString(const std::string& str) { c_str[src_len] = '\0'; return c_str; } + +char* lbug_get_last_error() { + return takeLastCAPIErrorMessage(); +} diff --git a/src/c_api/query_result.cpp b/src/c_api/query_result.cpp index bb3f77aae7..d6108f4572 100644 --- a/src/c_api/query_result.cpp +++ b/src/c_api/query_result.cpp @@ -96,11 +96,13 @@ lbug_state lbug_query_result_get_next_query_result(lbug_query_result* query_resu lbug_state lbug_query_result_get_next(lbug_query_result* query_result, lbug_flat_tuple* out_flat_tuple) { try { + clearLastCAPIErrorMessage(); auto flat_tuple = static_cast(query_result->_query_result)->getNext(); out_flat_tuple->_flat_tuple = flat_tuple.get(); out_flat_tuple->_is_owned_by_cpp = true; return LbugSuccess; } catch (Exception& e) { + setLastCAPIErrorMessage(e.what()); return LbugError; } } diff --git a/src/c_api/value.cpp b/src/c_api/value.cpp index 3cbc358e84..73f0f2cfe1 100644 --- a/src/c_api/value.cpp +++ b/src/c_api/value.cpp @@ -113,6 +113,31 @@ lbug_value* lbug_value_create_double(double val_) { return c_value; } +lbug_value* lbug_value_create_decimal(const char* val_, uint32_t precision, uint32_t scale) { + auto* c_value = (lbug_value*)calloc(1, sizeof(lbug_value)); + auto decimalType = LogicalType::DECIMAL(precision, scale); + auto value = Value::createDefaultValue(decimalType); + switch (decimalType.getPhysicalType()) { + case PhysicalTypeID::INT16: + lbug::function::decimalCast(val_, strlen(val_), value.val.int16Val, decimalType); + break; + case PhysicalTypeID::INT32: + lbug::function::decimalCast(val_, strlen(val_), value.val.int32Val, decimalType); + break; + case PhysicalTypeID::INT64: + lbug::function::decimalCast(val_, strlen(val_), value.val.int64Val, decimalType); + break; + case PhysicalTypeID::INT128: + lbug::function::decimalCast(val_, strlen(val_), value.val.int128Val, decimalType); + break; + default: + free(c_value); + return nullptr; + } + c_value->_value = new Value(std::move(value)); + return c_value; +} + lbug_value* lbug_value_create_internal_id(lbug_internal_id_t val_) { auto* c_value = (lbug_value*)calloc(1, sizeof(lbug_value)); internalID_t id(val_.offset, val_.table_id); @@ -175,6 +200,13 @@ lbug_value* lbug_value_create_string(const char* val_) { return c_value; } +lbug_value* lbug_value_create_uuid(const char* val_) { + auto* c_value = (lbug_value*)calloc(1, sizeof(lbug_value)); + c_value->_value = + new Value(lbug::common::uuid{lbug::common::UUID::fromCString(val_, strlen(val_))}); + return c_value; +} + lbug_state lbug_value_create_list(uint64_t num_elements, lbug_value** elements, lbug_value** out_value) { if (num_elements == 0) { @@ -345,6 +377,22 @@ lbug_state lbug_value_get_struct_field_name(lbug_value* value, uint64_t index, c return LbugSuccess; } +lbug_state lbug_value_get_struct_field_index(lbug_value* value, const char* field_name, + uint64_t* out_result) { + auto physical_type_id = static_cast(value->_value)->getDataType().getPhysicalType(); + if (physical_type_id != PhysicalTypeID::STRUCT) { + return LbugError; + } + auto val = static_cast(value->_value); + const auto& data_type = val->getDataType(); + auto index = StructType::getFieldIdx(data_type, field_name); + if (index == INVALID_STRUCT_FIELD_IDX) { + return LbugError; + } + *out_result = index; + return LbugSuccess; +} + lbug_state lbug_value_get_struct_field_value(lbug_value* value, uint64_t index, lbug_value* out_value) { return lbug_value_get_list_element(value, index, out_value); @@ -755,8 +803,7 @@ lbug_state lbug_value_get_uuid(lbug_value* value, char** out_result) { return LbugError; } try { - *out_result = - convertToOwnedCString(static_cast(value->_value)->getValue()); + *out_result = convertToOwnedCString(static_cast(value->_value)->toString()); } catch (Exception& e) { return LbugError; } diff --git a/src/include/c_api/helpers.h b/src/include/c_api/helpers.h index 21b386ab45..4d3e7cdbad 100644 --- a/src/include/c_api/helpers.h +++ b/src/include/c_api/helpers.h @@ -12,4 +12,10 @@ time_t convertTmToTime(struct tm tm); int32_t convertTimeToTm(time_t time, struct tm* out_tm); #endif +void setLastCAPIErrorMessage(const std::string& message); + +void clearLastCAPIErrorMessage(); + +char* takeLastCAPIErrorMessage(); + char* convertToOwnedCString(const std::string& str); diff --git a/src/include/c_api/lbug.h b/src/include/c_api/lbug.h index c5d6cbac10..1e0a924303 100644 --- a/src/include/c_api/lbug.h +++ b/src/include/c_api/lbug.h @@ -132,6 +132,10 @@ typedef struct { // The threshold of the WAL file size in bytes. When the size of the // WAL file exceeds this threshold, the database will checkpoint if auto_checkpoint is true. uint64_t checkpoint_threshold; + // If true, any WAL replay failure when loading the database will raise an error. + bool throw_on_wal_replay_failure; + // If true, checksums are enabled for WAL and storage pages. + bool enable_checksums; #if defined(__APPLE__) // The thread quality of service (QoS) for the worker threads. @@ -807,6 +811,14 @@ LBUG_C_API bool lbug_data_type_equals(lbug_logical_type* data_type1, lbug_logica * @param data_type The data type instance to return. */ LBUG_C_API lbug_data_type_id lbug_data_type_get_id(lbug_logical_type* data_type); +/** + * @brief Returns the child type of the given ARRAY or LIST data type. + * @param data_type The ARRAY or LIST data type instance. + * @param[out] out_result The output parameter that will hold the child type. + * @return The state indicating the success or failure of the operation. + */ +LBUG_C_API lbug_state lbug_data_type_get_child_type(lbug_logical_type* data_type, + lbug_logical_type* out_result); /** * @brief Returns the number of elements for array. * @param data_type The data type instance to return. @@ -916,6 +928,15 @@ LBUG_C_API lbug_value* lbug_value_create_float(float val_); * @param val_ The double value of the value to create. */ LBUG_C_API lbug_value* lbug_value_create_double(double val_); +/** + * @brief Creates a value with decimal type and the given string representation. + * Caller is responsible for destroying the returned value. + * @param val_ The decimal value to create. + * @param precision The decimal precision. + * @param scale The decimal scale. + */ +LBUG_C_API lbug_value* lbug_value_create_decimal(const char* val_, uint32_t precision, + uint32_t scale); /** * @brief Creates a value with internal_id type and the given internal_id value. Caller is * responsible for destroying the returned value. @@ -970,6 +991,12 @@ LBUG_C_API lbug_value* lbug_value_create_interval(lbug_interval_t val_); * @param val_ The string value of the value to create. */ LBUG_C_API lbug_value* lbug_value_create_string(const char* val_); +/** + * @brief Creates a value with UUID type and the given string representation. + * Caller is responsible for destroying the returned value. + * @param val_ The UUID string value to create. + */ +LBUG_C_API lbug_value* lbug_value_create_uuid(const char* val_); /** * @brief Creates a list value with the given number of elements and the given elements. * The caller needs to make sure that all elements have the same type. @@ -1062,6 +1089,15 @@ LBUG_C_API lbug_state lbug_value_get_struct_num_fields(lbug_value* value, uint64 */ LBUG_C_API lbug_state lbug_value_get_struct_field_name(lbug_value* value, uint64_t index, char** out_result); +/** + * @brief Returns the field index for the given field name in the given struct value. + * @param value The STRUCT value to inspect. + * @param field_name The field name to look up. + * @param[out] out_result The output parameter that will hold the field index. + * @return The state indicating the success or failure of the operation. + */ +LBUG_C_API lbug_state lbug_value_get_struct_field_index(lbug_value* value, const char* field_name, + uint64_t* out_result); /** * @brief Returns the field value at index of the given struct value. The value must be of physical * type STRUCT (STRUCT, NODE, REL, RECURSIVE_REL, UNION). @@ -1585,4 +1621,12 @@ LBUG_C_API char* lbug_get_version(); * @brief Returns the storage version of the Lbug library. */ LBUG_C_API uint64_t lbug_get_storage_version(); + +// Error handling +/** + * @brief Returns the last error message set by the C API, consuming it (subsequent calls return + * nullptr until another error occurs). The caller is responsible for freeing the returned string + * using lbug_destroy_string(). Returns nullptr if no error has been recorded. + */ +LBUG_C_API char* lbug_get_last_error(); #undef LBUG_C_API diff --git a/tools/java_api b/tools/java_api index 9db2465450..166d5e2f13 160000 --- a/tools/java_api +++ b/tools/java_api @@ -1 +1 @@ -Subproject commit 9db2465450b5a36e6cad275de6cdc477acc35423 +Subproject commit 166d5e2f139f5075be6974c24ab8e286810713ff