Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ jobs:
strategy:
matrix:
vsql:
- "0.0.3"
- "main"
runs-on: ubuntu-latest
steps:
Expand Down
55 changes: 17 additions & 38 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ All functions return NULL on connection failure or NULL input.
**Error Handling:**
- HTTP functions return NULL on curl-level failure (connection refused, DNS failure, timeout)
- `url_encode`/`url_decode` return NULL for NULL input or curl init failure
- Exceptions are caught and returned as `VEF_RESULT_ERROR`
- Exceptions are caught and surfaced as Warning 3200 via `result.warning()`

**Key Implementation Details:**
- Thread-local curl handles with connection keep-alive (`curl_easy_reset()` between calls)
Expand All @@ -83,66 +83,45 @@ All functions return NULL on connection failure or NULL input.
- Options JSON supports: `timeout` (int), `proxy`, `user_agent`, `ssl_cert`, `ssl_key`, `ssl_ca_bundle` (strings)

**Dependencies:**
- VillageSQL Extension Framework SDK (`<villagesql/extension.h>`)
- VillageSQL Extension Framework SDK (`<villagesql/vsql.h>`, Protocol V3)
- libcurl (system-provided)

**Code Organization:**
- File naming: lowercase with underscores (e.g., `vsql_http.cc`)
- Function naming: lowercase with underscores (e.g., `http_get_1_impl`)
- Variable naming: lowercase with underscores (e.g., `response_body`)

## VillageSQL Extension Framework (VEF) API Pattern
## VillageSQL Extension Framework (VEF) API Pattern — Protocol V3

This extension uses the Protocol V3 stable SDK (`<villagesql/vsql.h>`).

### Function Implementation Pattern

```cpp
void my_function_impl(vef_context_t* ctx,
vef_invalue_t* arg1, vef_invalue_t* arg2,
vef_vdf_result_t* result) {
// Check for NULL arguments
if (arg1->is_null || arg2->is_null) {
result->type = VEF_RESULT_NULL;
return;
}

// Access argument values
const char* str_value = arg1->str_value;
size_t str_len = arg1->str_len;

// Perform function logic
// ...
#include <villagesql/vsql.h>
using namespace vsql;

// Set result
result->type = VEF_RESULT_VALUE;
result->actual_len = result_length;
// Write to result->str_buf
void my_function_impl(StringArg arg1, StringArg arg2, StringResult result) {
if (arg1.is_null() || arg2.is_null()) { result.set_null(); return; }
std::string_view s1 = arg1.value();
// ...
result.set(output); // or result.set_length(n) after writing to result.buffer()
}
```

Typed argument wrappers: `StringArg`, `IntArg`, `RealArg`. Result wrappers: `StringResult`, `IntResult`, `RealResult`. Use `result.set_null()` for NULL, `result.warning("msg")` for soft errors (Warning 3200), `result.error("msg")` for hard errors (ERROR 3200).

### Function Registration Pattern

```cpp
#include <villagesql/extension.h>

using namespace villagesql::extension_builder;

VEF_GENERATE_ENTRY_POINTS(
make_extension("extension_name", "0.0.1")
make_extension()
.func(make_func<&my_function_impl>("my_function")
.returns(STRING) // or INT, etc.
.param(STRING) // add .param() for each parameter
.param(INT)
.buffer_size(1024) // max result size
.build())
.returns(STRING).param(STRING).param(INT).buffer_size(1024).build())
)
```

### Key Differences from Old MySQL UDF API:
- No separate init/main/deinit functions - single implementation function
- Arguments passed as `vef_invalue_t*` structs with `is_null`, `str_value`, `bin_value`, `int_value` fields
- Results set via `vef_vdf_result_t*` with `type`, `str_buf`, `bin_buf`, `actual_len` fields
- Function registration done declaratively in code using builder pattern
- No install.sql needed - functions registered at extension load time
Extension name and version come from `manifest.json`; `make_extension()` takes no arguments in V3.

## Testing

Expand Down
16 changes: 12 additions & 4 deletions cmake/FindVillageSQL.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,18 @@ set(_villagesql_found FALSE)
# Method 1: Use VillageSQL_BUILD_DIR for development builds
if(VillageSQL_BUILD_DIR AND NOT _villagesql_found)
# Look for staged SDK in build directory
file(GLOB _sdk_dirs "${VillageSQL_BUILD_DIR}/villagesql-extension-sdk-*")
file(GLOB _sdk_dirs_all "${VillageSQL_BUILD_DIR}/villagesql-extension-sdk-*")
set(_sdk_dirs "")
foreach(_d IN LISTS _sdk_dirs_all)
if(IS_DIRECTORY "${_d}")
list(APPEND _sdk_dirs "${_d}")
endif()
endforeach()
unset(_sdk_dirs_all)
if(_sdk_dirs)
list(SORT _sdk_dirs ORDER DESCENDING)
list(GET _sdk_dirs 0 _sdk_dir)
if(EXISTS "${_sdk_dir}/include/villagesql/extension.h")
if(EXISTS "${_sdk_dir}/include/villagesql/vsql.h")
set(VillageSQL_PREFIX "${_sdk_dir}")
set(VillageSQL_INCLUDE_DIR "${_sdk_dir}/include")
set(VillageSQL_CXX_FLAGS "-I${_sdk_dir}/include")
Expand Down Expand Up @@ -136,7 +144,7 @@ endif()

# Method 2: Use VillageSQL_SDK_DIR if explicitly set
if(VillageSQL_SDK_DIR AND NOT _villagesql_found)
if(EXISTS "${VillageSQL_SDK_DIR}/include/villagesql/extension.h")
if(EXISTS "${VillageSQL_SDK_DIR}/include/villagesql/vsql.h")
set(VillageSQL_PREFIX "${VillageSQL_SDK_DIR}")
set(VillageSQL_INCLUDE_DIR "${VillageSQL_SDK_DIR}/include")
set(VillageSQL_CXX_FLAGS "-I${VillageSQL_SDK_DIR}/include")
Expand Down Expand Up @@ -205,7 +213,7 @@ endif()
if(NOT _villagesql_found)
set(_default_prefix "$ENV{HOME}/.villagesql")

if(EXISTS "${_default_prefix}/include/villagesql/extension.h")
if(EXISTS "${_default_prefix}/include/villagesql/vsql.h")
set(VillageSQL_PREFIX "${_default_prefix}")
set(VillageSQL_INCLUDE_DIR "${_default_prefix}/include")
set(VillageSQL_CXX_FLAGS "-I${_default_prefix}/include")
Expand Down
Loading
Loading