# Apply a UDF

## Single record

Use the Aerospike C client API `aerospike_key_apply()` to apply a **Record UDF** against a record in the database.

Before using `aerospike_key_apply()`, the UDF module that contains the function must register with the Aerospike server. See [Register UDF](https://aerospike.com/docs/develop/client/c/usage/udf/manage).

This example is an excerpt from _examples/basic\_examples/get_ in the Aerospike C client package.

To continue, the client must have an [established the cluster connection](https://aerospike.com/docs/develop/client/c/connect).

## Defining the UDF

To define `bin_transform` in the `basice_udf` module:

```lua
function bin_transform(record, bin_name, x, y)

  record[bin_name] = (record[bin_name] * x) + y

  aerospike:update(record)

  return record[bin_name]

end
```

This simple arithmetic UDF has three arguments: _bin\_name_, _x_, and _y_. It updates the value in the specified bin after performing the arithmetic operation, and returns the resulting bin value.

## Initializing a Key

The application identifies records in the database using a key. In this example, the _key_ value is the string _test-key_, stored in namespace _test_ within set _test-set_. _key_ can be other data types such as integer or blob.

```cpp
as_key key;

as_key_init_str(&key, "test", "test-set", "test-key");
```

## Passing Parameters to the UDF

The _bin\_transform_ UDF requires a string parameter and two integer parameters, so first, populate an argument list:

```cpp
as_arraylist args;

as_arraylist_inita(&args, 3);

as_arraylist_append_str(&args, "test-bin-2");

as_arraylist_append_int64(&args, 4);

as_arraylist_append_int64(&args, 400);
```

## Applying a UDF on a Record

To call the UDF on the record in the database using _key_:

```cpp
as_val * result = NULL;

if (aerospike_key_apply(&as, &err, NULL, &key, "mymodule", "add",

  (as_list *) &args, &result) != AEROSPIKE_OK) {

    fprintf(stderr, "err(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

The value from the `bin_transform()` UDF returns in the `result` parameter:

-   If _key_ does not exist, `AEROSPIKE_ERR_RECORD_NOT_FOUND` returns.
-   If the UDF is found or if there is a run-time error executing the UDF, details on the error returns in `as_error`.

## Cleaning Up Resources

Use `as_val_destroy()` to release the UDF and associated resources:

```cpp
as_val_destroy(&result);
```

Use `as_arraylist_destroy()` to clean up the arguments list:

```cpp
as_arraylist_destroy(&args);
```

::: note
The key does not require an explicit destroy call since it and its members are created on the stack.
:::

## Transform

Use the Aerospike C client to scan the records in the database and transform each record using UDFs.

In SQL, a transformation on all rows in a table is performed as an `UPDATE` statement without predicates:

```cpp
UPDATE test.demo

SET a = 1, b = 2, c = 3
```

The Aerospike C client provides similar capabilities, but goes beyond what SQL provides by allowing you to transform records by applying a **Record UDF** on each record. These Record UDFs are applied to individual records, can have arguments, and can read and write the bins of a record and perform calculations.

Scanning and applying a Record UDF on each record can only be performed in the background; that is, the client sends the scan request to the database and does not wait for results. The scan is queued and runs on the database, and no results return to the client. The client has a scan ID, so can check status.

## Defining the Scan

For scans that transform each record, define a UDF to execute on each record and execute the scan using the background scan operation, `aerospike_scan_background()`.

You build the scan just like in Scan Records, but use `as_scan_apply_each()`:

```cpp
as_scan scan;

as_scan_init(&scan, "test", "demo");

as_scan_apply_each(&scan, "mymodule", "mytransform", NULL);
```

Operation sequence:

1.  Create an `as_scan` on the stack (line 1).
2.  Initialize the scan to scan the Namespace _test_ within set _demo_ (line 2).
3.  Add a Record UDF to apply to each record scanned.

::: note
The UDF `mytransform()` is defined in the `mymodule` UDF module. The UDF in this example is provided arguments.
:::

## Defining the Record UDF

The example uses the `mytransform` Record UDF defined in `mymodule` and mimics the SQL statement above.

```lua
function mytransform(rec)

    rec['a'] = 1

    rec['b'] = 2

    rec['c'] = 3

    aerospike:update(rec)

end
```

This more elaborate example increments _a_, calculates _b_ based on _a_, and calculates _c_ based on the values of _a_ and _b_:

```lua
function mytransform(rec)

    rec['a'] = rec['a'] + 1

    rec['b'] = rec['a'] * 2

    rec['c'] = rec['a'] + rec['b']

    aerospike:update(rec)

end
```

## Executing the Scan

To execute the scan using `aerospike_scan_background()`:

```cpp
uint64_t scan_id = 0;

if (aerospike_scan_background(&as, &err, NULL, &scan, &scan_id) != AEROSPIKE_OK) {

    fprintf(stderr, "error(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

`scan_id` queries the scan status. If `scan_id` = 0 (zero), the scan operation generates and sets the value of `scan_id`.

## Checking Scan Status

To query scan status using `aerospike_scan_info()`:

```cpp
as_scan_info scan_info;

if (aerospike_scan_info(&as, &err, NULL, scan_id, &scan_info) != AEROSPIKE_OK) {

    fprintf(stderr, "error(%d) %s at [%s:%d]\n", err.code, err.message, err.file, err.line);

}
```

This populates `as_scan_info` with the scan status.