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
405 changes: 76 additions & 329 deletions docs/en/guides/54-query/03-udf.md

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,27 +1,98 @@
---
title: ALTER FUNCTION
sidebar_position: 2
sidebar_position: 3
---
import FunctionDescription from '@site/src/components/FunctionDescription';

<FunctionDescription description="Introduced or updated: v1.2.116"/>

Alters a user-defined function.
Alters a user-defined function. Supports all function types: Scalar SQL, Tabular SQL, and Embedded functions.

## Syntax

### For Scalar SQL Functions
```sql
ALTER FUNCTION [ IF NOT EXISTS ] <function_name>
AS (<input_param_names>) -> <lambda_expression>
ALTER FUNCTION [ IF EXISTS ] <function_name>
( [<parameter_list>] )
RETURNS <return_type>
AS $$ <expression> $$
[ DESC='<description>' ]
```

### For Tabular SQL Functions
```sql
ALTER FUNCTION [ IF EXISTS ] <function_name>
( [<parameter_list>] )
RETURNS TABLE ( <column_definition_list> )
AS $$ <sql_statement> $$
[ DESC='<description>' ]
```

### For Embedded Functions
```sql
ALTER FUNCTION [ IF EXISTS ] <function_name>
( [<parameter_list>] )
RETURNS <return_type>
LANGUAGE <language>
[IMPORTS = ('<import_path>', ...)]
[PACKAGES = ('<package_path>', ...)]
HANDLER = '<handler_name>'
AS $$ <function_code> $$
[ DESC='<description>' ]
```

## Examples

### Altering Scalar SQL Function
```sql
-- Create a scalar function
CREATE FUNCTION calculate_tax(income DECIMAL)
RETURNS DECIMAL
AS $$ income * 0.2 $$;

-- Modify the function to use progressive tax rate
ALTER FUNCTION calculate_tax(income DECIMAL)
RETURNS DECIMAL
AS $$
CASE
WHEN income <= 50000 THEN income * 0.15
ELSE income * 0.25
END
$$;
```

### Altering Tabular SQL Function
```sql
-- Create a table function
CREATE FUNCTION get_employees()
RETURNS TABLE (id INT, name VARCHAR(100))
AS $$ SELECT id, name FROM employees $$;

-- Modify to include department and salary
ALTER FUNCTION get_employees()
RETURNS TABLE (id INT, name VARCHAR(100), department VARCHAR(100), salary DECIMAL)
AS $$ SELECT id, name, department, salary FROM employees $$;
```

### Altering Embedded Function
```sql
-- Create a UDF
CREATE FUNCTION a_plus_3 AS (a) -> a+3+3;
-- Create a Python function
CREATE FUNCTION simple_calc(x INT)
RETURNS INT
LANGUAGE python
HANDLER = 'calc'
AS $$
def calc(x):
return x * 2
$$;

-- Modify the lambda expression of the UDF
ALTER FUNCTION a_plus_3 AS (a) -> a+3;
-- Modify to use a different calculation
ALTER FUNCTION simple_calc(x INT)
RETURNS INT
LANGUAGE python
HANDLER = 'calc'
AS $$
def calc(x):
return x * 3 + 1
$$;
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
title: CREATE EMBEDDED FUNCTION
sidebar_position: 2
---
import FunctionDescription from '@site/src/components/FunctionDescription';

<FunctionDescription description="Introduced or updated: v1.2.339"/>

Creates an Embedded UDF using programming languages (Python, JavaScript, WASM). Uses the same unified `$$` syntax as SQL functions for consistency.

## Syntax

```sql
CREATE [ OR REPLACE ] FUNCTION [ IF NOT EXISTS ] <function_name>
( [<parameter_list>] )
RETURNS <return_type>
LANGUAGE <language>
[IMPORTS = ('<import_path>', ...)]
[PACKAGES = ('<package_path>', ...)]
HANDLER = '<handler_name>'
AS $$ <function_code> $$
[ DESC='<description>' ]
```

Where:
- `<parameter_list>`: Comma-separated list of parameters with their types (e.g., `x INT, name VARCHAR`)
- `<return_type>`: The data type of the function's return value
- `<language>`: Programming language (`python`, `javascript`, `wasm`)
- `<import_path>`: Stage files to import (e.g., `@s_udf/your_file.zip`)
- `<package_path>`: Packages to install from pypi (Python only)
- `<handler_name>`: Name of the function in the code to call
- `<function_code>`: The implementation code in the specified language

## Supported Languages

| Language | Description | Enterprise Required | Package Support |
|----------|-------------|-------------------|-----------------|
| `python` | Python 3 with standard library | Yes | PyPI packages via PACKAGES |
| `javascript` | Modern JavaScript (ES6+) | No | No |
| `wasm` | WebAssembly (Rust compiled) | No | No |

## Data Type Mappings

### Python
| Databend Type | Python Type |
|--------------|-------------|
| NULL | None |
| BOOLEAN | bool |
| INT | int |
| FLOAT/DOUBLE | float |
| DECIMAL | decimal.Decimal |
| VARCHAR | str |
| BINARY | bytes |
| LIST | list |
| MAP | dict |
| STRUCT | object |
| JSON | dict/list |

### JavaScript
| Databend Type | JavaScript Type |
|--------------|----------------|
| NULL | null |
| BOOLEAN | Boolean |
| INT | Number |
| FLOAT/DOUBLE | Number |
| DECIMAL | BigDecimal |
| VARCHAR | String |
| BINARY | Uint8Array |
| DATE/TIMESTAMP | Date |
| ARRAY | Array |
| MAP | Object |
| STRUCT | Object |
| JSON | Object/Array |

## Access Control Requirements

| Privilege | Object Type | Description |
|:----------|:--------------|:---------------|
| SUPER | Global, Table | Operates a UDF |

To create an embedded function, the user performing the operation or the [current_role](/guides/security/access-control/roles) must have the SUPER [privilege](/guides/security/access-control/privileges).

## Examples

### Python Function

```sql
-- Simple Python function
CREATE FUNCTION calculate_age_py(VARCHAR)
RETURNS INT
LANGUAGE python HANDLER = 'calculate_age'
AS $$
from datetime import datetime

def calculate_age(birth_date_str):
birth_date = datetime.strptime(birth_date_str, '%Y-%m-%d')
today = datetime.now()
age = today.year - birth_date.year
if (today.month, today.day) < (birth_date.month, birth_date.day):
age -= 1
return age
$$;

-- Use the function
SELECT calculate_age_py('1990-05-15') AS age;
```

### JavaScript Function

```sql
-- JavaScript function for age calculation
CREATE FUNCTION calculate_age_js(VARCHAR)
RETURNS INT
LANGUAGE javascript HANDLER = 'calculateAge'
AS $$
export function calculateAge(birthDateStr) {
const birthDate = new Date(birthDateStr);
const today = new Date();

let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();

if (monthDiff < 0 || (monthDiff === 0 && today.getDate() < birthDate.getDate())) {
age--;
}

return age;
}
$$;

-- Use the function
SELECT calculate_age_js('1990-05-15') AS age;
```

### Python Function with Packages

```sql
CREATE FUNCTION ml_model_score()
RETURNS FLOAT
LANGUAGE python IMPORTS = ('@s1/model.zip') PACKAGES = ('scikit-learn') HANDLER = 'model_score'
AS $$
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier

def model_score():
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=42)

model = RandomForestClassifier()
model.fit(X_train, y_train)
return model.score(X_test, y_test)
$$;

-- Use the function
SELECT ml_model_score() AS accuracy;
```

### WASM Function

First, create a Rust project and compile to WASM:

```toml
# Cargo.toml
[package]
name = "arrow-udf-example"
version = "0.1.0"

[lib]
crate-type = ["cdylib"]

[dependencies]
arrow-udf = "0.8"
```

```rust
// src/lib.rs
use arrow_udf::function;

#[function("fib(int) -> int")]
fn fib(n: i32) -> i32 {
let (mut a, mut b) = (0, 1);
for _ in 0..n {
let c = a + b;
a = b;
b = c;
}
a
}
```

Build and deploy:

```bash
cargo build --release --target wasm32-wasip1
# Upload to stage
CREATE STAGE s_udf;
PUT fs:///target/wasm32-wasip1/release/arrow_udf_example.wasm @s_udf/;
```

```sql
-- Create WASM function
CREATE FUNCTION fib_wasm(INT)
RETURNS INT
LANGUAGE wasm HANDLER = 'fib'
AS $$@s_udf/arrow_udf_example.wasm$$;

-- Use the function
SELECT fib_wasm(10) AS fibonacci_result;
```

Original file line number Diff line number Diff line change
@@ -1,21 +1,28 @@
---
title: CREATE FUNCTION
sidebar_position: 1
title: CREATE SCALAR FUNCTION
sidebar_position: 0
---
import FunctionDescription from '@site/src/components/FunctionDescription';

<FunctionDescription description="Introduced or updated: v1.2.339"/>
<FunctionDescription description="Introduced or updated: v1.2.799"/>

Creates a user-defined function.
Creates a Scalar SQL UDF using Databend's unified function syntax.

## Syntax

```sql
CREATE [ OR REPLACE ] FUNCTION [ IF NOT EXISTS ] <function_name>
AS ( <input_param_names> ) -> <lambda_expression>
( [<parameter_list>] )
RETURNS <return_type>
AS $$ <expression> $$
[ DESC='<description>' ]
```

Where:
- `<parameter_list>`: Optional comma-separated list of parameters with their types (e.g., `x INT, y FLOAT`)
- `<return_type>`: The data type of the function's return value
- `<expression>`: SQL expression that defines the function logic

## Access control requirements

| Privilege | Object Type | Description |
Expand All @@ -26,4 +33,31 @@ To create a user-defined function, the user performing the operation or the [cur

## Examples

See [Usage Examples](/guides/query/udf#usage-examples).
```sql
-- Create a function to calculate area of a circle
CREATE FUNCTION area_of_circle(radius FLOAT)
RETURNS FLOAT
AS $$
pi() * radius * radius
$$;

-- Create a function to calculate age in years
CREATE FUNCTION calculate_age(birth_date DATE)
RETURNS INT
AS $$
date_diff('year', birth_date, now())
$$;

-- Create a function with multiple parameters
CREATE FUNCTION calculate_bmi(weight_kg FLOAT, height_m FLOAT)
RETURNS FLOAT
AS $$
weight_kg / (height_m * height_m)
$$;

-- Use the functions
SELECT area_of_circle(5.0) AS circle_area;
SELECT calculate_age('1990-05-15') AS age;
SELECT calculate_bmi(70.0, 1.75) AS bmi;
```

Loading
Loading