Use lowercase sys.synonyms in mssql. #2225
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Description
The sys.synonyms view is actually lowercase in mssql. Case-insensitive database collations are fine with our use of SYS.SYNONYMS, but case sensitive ones like Latin1_General_BIN2 or any that end in BIN or BIN2 are not.
Fixes #2044
Dev Handoff Notes (Internal Use)
Links
Testing
Dev Verification
Started a database with a BIN collation:
docker run ~~e ACCEPT_EULA=Y -e MSSQL_PID="Developer"~~ e MSSQL_SA_PASSWORD="LiquibasePass1" ~~e MSSQL_TCP_PORT=14333~~ e MSSQL_COLLATION=Latin1_General_BIN2 ~~p 14333:14333~~ d mcr.microsoft.com/mssql/server:20 19-GA-ubuntu-16.04
then ran
liquibase generate-changelog
.Prior to the fix, it outputs a fine-level message of
Cannot get object dependencies
like[2021-11-18 10:52:55] FINE [liquibase.diff] Cannot get object dependencies: Error executing SQL select object_schema_name(referencing_id) as referencing_schema_name, object_name(referencing_id) as referencing_name, object_name(referenced_id) as referenced_name, object_schema_name(referenced_id) as referenced_schema_name from sys.sql_expression_dependencies depz where (object_schema_name(referenced_id)='dbo') UNION select object_schema_name(object_id) as referencing_schema_name, object_name(object_id) as referencing_name, object_name(parent_object_id) as referenced_name, object_schema_name(parent_object_id) as referenced_schema_name from sys.objects where parent_object_id > 0 and is_ms_shipped=0 and (object_schema_name(object_id)='dbo') UNION select object_schema_name(fk.object_id) as referencing_schema_name, fk.name as referencing_name, i.name as referenced_name, object_schema_name(i.object_id) as referenced_schema_name from sys.foreign_keys fk join sys.indexes i on fk.referenced_object_id=i.object_id and fk.key_index_id=i.index_id where fk.is_ms_shipped=0 and (object_schema_name(fk.object_id)='dbo') UNION select object_schema_name(i.object_id) as referencing_schema_name, object_name(i.object_id) as referencing_name, s.name as referenced_name, null as referenced_schema_name from sys.indexes i join sys.partition_schemes s on i.data_space_id = s.data_space_id UNION select null as referencing_schema_name, s.name as referencing_name, f.name as referenced_name, null as referenced_schema_name from sys.partition_functions f join sys.partition_schemes s on s.function_id=f.function_id UNION select null as referencing_schema_name, s.name as referencing_name, fg.name as referenced_name, null as referenced_schema_name from sys.partition_schemes s join sys.destination_data_spaces ds on s.data_space_id=ds.partition_scheme_id join sys.filegroups fg on ds.data_space_id=fg.data_space_id UNION select distinct null as referencing_schema_name, f.name as referencing_name, ds.name as referenced_name, null as referenced_schema_name from sys.database_files f join sys.data_spaces ds on f.data_space_id=ds.data_space_id where f.data_space_id > 1 UNION select object_schema_name(t.object_id) as referencing_schema_name, t.name as referencing_name, ds.name as referenced_name, null as referenced_schema_name from sys.tables t join sys.data_spaces ds on t.filestream_data_space_id=ds.data_space_id where t.filestream_data_space_id > 1 UNION select object_schema_name(t.object_id) as referencing_schema_name, t.name as referencing_name, ds.name as referenced_name, null as referenced_schema_name from sys.tables t join sys.data_spaces ds on t.lob_data_space_id=ds.data_space_id where t.lob_data_space_id > 1 UNION select object_schema_name(i.object_id) as referencing_schema_name, i.name as referencing_name, ds.name as referenced_name, null as referenced_schema_name from sys.indexes i join sys.data_spaces ds on i.data_space_id=ds.data_space_id where i.data_space_id > 1 UNION select object_schema_name(i.object_id) as referencing_schema_name, i.name as referencing_name, object_name(i.object_id) as referenced_name, object_schema_name(i.object_id) as referenced_schema_name from sys.indexes i where object_schema_name(i.object_id)='dbo' UNION SELECT SCHEMA_NAME(SCHEMA_ID) as referencing_schema_name, name as referencing_name, PARSENAME(BASE_OBJECT_NAME,1) AS referenced_name, (CASE WHEN PARSENAME(BASE_OBJECT_NAME,2) IS NULL THEN schema_name(schema_id) else PARSENAME(BASE_OBJECT_NAME,2) END) AS referenced_schema_name FROM SYS.SYNONYMS WHERE is_ms_shipped='false' AND SCHEMA_NAME(SCHEMA_ID)='dbo' UNION select object_schema_name(c.object_id) as referencing_schema_name, c.name as referencing_name, object_schema_name(nc.object_id) as referenced_schema_name, nc.name as referenced_name from sys.indexes c join sys.indexes nc on c.object_id=nc.object_id JOIN sys.objects o ON c.object_id = o.object_id where c.index_id != nc.index_id and c.type_desc='CLUSTERED' and c.is_unique='true' and (not(nc.type_desc='CLUSTERED') OR nc.is_unique='false') AND o.type_desc='VIEW' AND o.name='AR_DETAIL_OPEN': Invalid object name 'SYS.SYNONYMS'.
.After the fix, there is no "cannot get object dependencies" log messages
Test Requirements (Liquibase Internal QA)
This test requires:
Start the MSSQL Docker container with case-sensitive collation by running:
docker run --name mssql_19 -e ACCEPT_EULA=Y -e MSSQL_PID="Developer" -e MSSQL_SA_PASSWORD="LiquibasePass1" -e MSSQL_TCP_PORT=14333 -e MSSQL_COLLATION=Latin1_General_BIN2 -p 14333:14333 -d mcr.microsoft.com/mssql/server:2019-GA-ubuntu-16.04
Connect to the database as
sa
with passwordLiquibasePass1
; the port is14333
.Create a user and a database to use for testing. You can use the default
master
database but if you run drop-all on that master, you drop a lot of dependencies SQL Server itself needs. It is best practice not to use themaster
database for testing.To create a SQL Server login
datical_login
and databaseproCatalog
:Create a liquibase.properties file that both url and referenceUrl defined:
Use the attached changelogs and run a liquibase update to create a private and a public synonym on the database.
liquibase update --changelog-file lb2175-changelog.xml --labels=setup,createPrivateSynonym,createPublicSynonym
Query to Determine SQL Server Collation (run directly on database)
SELECT CONVERT (varchar(256), SERVERPROPERTY('collation'));
Latin1_General_BIN2
is a case-sensitive collation settingSQL_Latin1_General_CP1_CI_AS
is a case-insensitive collation setting.Manual Tests
Verify generate
changelog does not throw a database error when connecting to MSSQL with a casesensitive collation type.liquibase --log-level INFO generate-changelog --changelog-file gcl.mssql.sql
SYS.SYNONYMS
is an invalid object name.Verify diff
changelog does not throw a database error when connecting to MSSQL with a casesensitive collation type.liquibase --log-level INFO diff-changelog --changelog-file dcl.mssql.sql
SYS.SYNONYMS
is an invalid object name.Verify that generate
changelog does not throw a database error when there are no synonyms present when connecting to MSSQL with a casesensitive collation type.liquibase --log-level FINE generate-changelog --changelog-file gclEmpty.mssql.sql
SYS.SYNONYMS
is an invalid object name.Verify generate-changelog does not throw an error when connecting to a MSSQL with default collation.
liquibase --log-level FINE generate-changelog --changelog-file gclEmpty2.mssql.sql
SYS.SYNONYMS
is an invalid object name.Automated Tests
┆Issue is synchronized with this Jira Bug by Unito