Return a Result that is empty if all tables, columns, and capture instances have the necessary permissions to and an error if any table, column, or capture instance does not have the necessary permissions for tracking changes.
(
client: &mut Client,
capture_instances: impl IntoIterator<Item = &str>,
)
| 935 | /// or capture instance does not have the necessary permissions |
| 936 | /// for tracking changes. |
| 937 | pub async fn validate_source_privileges( |
| 938 | client: &mut Client, |
| 939 | capture_instances: impl IntoIterator<Item = &str>, |
| 940 | ) -> Result<(), SqlServerError> { |
| 941 | let params: SmallVec<[_; 1]> = capture_instances.into_iter().collect(); |
| 942 | |
| 943 | if params.is_empty() { |
| 944 | return Ok(()); |
| 945 | } |
| 946 | |
| 947 | let params_dyn: SmallVec<[_; 1]> = params |
| 948 | .iter() |
| 949 | .map(|instance| { |
| 950 | let instance: &dyn tiberius::ToSql = instance; |
| 951 | instance |
| 952 | }) |
| 953 | .collect(); |
| 954 | |
| 955 | let param_indexes = (1..params.len() + 1) |
| 956 | .map(|idx| format!("@P{}", idx)) |
| 957 | .join(", "); |
| 958 | |
| 959 | // NB(ptravers): we rely on HAS_PERMS_BY_NAME to check both table and column permissions. |
| 960 | let capture_instance_query = format!( |
| 961 | " |
| 962 | SELECT |
| 963 | SCHEMA_NAME(o.schema_id) + '.' + o.name AS qualified_table_name, |
| 964 | ct.capture_instance AS capture_instance, |
| 965 | COALESCE(HAS_PERMS_BY_NAME(SCHEMA_NAME(o.schema_id) + '.' + o.name, 'OBJECT', 'SELECT'), 0) AS table_select, |
| 966 | COALESCE(HAS_PERMS_BY_NAME('cdc.' + QUOTENAME(ct.capture_instance + '_CT') , 'OBJECT', 'SELECT'), 0) AS capture_table_select |
| 967 | FROM cdc.change_tables ct |
| 968 | JOIN sys.objects o ON o.object_id = ct.source_object_id |
| 969 | WHERE ct.capture_instance IN ({param_indexes}); |
| 970 | " |
| 971 | ); |
| 972 | |
| 973 | let rows = client |
| 974 | .query(capture_instance_query, ¶ms_dyn[..]) |
| 975 | .await?; |
| 976 | |
| 977 | let mut capture_instances_without_perms = vec![]; |
| 978 | let mut tables_without_perms = vec![]; |
| 979 | |
| 980 | for row in rows { |
| 981 | let table: &str = row |
| 982 | .try_get("qualified_table_name") |
| 983 | .context("getting table column")? |
| 984 | .ok_or_else(|| anyhow::anyhow!("no table column?"))?; |
| 985 | |
| 986 | let capture_instance: &str = row |
| 987 | .try_get("capture_instance") |
| 988 | .context("getting capture_instance column")? |
| 989 | .ok_or_else(|| anyhow::anyhow!("no capture_instance column?"))?; |
| 990 | |
| 991 | let permitted_table: i32 = row |
| 992 | .try_get("table_select") |
| 993 | .context("getting table_select column")? |
| 994 | .ok_or_else(|| anyhow::anyhow!("no table_select column?"))?; |
no test coverage detected