transition from UUID strings to a full-fledged UUID type
General Summary
Usage of UUID type is inconsistent across database internals.
Expected Behavior
-
instance_uuid->UUID; - System tables should store UUID strings using
UUIDtype.
Current Behavior
-
instance_uuid->TEXT; - System tables store UUID strings using
TEXTtype.
Steps to Reproduce
admin=> EXPLAIN SELECT instance_uuid();
QUERY PLAN
---------------------------------------------------------
projection (".proc_instance_uuid"(())::text -> "col_1")
execution options:
sql_vdbe_opcode_max = 45000
sql_motion_row_max = 5000
buckets = any
(5 rows)
Additional Context
The observed front of work is as follows:
- Make
instance_uuidreturnUUIDtype; - System tables should store UUID strings using
UUIDtype; - Migrating system tables on upgrade must not fail.
In addition to the above, I would like to mention that simply changing only the return type of
instance_uuidjust now is a bad option, since it will break the UX in the sense that now user will have toCASTfromUUIDtoTEXT, since in the system tables we still haveTEXTfields where these UUIDs are stored.
Possible Solution
Fixing the return type of the scalar function instance_uuid is quite simple:
// `sbroad/sbroad-core/src/executor/engine.rs:get_builtin_functions`
Function::new_volatile(
get_real_function_name("instance_uuid")
.expect("shouldn't fail")
.into(),
- DerivedType::new(Type::String),
+ DerivedType::new(Type::Uuid),
false,
),
and
// `sbroad/sbroad-core/src/frontend/sql/type_system.rs:default_type_system`
Function::new_scalar(
get_real_function_name("instance_uuid").expect("shouldn't fail"),
[],
- Text,
+ Uuid,
),
and
// `src/pgproto/value.rs:PgValue::try_from_rmpv`
+ (Value::String(v), Type::UUID) => {
+ let Some(s) = v.as_str() else {
+ Err(EncodingError::new(format!("couldn't encode string: {v:?}")))?
+ };
+ let Ok(uuid) = Uuid::from_str(s) else {
+ Err(EncodingError::new(format!(
+ "couldn't parse string as valid UUID: {s:?}"
+ )))?
+ };
+ Ok(PgValue::Uuid(uuid))
+ }
Speaking about migrating system tables and their data to a new type - this is a rather non-trivial task that has two solutions:
- Repack all values from the required fields into a new type "on the fly";
- Create a new column, copy values with new types into it, clear (via
NULL) the previous column, delete the old column, rename the new column to the previous name.