## User-defined types

[CQL user-defined types][cql_doc] are ordered sets of named, typed fields. They must be defined in a
keyspace:

```
CREATE TYPE ks.type1 (
  a int,
  b text,
  c float);
```

And can then be used as a column type in tables, or a field type in other user-defined types in that
keyspace:

```
CREATE TABLE ks.collect_things (
  pk int,
  ck1 text,
  ck2 text,
  v frozen<type1>,
  PRIMARY KEY (pk, ck1, ck2)
);

CREATE TYPE ks.type2 (v frozen<type1>);
```

### Fetching UDTs from results

The driver maps UDT columns to the [UdtValue] class, which exposes getters and setters to access
individual fields by index or name:

```java
Row row = session.execute("SELECT v FROM ks.collect_things WHERE pk = 1").one();

UdtValue udtValue = row.getUdtValue("v");
int a = udtValue.getInt(0);
String b = udtValue.getString("b");
Float c = udtValue.getFloat(2);
```

### Using UDTs as parameters

Statements may contain UDTs as bound values:

```java
PreparedStatement ps =
  session.prepare(
      "INSERT INTO ks.collect_things (pk, ck1, ck2, v) VALUES (:pk, :ck1, :ck2, :v)");
```

To create a new UDT value, you must first have a reference to its [UserDefinedType]. There are
various ways to get it:

* from the statement's metadata

    ```java
    UserDefinedType udt = (UserDefinedType) ps.getVariableDefinitions().get("v").getType();
    ```

* from the driver's [schema metadata](../metadata/schema/):

    ```java
    UserDefinedType udt = session.getMetadata().getKeyspace("ks").getUserDefinedType("type1");
    ```

* from another UDT value:

    ```java
    UserDefinedType udt = udtValue.getType();
    ```
  
Note that the driver's official API does not expose a way to build [UserDefinedType] instances
manually. This is because the type's internal definition must precisely match the database schema;
if it doesn't (for example if the fields are not in the same order), you run the risk of inserting
corrupt data, that you won't be able to read back. There is still a way to do it with the driver,
but it's part of the [internal API](../../api_conventions/):

```java
// Advanced usage: make sure you understand the risks
import com.datastax.oss.driver.internal.core.type.UserDefinedTypeBuilder;

UserDefinedType udt =
    new UserDefinedTypeBuilder("ks", "type1")
        .withField("a", DataTypes.INT)
        .withField("b", DataTypes.TEXT)
        .withField("c", DataTypes.FLOAT)
        .build();
```

Note that a manually created type is [detached](../detachable_types).

 
Once you have the type, call `newValue()` and set the fields:

```java
UdtValue udtValue = udt.newValue().setInt(0, 1).setString(1, "hello").setFloat(2, 2.3f);

// Or as a one-liner for convenience:
UdtValue udtValue = udt.newValue(1, "hello", 2.3f);
```

And bind your UDT value like any other type:

```java
BoundStatement bs =
    ps.boundStatementBuilder()
        .setInt("pk", 1)
        .setString("ck1", "1")
        .setString("ck2", "1")
        .setUdtValue("v", udtValue)
        .build();
session.execute(bs);
```

[cql_doc]: https://docs.datastax.com/en/cql/3.3/cql/cql_reference/cqlRefUDType.html

[UdtValue]:        https://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/data/UdtValue.html
[UserDefinedType]: https://docs.datastax.com/en/drivers/java/4.0/com/datastax/oss/driver/api/core/type/UserDefinedType.html