diff --git a/CN/modules/ROOT/nav.adoc b/CN/modules/ROOT/nav.adoc index 4b4aab6..dfc0950 100644 --- a/CN/modules/ROOT/nav.adoc +++ b/CN/modules/ROOT/nav.adoc @@ -38,6 +38,7 @@ **** xref:master/ecosystem_components/system_stats.adoc[system_stats] **** xref:master/ecosystem_components/wal2json.adoc[wal2json] **** xref:master/ecosystem_components/pg_stat_monitor.adoc[pg_stat_monitor] +**** xref:master/ecosystem_components/pg_curl.adoc[pg_curl] ** IvorySQL架构设计 *** 查询处理 **** xref:master/architecture/dual_parser.adoc[双parser] diff --git a/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc b/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc index e593a91..e8c6594 100644 --- a/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc +++ b/CN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc @@ -23,6 +23,7 @@ IvorySQL 作为一款兼容 Oracle 且基于 PostgreSQL 的高级开源数据库 | 10 | xref:master/ecosystem_components/system_stats.adoc[system_stats] | 3.2 | 提供用于访问系统级统计信息的函数 | 系统监控 | 11 | xref:master/ecosystem_components/pg_ai_query.adoc[pg_ai_query] | 0.1.1 | AI驱动的自然语言转SQL扩展,支持多种大语言模型 | AI辅助查询、自然语言数据库交互 | 12 | xref:master/ecosystem_components/pg_stat_monitor.adoc[pg_stat_monitor] | 2.3.1 | 收集性能统计数据,并通过统一视图和直方图形式直观展示查询性能指标。 | 性能监控 +| 13 | xref:master/ecosystem_components/pg_curl.adoc[pg_curl] | 2.4 | 基于 libcurl 的网络传输扩展,支持 HTTP/HTTPS、FTP、SMTP、IMAP 等二十余种协议,可在 SQL 中完成各类网络数据传输操作 | REST API 集成、邮件发送、文件传输、外部系统通知 |==== 这些插件均经过 IvorySQL 团队的测试和适配,确保在 IvorySQL 环境下稳定运行。用户可以根据业务需求选择合适的插件,进一步提升数据库系统的能力和灵活性。 diff --git a/CN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc b/CN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc new file mode 100644 index 0000000..68256fd --- /dev/null +++ b/CN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc @@ -0,0 +1,200 @@ + +:sectnums: +:sectnumlevels: 5 + += pg_curl + +== 概述 + +pg_curl 是一个基于 libcurl 的 PostgreSQL 扩展,它将 cURL 的强大数据传输能力直接引入数据库内部,允许用户通过 SQL 函数调用完成各种网络协议的数据传输操作,无需借助外部程序或中间件。 + +与只支持 HTTP 的轻量级扩展不同,pg_curl 全面封装了 libcurl 的 easy interface API,支持 DICT、FILE、FTP、FTPS、GOPHER、HTTP、HTTPS、IMAP、IMAPS、LDAP、LDAPS、MQTT、POP3、POP3S、RTMP、RTMPS、RTSP、SCP、SFTP、SMB、SMBS、SMTP、SMTPS、TELNET、TFTP、WS 和 WSS 等二十余种协议,提供了极为丰富的网络交互能力。 + +典型应用场景包括:在触发器或存储过程中向外部系统发送 HTTP 通知;直接从数据库发送邮件;通过 FTP/SFTP 上传或下载文件;调用第三方 REST API 并将结果写回数据库表;以及在数据处理流程中与 MQTT 消息代理、LDAP 目录等各类后端服务进行集成。 + +pg_curl 采用 MIT 许可证,项目地址:https://github.com/RekGRpth/pg_curl 。 + +== 功能特点 + +* *多协议支持*:基于 libcurl,支持 HTTP/HTTPS、FTP/FTPS、SMTP/SMTPS、IMAP、POP3、SCP、SFTP、MQTT、LDAP 等二十余种协议,覆盖绝大多数网络集成场景。 +* *完整的 HTTP 方法支持*:支持 GET、POST(URL 编码、JSON、multipart/form-data)、PUT、DELETE、PATCH 等标准 HTTP 方法,并可通过 `curl_easy_setopt_customrequest` 指定任意自定义方法。 +* *灵活的请求构造*:提供细粒度的 `curl_easy_setopt_*` 系列函数,可精确控制请求头、认证信息、超时、代理、TLS 证书、Cookie 等各项参数。 +* *多种认证方式*:支持 Basic Auth(用户名/密码)、Bearer Token、NTLM、Digest、OAuth 等多种认证机制。 +* *文件传输*:支持通过 FTP/FTPS/SFTP/SCP 上传(`curl_easy_setopt_readdata`)和下载文件,上传数据以 `bytea` 类型直接传入。 +* *邮件发送*:通过 SMTP/SMTPS 直接在数据库内发送邮件,支持设置发件人、收件人、邮件头及 MIME 正文。 +* *响应解析*:提供 `curl_easy_getinfo_data_in()`、`curl_easy_getinfo_header_in()` 等函数获取响应体和响应头,并可通过正则表达式将头信息解析为键值表。 +* *错误处理*:`curl_easy_getinfo_errcode()`、`curl_easy_getinfo_errdesc()` 及 `curl_easy_getinfo_errbuf()` 提供完整的错误码和错误描述,便于调试。 +* *超时与中断*:通过向 libcurl 注册进度回调并周期性检查 PostgreSQL 的取消标志(`QueryCancelPending`),支持被 `statement_timeout`、`pg_cancel_backend()` 等方式中断,防止长时间请求阻塞连接。 +* *URL 编码工具*:内置 `curl_easy_escape()` 和 `curl_easy_unescape()` 函数,方便在 SQL 中进行 URL 编码和解码。 + +== 安装 + +IvorySQL 的 RPM/DEB 安装包目前未内置 pg_curl,需要从源码编译安装。 + +[TIP] +以下示例环境为 Ubuntu 24.04(x86_64),已安装 IvorySQL 5 及以上版本,安装路径为 `/usr/local/ivorysql/ivorysql-5`。 + +=== 安装依赖 + +pg_curl 依赖系统的 libcurl 开发库,安装前需确认已安装该依赖: + +[source,shell] +---- +sudo apt install libcurl4-openssl-dev +---- + +=== 源码编译安装 + +从 https://github.com/RekGRpth/pg_curl 获取源码,然后执行编译安装: + +[source,shell] +---- +git clone https://github.com/RekGRpth/pg_curl.git +cd pg_curl +# 确保 pg_config 可访问,或通过 PG_CONFIG 显式指定 +PG_CONFIG=/usr/local/ivorysql/ivorysql-5/bin/pg_config make +PG_CONFIG=/usr/local/ivorysql/ivorysql-5/bin/pg_config make install +---- + +安装成功后,`pg_curl.so` 及对应的 SQL 脚本会被放置到 IvorySQL 的扩展目录中。 + +== 创建 Extension 并验证版本 + +使用 psql 连接到数据库(PG 模式端口 5432 或 Oracle 模式端口 1521 均可),执行如下命令: + +[source,sql] +---- +CREATE EXTENSION pg_curl; + +SELECT name, default_version, installed_version, comment + FROM pg_available_extensions + WHERE name = 'pg_curl'; +---- + +预期输出类似: + +[source,text] +---- + name | default_version | installed_version | comment +---------+-----------------+-------------------+---------------------------------------------------------------------------------------------------------------------------------------- + pg_curl | 2.4 | 2.4 | PostgreSQL cURL allows most curl actions, including data transfer with URL syntax via HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, ... +(1 row) +---- + +== 使用 + +pg_curl 采用"先配置、再执行、后取结果"的调用模式,核心流程如下: + +. 调用 `curl_easy_reset()` 初始化(或重置)当前 cURL 会话。 +. 调用各 `curl_easy_setopt_*`、`curl_header_append`、`curl_postfield_append` 等函数配置请求参数。 +. 调用 `curl_easy_perform()` 执行请求。 +. 调用 `curl_easy_getinfo_*` 系列函数获取响应结果或错误信息。 + +=== HTTP GET + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/get?'); +SELECT curl_url_append('key1', 'value1'); +SELECT curl_url_append('key2', 'hello world'); -- 自动 URL 编码 +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8'); +END; +---- + +=== HTTP POST(JSON) + +POST 表单(`curl_postfield_append`)和 multipart(`curl_mime_data`)的用法与此类似,替换数据设置函数即可。 + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_postfields(convert_to('{"name":"IvorySQL"}', 'utf-8')); +SELECT curl_easy_setopt_url('https://httpbin.org/post'); +SELECT curl_header_append('Content-Type', 'application/json; charset=utf-8'); +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8'); +END; +---- + +=== 认证与请求头 + +Basic Auth 使用 `curl_easy_setopt_username` / `curl_easy_setopt_password`;Bearer Token 及其他自定义头均通过 `curl_header_append` 添加: + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/bearer'); +SELECT curl_header_append('Authorization', 'Bearer '); +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8')::jsonb; +END; +---- + +=== 错误处理与超时 + +`curl_easy_perform()` 成功返回后,可通过以下函数检查执行状态(`errcode` 为 0 表示成功): + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/get'); +SELECT curl_easy_perform(); +SELECT + curl_easy_getinfo_errcode() AS errcode, + curl_easy_getinfo_errdesc() AS errdesc; +END; +---- + +pg_curl 通过 libcurl 进度回调检查 PostgreSQL 取消标志,`statement_timeout` 触发时请求会被立即中止并回滚当前事务: + +[source,sql] +---- +BEGIN; +SET LOCAL statement_timeout = '3s'; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/delay/10'); +SELECT curl_easy_perform(); -- 超时后抛出 query_canceled,事务回滚 +END; +---- + +== IvorySQL 适配说明 + +=== 双端口兼容 + +IvorySQL 采用双端口架构,同时支持 PostgreSQL 模式(默认端口 *5432*)和 Oracle 兼容模式(默认端口 *1521*): + +* 连接 *5432* 端口(PG 模式):接受标准 PostgreSQL SQL 语法。 +* 连接 *1521* 端口(Oracle 模式):接受 Oracle 兼容 SQL 语法。 + +pg_curl 在两种模式下均可正常使用,`CREATE EXTENSION pg_curl` 在 1521 和 5432 端口均能成功执行。 + +=== Oracle 模式注意事项 + +在 Oracle 模式(1521 端口)下使用 pg_curl 时,以下几点需要注意: + +* pg_curl 的所有函数均通过普通 `SELECT` 语句调用(如 `SELECT curl_easy_reset()`),在 Oracle 模式下同样有效;也可以使用 Oracle 惯用的 `SELECT curl_easy_reset() FROM DUAL` 写法。 +* `ivorysql.enable_emptystring_to_NULL` 参数会影响空字符串的处理行为。回归测试中已设置 `SET ivorysql.enable_emptystring_to_NULL = 'off'` 以确保空值参数(如空表单字段)按预期传递,生产环境中需根据实际需求配置该参数。 + +=== 在 PL/iSQL 中使用 + +pg_curl 可在 IvorySQL 的 PL/iSQL(Oracle 兼容存储过程语言)中调用,实现数据变更时自动推送外部通知。PL/iSQL 使用 Oracle 风格的 `IS` 关键字声明存储过程,调用返回值的函数时通过赋值给局部变量来丢弃结果: + +[source,sql] +---- +-- 在 PL/iSQL 存储过程中调用 pg_curl(Oracle 模式,IS 语法) +CREATE OR REPLACE PROCEDURE notify_external(p_payload IN VARCHAR2) IS + v_ok BOOLEAN; +BEGIN + v_ok := curl_easy_reset(); + v_ok := curl_easy_setopt_postfields(convert_to(p_payload, 'utf-8')); + v_ok := curl_easy_setopt_url('https://hooks.example.com/notify'); + v_ok := curl_header_append('Content-Type', 'application/json'); + v_ok := curl_easy_perform(); +END; +---- diff --git a/EN/modules/ROOT/nav.adoc b/EN/modules/ROOT/nav.adoc index d7f95c0..a0e9348 100644 --- a/EN/modules/ROOT/nav.adoc +++ b/EN/modules/ROOT/nav.adoc @@ -37,6 +37,7 @@ *** xref:master/ecosystem_components/system_stats.adoc[system_stats] *** xref:master/ecosystem_components/wal2json.adoc[wal2json] *** xref:master/ecosystem_components/pg_stat_monitor.adoc[pg_stat_monitor] +*** xref:master/ecosystem_components/pg_curl.adoc[pg_curl] * IvorySQL Architecture Design ** Query Processing *** xref:master/architecture/dual_parser.adoc[Dual Parser] diff --git a/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc b/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc index 42e4c8e..4c8c222 100644 --- a/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc +++ b/EN/modules/ROOT/pages/master/ecosystem_components/ecosystem_overview.adoc @@ -24,6 +24,7 @@ IvorySQL, as an advanced open-source database compatible with Oracle and based o |*10*| xref:master/ecosystem_components/system_stats.adoc[system_stats] | 3.2 | Provide functions for accessing system-level statistics. | system monitor |*11*| xref:master/ecosystem_components/pg_ai_query.adoc[pg_ai_query] | 0.1.1 | AI-driven natural language to SQL extension supporting multiple LLMs | AI-assisted querying, natural language database interaction |*12*| xref:master/ecosystem_components/pg_stat_monitor.adoc[pg_stat_monitor] | 2.3.1 | Collects performance statistics and provides query performance insights in a single view and graphically in histogram. | Performance monitoring +| 13 | xref:master/ecosystem_components/pg_curl.adoc[pg_curl] | 2.4 | A libcurl-based network transfer extension supporting HTTP/HTTPS, FTP, SMTP, IMAP, and 20+ other protocols, enabling network data transfer operations directly in SQL | REST API integration, email sending, file transfer, external system notifications |==== These plugins have all been tested and adapted by the IvorySQL team to ensure stable operation in the IvorySQL environment. Users can select appropriate plugins based on business needs to further enhance the capabilities and flexibility of the database system. diff --git a/EN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc b/EN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc new file mode 100644 index 0000000..68baae4 --- /dev/null +++ b/EN/modules/ROOT/pages/master/ecosystem_components/pg_curl.adoc @@ -0,0 +1,200 @@ + +:sectnums: +:sectnumlevels: 5 + += pg_curl + +== Overview + +pg_curl is a PostgreSQL extension based on libcurl that brings cURL's powerful data transfer capabilities directly into the database, allowing users to perform network protocol data transfer operations through SQL function calls without relying on external programs or middleware. + +Unlike lightweight extensions that only support HTTP, pg_curl fully encapsulates the libcurl easy interface API and supports more than twenty protocols including DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, POP3, POP3S, RTMP, RTMPS, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS, and WSS, providing extremely rich network interaction capabilities. + +Typical use cases include: sending HTTP notifications to external systems from triggers or stored procedures; sending emails directly from the database; uploading or downloading files via FTP/SFTP; calling third-party REST APIs and writing results back to database tables; and integrating with MQTT message brokers, LDAP directories, and other backend services in data processing workflows. + +pg_curl is licensed under the MIT License. Project repository: https://github.com/RekGRpth/pg_curl + +== Features + +* *Multi-protocol support*: Based on libcurl, supports more than twenty protocols including HTTP/HTTPS, FTP/FTPS, SMTP/SMTPS, IMAP, POP3, SCP, SFTP, MQTT, and LDAP, covering the vast majority of network integration scenarios. +* *Full HTTP method support*: Supports standard HTTP methods including GET, POST (URL-encoded, JSON, multipart/form-data), PUT, DELETE, and PATCH. Custom methods can be specified via `curl_easy_setopt_customrequest`. +* *Flexible request construction*: Provides fine-grained `curl_easy_setopt_*` functions to precisely control request headers, authentication, timeouts, proxies, TLS certificates, cookies, and more. +* *Multiple authentication methods*: Supports Basic Auth (username/password), Bearer Token, NTLM, Digest, OAuth, and other authentication mechanisms. +* *File transfer*: Supports uploading (via `curl_easy_setopt_readdata`) and downloading files over FTP/FTPS/SFTP/SCP, with upload data passed directly as `bytea` type. +* *Email sending*: Send emails directly from the database over SMTP/SMTPS, with support for setting sender, recipient, mail headers, and MIME body. +* *Response parsing*: Provides `curl_easy_getinfo_data_in()`, `curl_easy_getinfo_header_in()`, and other functions to retrieve response body and headers. Headers can be parsed into a key-value table using regular expressions. +* *Error handling*: `curl_easy_getinfo_errcode()`, `curl_easy_getinfo_errdesc()`, and `curl_easy_getinfo_errbuf()` provide complete error codes and descriptions for debugging. +* *Timeout and interruption*: By registering a progress callback with libcurl that periodically checks PostgreSQL's cancellation flag (`QueryCancelPending`), requests can be interrupted by `statement_timeout`, `pg_cancel_backend()`, and similar mechanisms, preventing long-running requests from blocking connections. +* *URL encoding utilities*: Built-in `curl_easy_escape()` and `curl_easy_unescape()` functions for URL encoding and decoding in SQL. + +== Installation + +pg_curl is not bundled in IvorySQL RPM/DEB packages and must be compiled and installed from source. + +[TIP] +The following example environment is Ubuntu 24.04 (x86_64) with IvorySQL 5 or later installed at `/usr/local/ivorysql/ivorysql-5`. + +=== Install Dependencies + +pg_curl depends on the system libcurl development library. Ensure it is installed before building: + +[source,shell] +---- +sudo apt install libcurl4-openssl-dev +---- + +=== Build and Install from Source + +Clone the source code from https://github.com/RekGRpth/pg_curl and run the build: + +[source,shell] +---- +git clone https://github.com/RekGRpth/pg_curl.git +cd pg_curl +# Ensure pg_config is accessible, or specify it explicitly via PG_CONFIG +PG_CONFIG=/usr/local/ivorysql/ivorysql-5/bin/pg_config make +PG_CONFIG=/usr/local/ivorysql/ivorysql-5/bin/pg_config sudo make install +---- + +After a successful installation, `pg_curl.so` and the corresponding SQL scripts will be placed in IvorySQL's extension directory. + +== Create Extension and Verify Version + +Connect to the database using psql (either PG mode port 5432 or Oracle mode port 1521), then run: + +[source,sql] +---- +CREATE EXTENSION pg_curl; + +SELECT name, default_version, installed_version, comment + FROM pg_available_extensions + WHERE name = 'pg_curl'; +---- + +Expected output: + +[source,text] +---- + name | default_version | installed_version | comment +---------+-----------------+-------------------+---------------------------------------------------------------------------------------------------------------------------------------- + pg_curl | 2.4 | 2.4 | PostgreSQL cURL allows most curl actions, including data transfer with URL syntax via HTTP, HTTPS, FTP, FTPS, GOPHER, TFTP, SCP, ... +(1 row) +---- + +== Usage + +pg_curl follows a "configure, execute, retrieve" pattern. The core workflow is: + +. Call `curl_easy_reset()` to initialize (or reset) the current cURL session. +. Call `curl_easy_setopt_*`, `curl_header_append`, `curl_postfield_append`, and other functions to configure request parameters. +. Call `curl_easy_perform()` to execute the request. +. Call `curl_easy_getinfo_*` functions to retrieve the response or error information. + +=== HTTP GET + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/get?'); +SELECT curl_url_append('key1', 'value1'); +SELECT curl_url_append('key2', 'hello world'); -- automatically URL-encoded +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8'); +END; +---- + +=== HTTP POST (JSON) + +Form POST (`curl_postfield_append`) and multipart POST (`curl_mime_data`) follow the same pattern — simply replace the data-setting function. + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_postfields(convert_to('{"name":"IvorySQL"}', 'utf-8')); +SELECT curl_easy_setopt_url('https://httpbin.org/post'); +SELECT curl_header_append('Content-Type', 'application/json; charset=utf-8'); +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8'); +END; +---- + +=== Authentication and Request Headers + +Basic Auth uses `curl_easy_setopt_username` / `curl_easy_setopt_password`. Bearer Token and other custom headers are added via `curl_header_append`: + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/bearer'); +SELECT curl_header_append('Authorization', 'Bearer '); +SELECT curl_easy_perform(); +SELECT convert_from(curl_easy_getinfo_data_in(), 'utf-8')::jsonb; +END; +---- + +=== Error Handling and Timeouts + +After `curl_easy_perform()` returns, check the execution status with the following functions (`errcode` of 0 indicates success): + +[source,sql] +---- +BEGIN; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/get'); +SELECT curl_easy_perform(); +SELECT + curl_easy_getinfo_errcode() AS errcode, + curl_easy_getinfo_errdesc() AS errdesc; +END; +---- + +pg_curl checks PostgreSQL's cancellation flag via a libcurl progress callback. When `statement_timeout` fires, the in-progress request is immediately aborted and the current transaction is rolled back: + +[source,sql] +---- +BEGIN; +SET LOCAL statement_timeout = '3s'; +SELECT curl_easy_reset(); +SELECT curl_easy_setopt_url('https://httpbin.org/delay/10'); +SELECT curl_easy_perform(); -- raises query_canceled after timeout, transaction rolls back +END; +---- + +== IvorySQL Adaptation Notes + +=== Dual-Port Compatibility + +IvorySQL uses a dual-port architecture supporting both PostgreSQL mode (default port *5432*) and Oracle-compatible mode (default port *1521*): + +* Port *5432* (PG mode): accepts standard PostgreSQL SQL syntax. +* Port *1521* (Oracle mode): accepts Oracle-compatible SQL syntax. + +pg_curl works normally in both modes. `CREATE EXTENSION pg_curl` succeeds on both port 1521 and port 5432. + +=== Oracle Mode Notes + +When using pg_curl in Oracle mode (port 1521): + +* All pg_curl functions are invoked via plain `SELECT` statements (e.g. `SELECT curl_easy_reset()`), which are valid in Oracle mode. The Oracle-style `SELECT curl_easy_reset() FROM DUAL` syntax also works. +* The `ivorysql.enable_emptystring_to_NULL` parameter affects how empty strings are handled. The regression tests set `SET ivorysql.enable_emptystring_to_NULL = 'off'` to ensure empty-value parameters (such as empty form fields) are passed as expected. Configure this parameter according to your production requirements. + +=== Using pg_curl in PL/iSQL + +pg_curl can be called from IvorySQL's PL/iSQL (the Oracle-compatible procedural language) to push external notifications automatically when data changes. PL/iSQL uses Oracle-style `IS` syntax for procedure declarations, and function return values are discarded by assigning them to a local variable: + +[source,sql] +---- +-- Call pg_curl inside a PL/iSQL stored procedure (Oracle mode, IS syntax) +CREATE OR REPLACE PROCEDURE notify_external(p_payload IN VARCHAR2) IS + v_ok BOOLEAN; +BEGIN + v_ok := curl_easy_reset(); + v_ok := curl_easy_setopt_postfields(convert_to(p_payload, 'utf-8')); + v_ok := curl_easy_setopt_url('https://hooks.example.com/notify'); + v_ok := curl_header_append('Content-Type', 'application/json'); + v_ok := curl_easy_perform(); +END; +----