--- warning: DO NOT CHANGE THIS MANUALLY, THIS IS GENERATED BY https://github.com/duckdb/community-extensions repository, check README there title: duckfn_open excerpt: | DuckDB Community Extensions Wrap Rust's open and sanitize-filename crates for SQL — open a path, a URL or the output of a query with your desktop's own program, and turn a string into a usable file name extension: name: duckfn_open description: Wrap Rust's open and sanitize-filename crates for SQL — open a path, a URL or the output of a query with your desktop's own program, and turn a string into a usable file name version: 0.1.0 language: Rust build: cargo license: MIT requires_toolchains: "rust;python3" excluded_platforms: "wasm_mvp;wasm_eh;wasm_threads" maintainers: - shijianjs repo: github: shijianjs/duckfn-open ref: 6995c11bb78279aab4caf5b11f3d0df3011fb3a7 ref_next: 6995c11bb78279aab4caf5b11f3d0df3011fb3a7 docs: hello_world: | -- What would open this on the machine running the query, without opening anything SELECT op_open_commands('report.html'); -- Hand an existing path to the desktop's default program SELECT op_open_path('./report.html'); -- Most query output is content, not a path: write it out and get the path back SELECT op_write_file('{"a":1}', 'json'); extended_description: | `duckfn_open` wraps two mature Rust crates for SQL: [`open`](https://crates.io/crates/open), which hands a path or a URL to whatever the desktop is configured to open it with, and [`sanitize-filename`](https://crates.io/crates/sanitize-filename), whose file-name rules it puts on SQL. Nine scalar function names, in three groups: - **Paths and URLs** — `op_open_path(path[, app])` and `op_open_path_detached(path[, app])` hand an existing file or link to the desktop, waiting for it or not; `op_open_commands(path)` lists the commands a launch would try, running none of them. - **Content** — `op_write_file(content|blob, ext[, opts])` writes text or bytes to a file and returns the path, starting nothing; `op_open_content(…)` writes it and opens it in the same call; `op_open_html(content)` is the zero-configuration version of that; `op_print(text[, tail])` writes to stdout, past the result set's column formatting, and hands the text back. The optional third argument is the registered `op_write_file_options` STRUCT (`dir`, `name`, `part`). - **File names** — `op_sanitize_filename(value[, replacement[, truncate, windows]])` rewrites a value into a usable name, and `op_sanitize_filename_check(…)` answers whether it already is one. This pair starts no process and touches no file, so a name taken from the data can be checked before anything is built on it. It is aimed at interactive work: a person is at the machine, running DuckDB, and wants the result in front of them. A launcher is desktop software, so DuckDB embedded in an application is outside what this is for — on a machine with no desktop only the half that starts no process is of any use. The extension starts a process and writes the file you ask for (into the directory you name, or the system temp directory); it reads no configuration, opens no network connection of its own, and does not inspect the content it passes along. Requires **DuckDB 1.3 or newer**. Documentation: [user guide](https://shijianjs.github.io/duckfn-open/docs/intro) · [function reference](https://shijianjs.github.io/duckfn-open/docs/category/functions) · [source and development notes](https://github.com/shijianjs/duckfn-open). extension_star_count: 0 extension_star_count_pretty: 0 extension_download_count: 536 extension_download_count_pretty: 536 image: '/images/community_extensions/social_preview/preview_community_extension_duckfn_open.png' layout: community_extension_doc --- ### Compatibility Matrix This table covers all DuckDB releases that have not reached [end-of-life](https://duckdb.org/release_calendar), including LTS releases, and shows the 2 most recent patch releases of each. Older patch releases are not listed, but the extension may be available for them as well.
| Platform | 1.4.4 | 1.4.5 | 1.5.5 | 1.5.6 | 2.0.0 | | :--- | :---: | :---: | :---: | :---: | :---: | | Linux AMD64 | ❌ | ❌ | ❌ | ❌ | ✅ | | Linux ARM64 | ❌ | ❌ | ❌ | ❌ | ✅ | | macOS AMD64 | ❌ | ❌ | ❌ | ❌ | ✅ | | macOS ARM64 | ❌ | ❌ | ❌ | ❌ | ✅ | | Windows AMD64 | ❌ | ❌ | ❌ | ❌ | ✅ | | Windows ARM64 | ❌ | ❌ | ❌ | ❌ | ❌ | | WebAssembly | ❌ | ❌ | ❌ | ❌ | ❌ | ### Installing and Loading ```sql INSTALL {{ page.extension.name }} FROM community; LOAD {{ page.extension.name }}; ``` {% if page.docs.hello_world %} ### Example ```sql {{ page.docs.hello_world }}``` {% endif %} {% if page.docs.extended_description %} ### About {{ page.extension.name }} {{ page.docs.extended_description }} {% endif %} ### Added Functions
| function_name | function_type | description | comment | examples | |----------------------------|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | op_open_commands | scalar | Lists, without running them, the launcher commands op_open_path would try in order | The read-only pair of op_open_path: nothing is started, so the result is stable enough to assert in CI on a headless runner | [SELECT op_open_commands('report.html')] | | op_open_content | scalar | Writes a piece of text or binary content out to a file and opens it with the program the desktop is configured to use | op_write_file plus op_open_path in one call: it returns the path it wrote, so a launcher that cannot start is reported as an error carrying that path instead of a lost false; it does not wait for the program to exit, and the BLOB signatures write the bytes exactly as they are | [SELECT op_open_content(logo_blob, 'png'); SELECT op_open_content(read_text('report.html'), 'html'); SELECT op_open_content(svg, 'svg', {'dir':'./out', 'part':'sales'})] | | op_open_html | scalar | Writes an HTML string to a temporary file and opens it in the system default browser, returning the file path | The zero-configuration shortcut: op_open_content(content, 'html') with every option left at its default (system temp directory, generated name); needs no configuration because SQL renders HTML | [SELECT op_open_html('

hello

'); SELECT op_open_html(read_text('report.html'))] | | op_open_path | scalar | Opens a local path or URL with the program the desktop is configured to use | true once a launcher has been started, false when none could be started; NULL input short-circuits to NULL and starts nothing | [SELECT op_open_path('report.html'); SELECT op_open_path('https://duckdb.org', 'firefox')] | | op_open_path_detached | scalar | Opens a local path or URL and returns as soon as the launcher is started | The non-blocking pair of op_open_path: true means a process was started, not that the target opened | [SELECT op_open_path_detached('https://duckdb.org')] | | op_print | scalar | Prints a piece of text straight to stdout, bypassing the result set's column formatting | For character art and other line-aligned output the CLI would otherwise wrap: the text is written to stdout as it is and handed back unchanged, so the call can stay in a projection; the optional second argument is what follows the text instead of the default newline | [SELECT op_print(report, chr(10) \|\| chr(10)); SELECT op_print(tp_qr('https://query.farm')); SELECT op_print('rows: ' \|\| count(*)) FROM t] | | op_sanitize_filename | scalar | Rewrites a string into something usable as a file name, following sanitize-filename | The crate's own defaults: the illegal characters are deleted (pass a replacement to see where they were), the 255-byte cut is applied, and the Windows rules are on because a query should answer the same way on every machine | [SELECT op_sanitize_filename('quarterly/report:v2.csv'); SELECT op_sanitize_filename(report_title, '_')] | | op_sanitize_filename_check | scalar | Tells whether a string is already usable as a file name, rewriting nothing | The predicate half of sanitize-filename: true means op_sanitize_filename with the same options would answer with the value it was given | [SELECT count(*) FROM files WHERE NOT op_sanitize_filename_check(name)] | | op_write_file | scalar | Writes a piece of text or binary content out to a file and returns its path, with the extension required and the directory, file name and name segment optional | Starts nothing: hand the returned path to op_open_path to open it. `dir` defaults to the system temp directory (created when missing), `name` defaults to a generated open-