Ordered set of named, typed fields, e.g. { street: '1 Main St', zip: 12345}
.
row.getUdtValue()
/ boundStatement.setUdtValue()
.udtValue.getString("street")
, udtValue.setInt(1, 12345)
...udtValue.getType()
.UserDefinedTypeBuilder
(not recommended, dangerous if you build a type that doesn't match the database schema).userDefinedType.newValue()
.CQL user-defined types 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>);
The driver maps UDT columns to the UdtValue class, which exposes getters and setters to access individual fields by index or name:
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);
Statements may contain UDTs as bound values:
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
UserDefinedType udt = (UserDefinedType) ps.getVariableDefinitions().get("v").getType();
from the driver's schema metadata:
UserDefinedType udt = session.getMetadata() .getKeyspace("ks") .flatMap(ks -> ks.getUserDefinedType("type1")) .orElseThrow(() -> new IllegalArgumentException("Missing UDT definition"));
from another UDT value:
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:
// 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.
Once you have the type, call newValue()
and set the fields:
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:
BoundStatement bs = ps.boundStatementBuilder() .setInt("pk", 1) .setString("ck1", "1") .setString("ck2", "1") .setUdtValue("v", udtValue) .build(); session.execute(bs);