Skip to content

Commit 45b3c8e

Browse files
committed
mcp: Cover mz_mcp_data_products view semantics
1 parent 7f6c527 commit 45b3c8e

1 file changed

Lines changed: 226 additions & 0 deletions

File tree

test/sqllogictest/rbac_mcp_agent.slt

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1003,6 +1003,232 @@ ALTER ROLE agent RESET restrict_to_user_objects;
10031003
----
10041004
COMPLETE 0
10051005

1006+
# =============================================================================
1007+
# Data product view semantics (mz_mcp_data_products / _details)
1008+
#
1009+
# The RBAC cases above exercise privilege filtering. These cases pin the
1010+
# view logic itself: which objects qualify, how the description is chosen,
1011+
# and how column types map into the JSON Schema. They run as a
1012+
# fully-privileged owner so the object set is deterministic and independent
1013+
# of the agent-role grants above.
1014+
# =============================================================================
1015+
1016+
statement ok
1017+
CREATE SCHEMA dp_semantics;
1018+
1019+
statement ok
1020+
SET search_path = dp_semantics;
1021+
1022+
# A materialized view qualifies as a data product with no index required.
1023+
statement ok
1024+
CREATE MATERIALIZED VIEW mv_plain AS SELECT 1 AS id;
1025+
1026+
# A plain (non-indexed) view does NOT qualify: reading it would trigger a
1027+
# full recompute.
1028+
statement ok
1029+
CREATE VIEW v_unindexed AS SELECT 1 AS id;
1030+
1031+
# A view qualifies only once it has an index.
1032+
statement ok
1033+
CREATE VIEW v_indexed AS SELECT 1 AS id, 'a' AS label;
1034+
1035+
statement ok
1036+
CREATE INDEX v_indexed_idx ON v_indexed (id);
1037+
1038+
query T
1039+
SELECT object_name FROM mz_internal.mz_mcp_data_products
1040+
WHERE object_name LIKE '%"dp_semantics"%' ORDER BY object_name;
1041+
----
1042+
"materialize"."dp_semantics"."mv_plain"
1043+
"materialize"."dp_semantics"."v_indexed"
1044+
1045+
# Multiple indexes on one object must not duplicate its row (SELECT DISTINCT).
1046+
statement ok
1047+
CREATE INDEX v_indexed_idx2 ON v_indexed (label);
1048+
1049+
query T
1050+
SELECT object_name FROM mz_internal.mz_mcp_data_products
1051+
WHERE object_name = '"materialize"."dp_semantics"."v_indexed"';
1052+
----
1053+
"materialize"."dp_semantics"."v_indexed"
1054+
1055+
# -----------------------------------------------------------------------------
1056+
# Description precedence: index comment wins over object comment (COALESCE).
1057+
# -----------------------------------------------------------------------------
1058+
1059+
# No comments: description is NULL.
1060+
query T
1061+
SELECT description FROM mz_internal.mz_mcp_data_products
1062+
WHERE object_name = '"materialize"."dp_semantics"."mv_plain"';
1063+
----
1064+
NULL
1065+
1066+
# Object comment only: description is the object comment.
1067+
statement ok
1068+
COMMENT ON MATERIALIZED VIEW mv_plain IS 'the object comment';
1069+
1070+
query T
1071+
SELECT description FROM mz_internal.mz_mcp_data_products
1072+
WHERE object_name = '"materialize"."dp_semantics"."mv_plain"';
1073+
----
1074+
the object comment
1075+
1076+
# Index comment present: it takes precedence over the object comment. Uses a
1077+
# dedicated single-index view so the COALESCE precedence is unambiguous (with
1078+
# multiple indexes the DISTINCT can surface one row per differing description).
1079+
statement ok
1080+
CREATE VIEW v_desc AS SELECT 1 AS id;
1081+
1082+
statement ok
1083+
CREATE INDEX v_desc_idx ON v_desc (id);
1084+
1085+
statement ok
1086+
COMMENT ON VIEW v_desc IS 'object comment on view';
1087+
1088+
statement ok
1089+
COMMENT ON INDEX v_desc_idx IS 'index comment wins';
1090+
1091+
query T
1092+
SELECT description FROM mz_internal.mz_mcp_data_products
1093+
WHERE object_name = '"materialize"."dp_semantics"."v_desc"';
1094+
----
1095+
index comment wins
1096+
1097+
# -----------------------------------------------------------------------------
1098+
# JSON Schema type mapping in mz_mcp_data_product_details.
1099+
# -----------------------------------------------------------------------------
1100+
1101+
statement ok
1102+
CREATE MATERIALIZED VIEW mv_types AS
1103+
SELECT
1104+
1::int AS c_int,
1105+
1.5::double AS c_double,
1106+
true AS c_bool,
1107+
'x'::text AS c_text,
1108+
'2024-01-01'::date AS c_date,
1109+
'{}'::jsonb AS c_jsonb,
1110+
'\x00'::bytea AS c_bytea,
1111+
'12:34:56'::time AS c_time,
1112+
'2024-01-01 12:00:00'::timestamp AS c_ts,
1113+
'2024-01-01 12:00:00+00'::timestamptz AS c_tstz,
1114+
'00000000-0000-0000-0000-000000000000'::uuid AS c_uuid;
1115+
1116+
# Numeric columns map to JSON Schema type "number".
1117+
query T
1118+
SELECT schema->'properties'->'c_int'->>'type' FROM mz_internal.mz_mcp_data_product_details
1119+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1120+
----
1121+
number
1122+
1123+
query T
1124+
SELECT schema->'properties'->'c_double'->>'type' FROM mz_internal.mz_mcp_data_product_details
1125+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1126+
----
1127+
number
1128+
1129+
# Boolean maps to "boolean".
1130+
query T
1131+
SELECT schema->'properties'->'c_bool'->>'type' FROM mz_internal.mz_mcp_data_product_details
1132+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1133+
----
1134+
boolean
1135+
1136+
# text falls through to the "string" default.
1137+
query T
1138+
SELECT schema->'properties'->'c_text'->>'type' FROM mz_internal.mz_mcp_data_product_details
1139+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1140+
----
1141+
string
1142+
1143+
# date is a string with a format hint.
1144+
query TT
1145+
SELECT schema->'properties'->'c_date'->>'type', schema->'properties'->'c_date'->>'format'
1146+
FROM mz_internal.mz_mcp_data_product_details
1147+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1148+
----
1149+
string date
1150+
1151+
# jsonb maps to a nested "object".
1152+
query T
1153+
SELECT schema->'properties'->'c_jsonb'->>'type' FROM mz_internal.mz_mcp_data_product_details
1154+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1155+
----
1156+
object
1157+
1158+
# bytea is the most distinctive branch: string with the two extra content
1159+
# hints so a JSON Schema consumer knows to Base64-decode the value.
1160+
query TTT
1161+
SELECT
1162+
schema->'properties'->'c_bytea'->>'type',
1163+
schema->'properties'->'c_bytea'->>'contentEncoding',
1164+
schema->'properties'->'c_bytea'->>'contentMediaType'
1165+
FROM mz_internal.mz_mcp_data_product_details
1166+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1167+
----
1168+
string base64 application/octet-stream
1169+
1170+
# time is a string with format=time.
1171+
query TT
1172+
SELECT schema->'properties'->'c_time'->>'type', schema->'properties'->'c_time'->>'format'
1173+
FROM mz_internal.mz_mcp_data_product_details
1174+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1175+
----
1176+
string time
1177+
1178+
# timestamp and timestamptz both match the `ilike 'timestamp%'` branch and
1179+
# map to string with format=date-time.
1180+
query TT
1181+
SELECT schema->'properties'->'c_ts'->>'type', schema->'properties'->'c_ts'->>'format'
1182+
FROM mz_internal.mz_mcp_data_product_details
1183+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1184+
----
1185+
string date-time
1186+
1187+
query TT
1188+
SELECT schema->'properties'->'c_tstz'->>'type', schema->'properties'->'c_tstz'->>'format'
1189+
FROM mz_internal.mz_mcp_data_product_details
1190+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1191+
----
1192+
string date-time
1193+
1194+
# uuid is a string with format=uuid.
1195+
query TT
1196+
SELECT schema->'properties'->'c_uuid'->>'type', schema->'properties'->'c_uuid'->>'format'
1197+
FROM mz_internal.mz_mcp_data_product_details
1198+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1199+
----
1200+
string uuid
1201+
1202+
# -----------------------------------------------------------------------------
1203+
# Column comments surface as the property description; absent otherwise.
1204+
# -----------------------------------------------------------------------------
1205+
1206+
statement ok
1207+
COMMENT ON COLUMN mv_types.c_int IS 'the primary id';
1208+
1209+
query T
1210+
SELECT schema->'properties'->'c_int'->>'description' FROM mz_internal.mz_mcp_data_product_details
1211+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1212+
----
1213+
the primary id
1214+
1215+
# A column with no comment has no description key (jsonb_strip_nulls removes it).
1216+
query T
1217+
SELECT schema->'properties'->'c_double' ? 'description' FROM mz_internal.mz_mcp_data_product_details
1218+
WHERE object_name = '"materialize"."dp_semantics"."mv_types"';
1219+
----
1220+
false
1221+
1222+
# -----------------------------------------------------------------------------
1223+
# Cleanup for this section.
1224+
# -----------------------------------------------------------------------------
1225+
1226+
statement ok
1227+
SET search_path = public;
1228+
1229+
statement ok
1230+
DROP SCHEMA dp_semantics CASCADE;
1231+
10061232
# =============================================================================
10071233
# Cleanup
10081234
# =============================================================================

0 commit comments

Comments
 (0)