diff --git a/src/driver/introspection.rs b/src/driver/introspection.rs index a9c94fc..1ce577b 100644 --- a/src/driver/introspection.rs +++ b/src/driver/introspection.rs @@ -20,7 +20,7 @@ use std::collections::HashMap; pub const Q_GET_TABLES: &str = "\ SELECT \ t.name, \ - TRY_CONVERT(nvarchar(max), ep.value) AS comment \ + CONVERT(nvarchar(max), ep.value) AS comment \ FROM sys.tables t \ JOIN sys.schemas s ON t.schema_id = s.schema_id \ LEFT JOIN sys.extended_properties ep \ @@ -57,7 +57,7 @@ SELECT \ AND i.is_primary_key = 1 \ ), 0) AS BIT) AS is_pk, \ dc.definition AS default_value, \ - TRY_CONVERT(nvarchar(max), ep.value) AS comment \ + CONVERT(nvarchar(max), ep.value) AS comment \ FROM sys.columns c \ JOIN sys.types ty ON c.user_type_id = ty.user_type_id \ LEFT JOIN sys.default_constraints dc \ @@ -218,7 +218,7 @@ SELECT \ AND i.is_primary_key = 1 \ ), 0) AS BIT) AS is_pk, \ dc.definition AS default_value, \ - TRY_CONVERT(nvarchar(max), ep.value) AS comment \ + CONVERT(nvarchar(max), ep.value) AS comment \ FROM sys.columns c \ JOIN sys.tables t ON c.object_id = t.object_id \ JOIN sys.schemas s ON t.schema_id = s.schema_id \ diff --git a/src/driver/introspection/tests.rs b/src/driver/introspection/tests.rs index b68330e..f5f232c 100644 --- a/src/driver/introspection/tests.rs +++ b/src/driver/introspection/tests.rs @@ -11,7 +11,7 @@ fn q_get_tables_queries_descriptions_with_object_scope() { assert!(Q_GET_TABLES.contains("ep.major_id = t.object_id")); assert!(Q_GET_TABLES.contains("ep.minor_id = 0")); assert!(Q_GET_TABLES.contains("ep.name = N'MS_Description'")); - assert!(Q_GET_TABLES.contains("TRY_CONVERT(nvarchar(max), ep.value) AS comment")); + assert!(Q_GET_TABLES.contains("CONVERT(nvarchar(max), ep.value) AS comment")); assert!(Q_GET_TABLES.contains("@P1")); assert!(Q_GET_TABLES.contains("ORDER BY t.name")); } @@ -29,7 +29,7 @@ fn q_get_columns_joins_sys_types_and_reports_pk() { assert!(Q_GET_COLUMNS.contains("ep.major_id = c.object_id")); assert!(Q_GET_COLUMNS.contains("ep.minor_id = c.column_id")); assert!(Q_GET_COLUMNS.contains("ep.name = N'MS_Description'")); - assert!(Q_GET_COLUMNS.contains("TRY_CONVERT(nvarchar(max), ep.value) AS comment")); + assert!(Q_GET_COLUMNS.contains("CONVERT(nvarchar(max), ep.value) AS comment")); assert!(Q_GET_COLUMNS.contains("c.is_computed AS is_generated")); assert!(Q_GET_COLUMNS.contains("OBJECT_ID(@P1)")); assert!(Q_GET_COLUMNS.contains("ORDER BY c.column_id")); @@ -167,7 +167,7 @@ fn q_get_all_columns_batch_groups_by_table() { assert!(Q_GET_ALL_COLUMNS_BATCH.contains("ep.major_id = c.object_id")); assert!(Q_GET_ALL_COLUMNS_BATCH.contains("ep.minor_id = c.column_id")); assert!(Q_GET_ALL_COLUMNS_BATCH.contains("ep.name = N'MS_Description'")); - assert!(Q_GET_ALL_COLUMNS_BATCH.contains("TRY_CONVERT(nvarchar(max), ep.value) AS comment")); + assert!(Q_GET_ALL_COLUMNS_BATCH.contains("CONVERT(nvarchar(max), ep.value) AS comment")); assert!(Q_GET_ALL_COLUMNS_BATCH.contains("@P1")); assert!(Q_GET_ALL_COLUMNS_BATCH.contains("ORDER BY t.name, c.column_id")); // Must emit the table name so the caller can group rows. diff --git a/src/driver/triggers/mod.rs b/src/driver/triggers/mod.rs index 8c2a691..81286f4 100644 --- a/src/driver/triggers/mod.rs +++ b/src/driver/triggers/mod.rs @@ -10,7 +10,7 @@ SELECT tr.[name], tb.[name], WHERE te.[object_id] = tr.[object_id] ORDER BY te.[type_desc] FOR XML PATH(N''), TYPE - ).value(N'.', N'nvarchar(max)'), 1, 4, N''), + ).value('.', 'nvarchar(max)'), 1, 4, N''), CASE WHEN tr.[is_instead_of_trigger] = 1 THEN N'INSTEAD OF' ELSE N'AFTER' END, sm.[definition] FROM sys.triggers tr diff --git a/src/driver/triggers/tests.rs b/src/driver/triggers/tests.rs index d53023c..482610e 100644 --- a/src/driver/triggers/tests.rs +++ b/src/driver/triggers/tests.rs @@ -11,3 +11,8 @@ fn drop_trigger_uses_schema_qualified_identifier() { "DROP TRIGGER [dbo].[audit_orders]" ); } + +#[test] +fn list_triggers_xml_value_uses_non_unicode_literals() { + assert!(LIST_TRIGGERS.contains(".value('.', 'nvarchar(max)')")); +} diff --git a/tests/live_db.rs b/tests/live_db.rs index 4e9f061..926622f 100644 --- a/tests/live_db.rs +++ b/tests/live_db.rs @@ -1116,6 +1116,61 @@ fn zero_row_select_preserves_column_headers() { assert!(result_rows(&result).is_empty()); } +#[test] +fn get_triggers_lists_events_and_timing() { + let mut plugin = Plugin::with_scratch_database(); + plugin.reset_table("trigger_target", "id INT NOT NULL PRIMARY KEY"); + plugin.execute(format!( + "EXEC(N'CREATE TRIGGER [{TEST_SCHEMA}].[trg_target_audit] ON [{TEST_SCHEMA}].[trigger_target] \ + AFTER INSERT, UPDATE AS SET NOCOUNT ON')" + )); + + let triggers = plugin.call_ok( + "get_triggers", + json!({ "params": connection_params(), "schema": TEST_SCHEMA }), + ); + let trigger = triggers + .as_array() + .unwrap() + .iter() + .find(|t| t["name"] == "trg_target_audit") + .expect("trigger listed"); + assert_eq!(trigger["table_name"], "trigger_target"); + assert_eq!(trigger["event"], "INSERT OR UPDATE"); + assert_eq!(trigger["timing"], "AFTER"); + + plugin.execute(format!("DROP TABLE [{TEST_SCHEMA}].[trigger_target]")); +} + +#[test] +fn metadata_introspection_works_at_compatibility_level_100() { + let mut plugin = Plugin::spawn(); + let master = connection_params_for("master", "ss003-master"); + plugin.execute_with( + &master, + "IF DB_ID(N'tabularis_compat100') IS NULL EXEC(N'CREATE DATABASE [tabularis_compat100]'); \ + ALTER DATABASE [tabularis_compat100] SET COMPATIBILITY_LEVEL = 100", + ); + let params = connection_params_for("tabularis_compat100", "ss003-compat100"); + plugin.execute_with( + ¶ms, + "DROP TABLE IF EXISTS dbo.legacy; CREATE TABLE dbo.legacy (id INT NOT NULL PRIMARY KEY)", + ); + + for (method, extra) in [ + ("get_tables", json!({})), + ("get_columns", json!({ "table": "legacy" })), + ("get_all_columns_batch", json!({})), + ] { + let mut request = json!({ "params": params, "schema": "dbo" }); + request + .as_object_mut() + .unwrap() + .extend(extra.as_object().unwrap().clone()); + plugin.call_ok(method, request); + } +} + #[test] fn multi_statement_and_batch_rpc_preserve_result_sets_and_temp_table_session() { let mut plugin = Plugin::with_scratch_database();