> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-trino-dialect.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

> Documentación de las funciones definidas por el usuario en WebAssembly

# Funciones definidas por el usuario en WebAssembly

export const ExperimentalBadge = () => {
  return <a href="https://clickhouse.com/docs/reference/settings/beta-and-experimental-features#experimental-features" className="experimentalBadge">
            <div className="experimentalIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.25" d="M5.5 2H10.5" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M9.50015 2V6.19625L13.4283 12.7425C13.4738 12.8183 13.4985 12.9049 13.4996 12.9934C13.5008 13.0818 13.4785 13.169 13.435 13.246C13.3914 13.323 13.3283 13.3871 13.2519 13.4317C13.1755 13.4764 13.0886 13.4999 13.0002 13.5H3.00015C2.91164 13.5 2.8247 13.4766 2.74822 13.432C2.67174 13.3874 2.60847 13.3233 2.56487 13.2463C2.52126 13.1693 2.49889 13.082 2.50004 12.9935C2.50119 12.905 2.52582 12.8184 2.5714 12.7425L6.50015 6.19625V2" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.25" d="M4.47656 9.56754C5.30344 9.41254 6.47656 9.47942 7.99969 10.25C10.0153 11.2707 11.4216 11.0569 12.2184 10.7282" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
        </div>
            Funcionalidad experimental
        </a>;
};

export const CloudNotSupportedBadge = () => {
  return <a href="https://clickhouse.com/docs/products/cloud/guides/cloud-compatibility#list-of-unsupported-features" className="cloudNotSupportedBadge">
            <div className="cloudNotSupportedIcon">
            <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
                <path strokeWidth="1.5" d="M6.33366 12.6666L12.3739 12.6667C13.6593 12.6667 14.7073 11.6187 14.7073 10.3334C14.7073 9.04804 13.6593 8.00003 12.3739 8.00003C12.3739 8.00003 12.3337 7.66659 12.0003 7.33325M10.667 5.33322C8.00033 2.33325 4.45395 4.78537 4.14195 6.68203C2.55728 6.7627 1.29395 8.06203 1.29395 9.6667C1.29395 11.3234 2.66699 12.6666 4.00033 12.6666" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
                <path strokeWidth="1.5" d="M2.66699 14L12.0003 4.66663" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" />
            </svg>

        </div>
            No es compatible con ClickHouse Cloud
        </a>;
};

ClickHouse admite la creación de funciones definidas por el usuario (UDFs) escritas en WebAssembly. Esto permite ejecutar lógica personalizada escrita en lenguajes como Rust, C, C++ u otros, compilándola en módulos de WebAssembly.

<CloudNotSupportedBadge />

<ExperimentalBadge />

<div id="overview">
  ## Descripción general
</div>

Un módulo de WebAssembly es un archivo binario compilado que contiene una o varias funciones a las que se puede llamar desde ClickHouse.
Piense en un módulo como una biblioteca o un objeto compartido que se carga una vez y se reutiliza muchas veces.

Los módulos de WebAssembly que contienen UDFs pueden escribirse en cualquier lenguaje que pueda compilarse a WebAssembly, como Rust, C o C++.

El código compilado a WebAssembly (código "guest") y ejecutado por ClickHouse ("host") se ejecuta en un entorno aislado con acceso únicamente a un espacio de memoria dedicado.

El código guest exporta funciones que ClickHouse puede invocar; entre ellas se incluyen las funciones que implementan su lógica personalizada (utilizadas para definir UDFs), así como las funciones auxiliares necesarias para la gestión de la memoria y el intercambio de datos entre ClickHouse y el código WebAssembly.

Su código debe compilarse como WebAssembly "freestanding" (también conocido como `wasm32-unknown-unknown`) sin dependencias de un sistema operativo ni de una biblioteca estándar. Además, solo se admite el destino predeterminado de WebAssembly de 32 bits (sin la extensión `wasm64`).
El módulo debe seguir uno de los protocolos de comunicación (ABI) compatibles para interactuar con ClickHouse.

Una vez compilado, el código binario del módulo se carga en ClickHouse insertándolo en la tabla `system.webassembly_modules`.
Después, puede crear UDFs que hagan referencia a las funciones exportadas por el módulo mediante la sentencia `CREATE FUNCTION ... LANGUAGE WASM`.

<div id="prerequisites">
  ## Requisitos previos
</div>

Active la compatibilidad con WebAssembly en la configuración de ClickHouse:

```xml theme={null}
<clickhouse>
    <allow_experimental_webassembly_udf>true</allow_experimental_webassembly_udf>
    <webassembly_udf_engine>wasmtime</webassembly_udf_engine>
</clickhouse>
```

Implementaciones del motor disponibles:

* `wasmtime` (predeterminado, recomendado) — usa [WasmTime](https://github.com/bytecodealliance/wasmtime)
* `wasmedge` — usa [WasmEdge](https://github.com/WasmEdge/WasmEdge)

<div id="quick-start">
  ## Inicio rápido
</div>

Este ejemplo muestra el flujo de trabajo completo para crear una UDF de WebAssembly implementando una calculadora de la [conjetura de Collatz](https://en.wikipedia.org/wiki/Collatz_conjecture).

Escribiremos el código en formato de texto de WebAssembly (WAT), que es una representación legible de WebAssembly, por lo que en esta etapa no se necesita ningún lenguaje de programación.
ClickHouse requiere que el módulo esté en formato binario, así que usaremos el transpilador para convertir WAT a WASM.
Para realizar esta conversión, puede usar `wat2wasm` de [WebAssembly Binary Toolkit (WABT)](https://github.com/WebAssembly/wabt) o el comando `parse` de [wasm-tools](https://github.com/bytecodealliance/wasm-tools).

```bash theme={null}
cat << 'EOF' | wasm-tools parse | clickhouse client -q "INSERT INTO system.webassembly_modules (name, code) SELECT 'collatz', code FROM input('code String') FORMAT RawBlob"
(module
  (func $next (param $n i32) (result i32)
    local.get $n i32.const 1 i32.and
    (if (result i32)
      (then local.get $n i32.const 3 i32.mul i32.const 1 i32.add)
      (else local.get $n i32.const 2 i32.div_u)))
  (func $steps (export "steps") (param $n i32) (result i32)
    (local $count i32)
    local.get $n i32.const 1 i32.lt_u
    (if (then i32.const 0 return))
    (block $done (loop $loop
      local.get $n i32.const 1 i32.eq br_if $done
      local.get $n call $next local.set $n
      local.get $count i32.const 1 i32.add local.set $count
      br $loop))
    local.get $count)
)
EOF
```

En el fragmento anterior, enviamos el código WASM binario directamente al ClickHouse client mediante una tubería con `FORMAT RawBlob` para insertarlo en la tabla `system.webassembly_modules`.

Luego definimos la UDF que hace referencia a la función `steps` exportada por el módulo:

```sql theme={null}
CREATE FUNCTION collatz_steps LANGUAGE WASM ARGUMENTS (n UInt32) RETURNS UInt32 FROM 'collatz' :: 'steps';
```

Ten en cuenta que especificamos el nombre de la función del módulo después de `::`, porque es distinto del nombre de la UDF.

Ahora podemos usar la función `collatz_steps` en nuestras consultas:

```sql theme={null}
SELECT groupArray(collatz_steps(number :: UInt32))
FROM numbers(1, 100)
FORMAT TSV
```

La columna `number` se convierte explícitamente a `UInt32`, porque las funciones de WebAssembly requieren una coincidencia exacta con los tipos de la firma especificada en la sentencia `CREATE FUNCTION`.

En el resultado obtuvimos la secuencia de pasos de Collatz para los números del 1 al 100, correspondiente a la secuencia [A006577 de la OEIS](https://oeis.org/A006577).

```text theme={null}
[0,1,7,2,5,8,16,3,19,6,14,9,9,17,17,4,12,20,20,7,7,15,15,10,23,10,111,18,18,18,106,5,26,13,13,21,21,21,34,8,109,8,29,16,16,16,104,11,24,24,24,11,11,112,112,19,32,19,32,19,19,107,107,6,27,27,27,14,14,14,102,22,115,22,14,22,22,35,35,9,22,110,110,9,9,30,30,17,30,17,92,17,17,105,105,12,118,25,25,25]
```

<div id="manage-wasm-modules-via-system-table">
  ## Administrar módulos WASM mediante la tabla del sistema
</div>

Los módulos de WebAssembly se almacenan en la tabla `system.webassembly_modules`, que tiene la siguiente estructura:

* **Columnas**
  * `name` String — Nombre del módulo. No puede estar vacío; solo se permiten caracteres alfanuméricos y guiones bajos.
  * `code` String — Código WASM binario sin procesar. Solo escritura; las lecturas devuelven una cadena vacía.
  * `hash` UInt256 — SHA256 del binario del módulo (cero si está presente en disco, pero aún no se ha cargado).

La gestión de módulos se realiza mediante operaciones SQL estándar sobre esta tabla:

<div id="insert-a-module">
  ### Insertar un módulo
</div>

```sql theme={null}
INSERT INTO system.webassembly_modules (name, code)
SELECT 'my_module', base64Decode('AGFzbQEAAAA...');
```

Si lo desea, proporcione el hash de integridad:

```sql theme={null}
INSERT INTO system.webassembly_modules (name, code, hash)
SELECT 'my_module', base64Decode('...'), reinterpretAsUInt256(unhex('369f...c57d'));
```

Si el hash proporcionado no coincide con el SHA256 calculado para el código del módulo, la inserción falla. Esto puede resultar útil al cargar módulos desde fuentes externas, como S3 o HTTP.

<div id="distribute-a-module-across-a-cluster">
  ### Distribuir un módulo en un clúster
</div>

`system.webassembly_modules` es una tabla por instancia: un `INSERT` solo se aplica a la réplica que gestiona la conexión. No existe una forma `ON CLUSTER` de la sentencia `INSERT`, por lo que un `CREATE FUNCTION ... ON CLUSTER` posterior fallará en las réplicas que no tengan el módulo:

```text theme={null}
Code: 674. DB::Exception: WebAssembly module 'collatz' not found:
while adding user defined function `collatz_steps`. (RESOURCE_NOT_FOUND)
```

Para distribuir una inserción a todos los nodos, escriba en la función de tabla `cluster` en lugar de la tabla local `system.webassembly_modules`:

```bash theme={null}
cat collatz.wasm | clickhouse client -q "
  INSERT INTO FUNCTION cluster('default', 'system', 'webassembly_modules') (name, code)
  SELECT 'collatz', code FROM input('code String') FORMAT RawBlob"
```

<Note>
  Este patrón depende de que la ruta subyacente de escritura distribuida recorra todas las réplicas de cada segmento, lo que solo ocurre cuando el clúster está configurado con `internal_replication=false`. Con `internal_replication=true` (el valor predeterminado en los clústeres que usan `ReplicatedMergeTree` para gestionar por sí mismos la replicación), el insert se envía a una sola réplica en buen estado por segmento, y `system.webassembly_modules` no se replica por esa ruta, por lo que algunas réplicas seguirán sin tener el módulo. En esa configuración, debes hacer el insert en cada réplica por separado, por ejemplo, iterando sobre `system.clusters` y escribiendo mediante `remote(...)` por host, o copiando el binario en `user_scripts/wasm/` en cada host.

  Puedes consultar `internal_replication` de un clúster con `SELECT cluster, shard_num, internal_replication FROM system.clusters`.
</Note>

Después del insert distribuido, el módulo está presente en todas las réplicas y `CREATE FUNCTION ... ON CLUSTER` se ejecuta correctamente:

```sql theme={null}
CREATE FUNCTION collatz_steps ON CLUSTER 'default'
LANGUAGE WASM FROM 'collatz' :: 'steps'
ARGUMENTS (n UInt32) RETURNS UInt32;
```

Puede verificar que el módulo esté cargado en todo el clúster con `clusterAllReplicas`:

```sql theme={null}
SELECT hostName(), name FROM clusterAllReplicas('default', system.webassembly_modules) WHERE name = 'collatz';
```

Las inserciones en `system.webassembly_modules` son idempotentes para el mismo par `(name, hash)`, por lo que volver a ejecutar la inserción distribuida es seguro y una forma razonable de reparar el estado después de reemplazar una réplica. Tenga en cuenta que los servidores recién añadidos no reciben retroactivamente los módulos existentes; debe volver a ejecutar la inserción en el clúster actualizado, o colocar el binario en el directorio `user_scripts/wasm/` del nuevo host.

<div id="list-modules">
  ### Listar módulos
</div>

```sql theme={null}
SELECT name, lower(hex(reinterpretAsFixedString(hash))) AS sha256 FROM system.webassembly_modules

   ┌─name────┬─sha256───────────────────────────────────────────────────────────┐
1. │ collatz │ a084a10b7b5cb07db198bc93bf1f3c1f8cb8ef279df7a4f6b66b1cdd55d79c48 │
   └─────────┴──────────────────────────────────────────────────────────────────┘
```

<div id="delete-a-module">
  ### Eliminar un módulo
</div>

La eliminación se realiza mediante la sentencia `DELETE FROM system.webassembly_modules WHERE name = '...'`.
El predicado debe ser `name = 'literal'` para una coincidencia exacta o `name LIKE 'pattern'` para eliminar todos los módulos cuyo nombre coincida con el patrón; no se acepta ninguna otra forma.

```sql theme={null}
DELETE FROM system.webassembly_modules WHERE name = 'collatz';

-- Eliminar en masa todos los módulos cuyo nombre empiece por `tmp_` (el guion bajo literal se escapa como `\_`):
DELETE FROM system.webassembly_modules WHERE name LIKE 'tmp\_%';
```

Si alguna UDF existente hace referencia a uno de los módulos coincidentes, la eliminación fallará, por lo que primero debe eliminar esas UDFs.

<div id="create-a-webassembly-udf">
  ## Crear una UDF de WebAssembly
</div>

**Sintaxis**:

```sql theme={null}
CREATE [OR REPLACE] FUNCTION function_name
LANGUAGE WASM
FROM 'module_name' [:: 'source_function_name']
ARGUMENTS ( [name type[, ...]] | [type[, ...]] )
RETURNS return_type
[ABI ROW_DIRECT | ABI BUFFERED_V1 | ABI ASSEMBLYSCRIPT]
[DETERMINISTIC]
[SHA256_HASH 'hex']
[SETTINGS key = value[, ...]];
```

**Parámetros**:

* `function_name`: Nombre de la función en ClickHouse. Puede ser diferente del nombre de la función exportada en el módulo.
* `FROM 'module_name' :: 'source_function_name'`: Nombre del módulo WASM cargado y nombre de la función del módulo WASM que se va a usar (de forma predeterminada, function\_name)
* `ARGUMENTS`: Lista de nombres y tipos de argumentos (los nombres son opcionales y se usan en formatos de serialización que admiten campos con nombre)
* `ABI`: Versión de la interfaz binaria de aplicación
  * `ROW_DIRECT`: Mapeo directo de tipos, procesamiento fila por fila
  * `BUFFERED_V1`: Procesamiento por bloques con serialización
  * `ASSEMBLYSCRIPT`: Procesamiento fila por fila para módulos generados por el compilador [AssemblyScript](https://www.assemblyscript.org). Los tipos numéricos se asignan a primitivas de AssemblyScript; ClickHouse `String` se asigna a `string`.
* `DETERMINISTIC`: Declara la función como determinista: siempre devuelve el mismo resultado para la misma entrada. Cuando se especifica, ClickHouse puede plegar a constantes las llamadas en las que todos los argumentos son constantes: la función se evalúa una vez durante el análisis de la consulta y el resultado se reutiliza para cada fila.
* `SHA256_HASH`: Hash esperado del módulo para su verificación (se completa automáticamente si se omite); puede usarse para garantizar que se cargue el módulo WASM correcto en distintas réplicas.
* `SETTINGS`: Configuración por función
  * `serialization_format` String — Formato utilizado para serializar los bloques de argumentos que se pasan al módulo y para analizar el resultado devuelto. Se usa únicamente con `ABI BUFFERED_V1`. Valores admitidos: `MsgPack`, `JSONEachRow`, `CSV`, `TSV`, `TSVRaw`, `RowBinary` y `Buffers`. Predeterminado: `MsgPack`. Los formatos basados en bloques, como `Buffers`, deben devolver una sola columna cuyo tipo coincida con la firma de la función declarada.
  * `webassembly_udf_enable_fuel` Bool — Habilita un presupuesto de fuel finito para la función. Predeterminado: `true`. Cuando es `false`, la configuración de nivel de consulta `webassembly_udf_max_fuel` se ignora para esta función. Deshabilitar los límites de fuel puede mejorar el rendimiento al usar el engine `wasmtime`. Sin embargo, para código guest no confiable o con errores, puede aumentar el riesgo de ejecución descontrolada.

<div id="abis-versions">
  ## Versiones de las ABI
</div>

Para interactuar con ClickHouse, los módulos de WebAssembly deben cumplir con una de las ABI (interfaz binaria de aplicación) compatibles.

* `ROW_DIRECT`: mapeo directo de tipos (solo tipos primitivos `Int32`, `UInt32`, `Int64`, `UInt64`, `Float32`, `Float64`)
* `BUFFERED_V1`: tipos complejos con serialización
* `ASSEMBLYSCRIPT`: interoperabilidad fila por fila con módulos de [AssemblyScript](https://www.assemblyscript.org); admite tipos numéricos y `String`.

<div id="abi-row_direct">
  ### ABI ROW\_DIRECT
</div>

Llama directamente a una función WASM exportada para cada fila.

* Los argumentos y los tipos de retorno deben ser tipos numéricos `Int32/UInt32/Int64/UInt64/Float32/Float64/Int128/UInt128`.
* Las cadenas no son compatibles con esta ABI.
* Las firmas deben coincidir con la exportación WASM (`i32/i64/f32/f64/v128`).
* El módulo no necesita exportar funciones de soporte.

Por ejemplo, una función con la firma:

```
(func (param i32 i64 f32) (result f64) ...)
```

Se puede crear así:

```sql theme={null}
CREATE FUNCTION my_func ARGUMENTS (Int32, UInt64, Float32) RETURNS Float64 ...
```

WebAssembly no distingue entre argumentos con signo y sin signo, sino que utiliza distintas instrucciones para interpretar los valores. Por lo tanto, el tamaño del argumento debe coincidir exactamente, mientras que si es con signo o sin signo lo determinan las operaciones dentro de la función.

<div id="abi-buffered_v1">
  ### ABI BUFFERED\_V1
</div>

<Note>
  Esta ABI es experimental y está sujeta a cambios en versiones futuras.
</Note>

Procesa bloques completos de una sola vez mediante (des)serialización a través de la memoria WASM. Admite cualquier tipo de argumento y de retorno.

Los datos se intercambian mediante búferes en la memoria WASM. Un búfer es una estructura de 8 bytes que contiene un puntero a los datos y su tamaño (dos valores `u32` en orden little-endian). Los búferes se pasan mediante un identificador: un puntero a esta estructura, no a los propios datos. El código guest debe exportar dos funciones para crear y destruir estos búferes.

Para cada bloque de entrada, ClickHouse:

1. Serializa las columnas de argumentos mediante el `serialization_format` de la función (`MsgPack` de forma predeterminada). Los formatos basados en filas escriben los valores fila por fila, con los valores de los argumentos en el orden en que se declaran en `ARGUMENTS`; los formatos con campos con nombre usan los nombres de los argumentos, por lo que debe declararlos en `ARGUMENTS` al utilizar dichos formatos.
2. Llama a `clickhouse_create_buffer`, exportada por el módulo, y copia los datos serializados en la memoria a la que apunta el búfer devuelto.
3. Llama a la función definida por el usuario con dos argumentos `i32`: el identificador del búfer de entrada (`0` si la función no tiene argumentos) y el número de filas. La función devuelve un único `i32`: el identificador del búfer de resultados, que el propio código guest asigna; devolver `0` hace que la consulta falle con un error.
4. Lee el búfer de resultados: debe contener exactamente una columna con exactamente el mismo número de filas, serializada en el mismo formato. En formatos con campos con nombre, como `JSONEachRow`, la columna de resultados debe llamarse `result`.
5. Llama a `clickhouse_destroy_buffer` para los identificadores tanto del búfer de entrada (si existe) como del búfer de resultados. El código guest no debe liberar el búfer de resultados por sí mismo ni devolver el identificador de entrada como resultado; de lo contrario, se destruiría dos veces.

La función se invoca una vez por bloque de entrada: una consulta grande se divide en varios bloques mediante el pipeline de consultas (el número máximo de filas por llamada también puede limitarse con la configuración `webassembly_udf_max_input_block_size`), por lo que el número de filas pasado en cada llamada corresponde al tamaño de ese bloque, no al de toda la consulta.

<Note>
  Los bytes exactos de los búferes los determina el formato elegido, y el código guest debe decodificarlos y codificarlos por sí mismo. En particular, para valores `String`:

  * `MsgPack`: ClickHouse escribe los valores `String` mediante la familia de tipos `bin` (`0xc4`/`0xc5`/`0xc6`), no mediante la familia `str`. Ambas familias se aceptan al analizar el resultado.
  * `RowBinary`: cada `String` lleva como prefijo su longitud en bytes codificada como un varint sin signo ([LEB128](https://en.wikipedia.org/wiki/LEB128)), no como un entero de ancho fijo.
  * `JSONEachRow`: cada fila de resultados debe ser un objeto con la clave `result`, por ejemplo `{"result":"value"}`.
</Note>

```
(module
  ;; Allocate a new buffer of specified size
  ;; Returns: handle to Buffer structure (not direct data pointer!) with pointer to data and size
  (func (export "clickhouse_create_buffer")
    (param $size i32)    ;; Size of data to allocate
    (result i32))        ;; Returns buffer handle with enough space

  ;; Free a buffer by its handle
  (func (export "clickhouse_destroy_buffer")
    (param $handle i32)  ;; Buffer handle to free
    (result))            ;; No return value

    ;; User-defined function
    (func (export "user_defined_function1")
      (param $input_buffer_handle i32)  ;; Input buffer handle
      (param $n i32)                    ;; Number of rows in input
      (result i32))                     ;; Returns output buffer handle
)
```

Un ejemplo completo en C autónomo: `str_reverse` invierte los bytes de cada cadena de entrada mediante `serialization_format = 'RowBinary'`. Las instancias del módulo se reutilizan entre bloques, por lo que `clickhouse_destroy_buffer` debe liberar realmente la memoria; aquí el asignador se restablece una vez destruidos todos los búferes.

```c theme={null}
#include <stdint.h>

typedef struct {
    uint8_t * data;
    uint32_t size;
} ClickHouseBuffer;

#define HEAP_SIZE (1 << 24)
static _Alignas(16) uint8_t heap[HEAP_SIZE];
static uint32_t heap_pos = 0;
static uint32_t live_buffers = 0;

__attribute__((export_name("clickhouse_create_buffer")))
ClickHouseBuffer * clickhouse_create_buffer(uint32_t size)
{
    uint32_t total = (sizeof(ClickHouseBuffer) + size + 15u) & ~15u;
    if (heap_pos + total > HEAP_SIZE)
        return 0; /* a zero handle makes the host fail the query with an error */
    ClickHouseBuffer * buf = (ClickHouseBuffer *) &heap[heap_pos];
    buf->data = &heap[heap_pos + sizeof(ClickHouseBuffer)];
    buf->size = size;
    heap_pos += total;
    ++live_buffers;
    return buf;
}

__attribute__((export_name("clickhouse_destroy_buffer")))
void clickhouse_destroy_buffer(ClickHouseBuffer * buf)
{
    if (--live_buffers == 0)
        heap_pos = 0;
}

/* RowBinary prefixes each String with its byte length as an unsigned varint (LEB128) */
static uint64_t read_varint(const uint8_t ** pp)
{
    uint64_t value = 0;
    for (int shift = 0;; shift += 7)
    {
        uint8_t b = *(*pp)++;
        value |= (uint64_t)(b & 0x7f) << shift;
        if (!(b & 0x80))
            return value;
    }
}

static void write_varint(uint8_t ** pp, uint64_t value)
{
    while (value >= 0x80)
    {
        *(*pp)++ = (uint8_t)(value | 0x80);
        value >>= 7;
    }
    *(*pp)++ = (uint8_t)value;
}

/* Reverses the bytes of each input string */
__attribute__((export_name("str_reverse")))
ClickHouseBuffer * str_reverse(ClickHouseBuffer * input, uint32_t num_rows)
{
    ClickHouseBuffer * out = clickhouse_create_buffer(input->size);
    if (!out)
        return 0;
    const uint8_t * in = input->data;
    uint8_t * o = out->data;
    for (uint32_t row = 0; row < num_rows; ++row)
    {
        uint64_t len = read_varint(&in);
        write_varint(&o, len);
        for (uint64_t i = 0; i < len; ++i)
            o[i] = in[len - 1 - i];
        in += len;
        o += len;
    }
    out->size = (uint32_t)(o - out->data);
    return out;
}
```

Compila con clang y `wasm-ld` (distribuido con LLVM/lld):

```bash theme={null}
clang --target=wasm32 -ffreestanding -nostdlib -fno-builtin -c str_reverse.c
wasm-ld --no-entry str_reverse.o -o str_reverse.wasm
```

Las funciones deben ser visibles entre las exportaciones del módulo: márquelas con `__attribute__((export_name("...")))` como se indicó anteriormente, o enlácelo con `wasm-ld --export-all`. `-fno-builtin` evita que clang transforme bucles simples de bytes en llamadas a `memcpy`/`memset`, que no están disponibles sin una biblioteca estándar.

Cargue el módulo y cree la función:

```bash theme={null}
cat str_reverse.wasm | clickhouse client -q "INSERT INTO system.webassembly_modules (name, code) SELECT 'str_reverse', code FROM input('code String') FORMAT RawBlob"
```

```sql theme={null}
CREATE FUNCTION str_reverse LANGUAGE WASM ABI BUFFERED_V1
FROM 'str_reverse' :: 'str_reverse'
ARGUMENTS (s String) RETURNS String
SETTINGS serialization_format = 'RowBinary';

SELECT str_reverse(toString(number + 100)) FROM numbers(3);
```

```text theme={null}
001
101
201
```

<div id="abi-assemblyscript">
  ### ABI ASSEMBLYSCRIPT
</div>

Se aplica a módulos generados por el compilador [AssemblyScript](https://www.assemblyscript.org). Cada fila desencadena una llamada a la función exportada, asignando los valores de ClickHouse a primitivos de AssemblyScript y objetos `string`.

**Tipos compatibles**:

* Numéricos: `Int8`/`UInt8`, `Int16`/`UInt16` (ampliados a `i32` en el límite), `Int32`/`UInt32`, `Int64`/`UInt64`, `Float32`, `Float64`

* `String` — se asigna a `string` de AssemblyScript (UTF-16 en la memoria de WASM). ClickHouse gestiona automáticamente la conversión UTF-8 ↔ UTF-16.

* No se admiten clases personalizadas de AssemblyScript como tipos de argumento o de retorno; sus identificadores de clase en tiempo de ejecución no son estables entre compilaciones (consulta [AssemblyScript#2982](https://github.com/AssemblyScript/assemblyscript/issues/2982)).

**Requisitos del módulo**:

El módulo debe compilarse con el entorno de ejecución administrado de AssemblyScript para que se exporten `__new`, `__pin` y `__unpin`. El manejo estándar de cadenas de entrada y salida da por hecho esto. La invocación recomendada:

```bash theme={null}
asc src.ts --runtime incremental --exportRuntime -o src.wasm
```

AssemblyScript también importa `env.abort` para interrupciones del runtime (falta de memoria, comprobaciones de límites, etc.). ClickHouse proporciona esta importación automáticamente: cuando se activa un `abort`, la consulta activa falla con una excepción `WASM_ERROR` que incluye el mensaje de AssemblyScript decodificado y la ubicación en el código fuente.

**Ejemplo**:

```typescript theme={null}
// src.ts
export function add(a: u32, b: u32): u32 {
  return a + b;
}

export function greet(name: string): string {
  return "Hello, " + name + "!";
}
```

Después de compilar con `asc` y cargar el archivo `.wasm` resultante en `system.webassembly_modules`, declare las UDFs de la siguiente manera:

```sql theme={null}
CREATE FUNCTION as_add
    LANGUAGE WASM ABI ASSEMBLYSCRIPT
    FROM 'as_example' :: 'add'
    ARGUMENTS (a UInt32, b UInt32) RETURNS UInt32;

CREATE FUNCTION as_greet
    LANGUAGE WASM ABI ASSEMBLYSCRIPT
    FROM 'as_example' :: 'greet'
    ARGUMENTS (name String) RETURNS String;
```

<div id="note-for-developing-udfs-in-rust">
  ### Nota para desarrollar UDFs en Rust
</div>

Para los programas en Rust, proporcionamos un crate auxiliar [clickhouse-wasm-udf](https://crates.io/crates/clickhouse-wasm-udf) para simplificar el desarrollo de WebAssembly UDFs para ClickHouse. El crate proporciona funciones para la gestión de memoria, por lo que no necesitas implementar manualmente las funciones `clickhouse_create_buffer` y `clickhouse_destroy_buffer`, sino añadir el crate como dependencia. También incluye macros `#[clickhouse_wasm_udf]` para encapsular tus funciones habituales de Rust en el formato ABI requerido.

Con este crate, puedes escribir UDFs así:

```rust theme={null}

use clickhouse_wasm_udf_bindgen::clickhouse_udf;

#[clickhouse_udf]
pub fn some_udf(data: String) -> HashMap<String, String> {
    // Tu implementación aquí
}

```

Las macros generarán una función de envoltura que acepta y devuelve estructuras de búfer, y gestionarán automáticamente la serialización y deserialización mediante `serde`.

<div id="host-api-available-to-modules">
  ## API del host disponible para los módulos
</div>

Las siguientes funciones del host pueden importarse y usarse en los módulos:

* `clickhouse_server_version() -> i64` — devuelve la versión del servidor ClickHouse como un entero (p. ej., 25011001 para v25.11.1.1).
* `clickhouse_throw(ptr: i32, size: i32)` — genera un error con el mensaje proporcionado. Acepta un puntero a la ubicación de memoria que contiene la cadena con el mensaje de error y el tamaño de la cadena.
* `clickhouse_log(ptr: i32, size: i32)` — registra un mensaje en el log de texto del servidor ClickHouse.
* `clickhouse_random(ptr: i32, size: i32)` — rellena la memoria con bytes aleatorios.
* `env.abort(message: i32, fileName: i32, line: i32, column: i32)` — se proporciona para módulos compatibles con AssemblyScript. Al llamarlo (o al activar una trampa del runtime de AssemblyScript que lo invoque), finaliza la UDF con una excepción `WASM_ERROR` que contiene el mensaje decodificado y la ubicación de origen. Los módulos que no importan `env.abort` no se ven afectados.

<div id="settings">
  ## Configuración
</div>

Las siguientes configuraciones a nivel de consulta controlan la ejecución de WebAssembly UDF:

* `webassembly_udf_max_fuel` — Límite de fuel por ejecución de una instancia de WebAssembly UDF. Cada instrucción de WebAssembly consume cierta cantidad de fuel. El valor se escala por 1024 antes de pasarse al runtime, por lo que `webassembly_udf_max_fuel = 1` corresponde a aproximadamente 1024 unidades de fuel. Establézcalo en 0 para no tener ningún límite finito. Se aplica solo a las funciones cuya configuración por función `webassembly_udf_enable_fuel` es true, que es el valor predeterminado.

* `webassembly_udf_max_memory` — Límite de memoria en bytes por instancia de WebAssembly UDF.

* `webassembly_udf_max_input_block_size` — Número máximo de filas que se pasan a una WebAssembly UDF en un solo bloque. Establézcalo en 0 para procesar todas las filas a la vez.

* `webassembly_udf_max_instances` — Número máximo de instancias de WebAssembly UDF que pueden ejecutarse en paralelo por función.

Ejemplo de uso:

```sql theme={null}
SET webassembly_udf_max_fuel = 200000;
SELECT my_wasm_udf(column) FROM table;
```

<div id="see-also">
  ## Véase también
</div>

* [Introducción a las UDF de ClickHouse](/es/reference/functions/regular-functions/udf)
