diff --git a/extensions/cms/package.json b/extensions/cms/package.json index b77dc4c4d2..4e64ba2d19 100644 --- a/extensions/cms/package.json +++ b/extensions/cms/package.json @@ -143,6 +143,20 @@ "isRequired": true, "isArray": false }, + { + "specialValueType": null, + "isIdentity": false, + "name": "applicationName", + "displayName": "%cms.connectionOptions.applicationName.displayName%", + "description": "%cms.connectionOptions.applicationName.description%", + "groupName": "%cms.connectionOptions.groupName.initialization%", + "valueType": "string", + "defaultValue": null, + "objectType": null, + "categoryValues": null, + "isRequired": false, + "isArray": false + }, { "specialValueType": null, "isIdentity": false, @@ -466,20 +480,6 @@ "isRequired": false, "isArray": false }, - { - "specialValueType": "appName", - "isIdentity": false, - "name": "applicationName", - "displayName": "%cms.connectionOptions.applicationName.displayName%", - "description": "%cms.connectionOptions.applicationName.description%", - "groupName": "%cms.connectionOptions.groupName.context%", - "valueType": "string", - "defaultValue": null, - "objectType": null, - "categoryValues": null, - "isRequired": false, - "isArray": false - }, { "specialValueType": null, "isIdentity": false, diff --git a/extensions/mssql/config.json b/extensions/mssql/config.json index a719c576d7..09a2549faa 100644 --- a/extensions/mssql/config.json +++ b/extensions/mssql/config.json @@ -1,6 +1,6 @@ { "downloadUrl": "https://github.com/Microsoft/sqltoolsservice/releases/download/{#version#}/microsoft.sqltools.servicelayer-{#fileName#}", - "version": "4.7.0.22", + "version": "4.7.0.23", "downloadFileNames": { "Windows_86": "win-x86-net7.0.zip", "Windows_64": "win-x64-net7.0.zip", @@ -10,7 +10,10 @@ "Linux": "rhel-x64-net7.0.tar.gz" }, "installDirectory": "./sqltoolsservice/{#platform#}/{#version#}", - "executableFiles": ["MicrosoftSqlToolsServiceLayer.exe", "MicrosoftSqlToolsServiceLayer"], + "executableFiles": [ + "MicrosoftSqlToolsServiceLayer.exe", + "MicrosoftSqlToolsServiceLayer" + ], "retry": { "retries": 15, "factor": 2, diff --git a/extensions/mssql/package.json b/extensions/mssql/package.json index 3bab915da4..537e9717cb 100644 --- a/extensions/mssql/package.json +++ b/extensions/mssql/package.json @@ -900,6 +900,20 @@ "isRequired": true, "isArray": false }, + { + "specialValueType": null, + "isIdentity": false, + "name": "applicationName", + "displayName": "%mssql.connectionOptions.applicationName.displayName%", + "description": "%mssql.connectionOptions.applicationName.description%", + "groupName": "%mssql.connectionOptions.groupName.initialization%", + "valueType": "string", + "defaultValue": null, + "objectType": null, + "categoryValues": null, + "isRequired": false, + "isArray": false + }, { "specialValueType": null, "isIdentity": false, @@ -1236,20 +1250,6 @@ "isRequired": false, "isArray": false }, - { - "specialValueType": "appName", - "isIdentity": false, - "name": "applicationName", - "displayName": "%mssql.connectionOptions.applicationName.displayName%", - "description": "%mssql.connectionOptions.applicationName.description%", - "groupName": "%mssql.connectionOptions.groupName.context%", - "valueType": "string", - "defaultValue": null, - "objectType": null, - "categoryValues": null, - "isRequired": false, - "isArray": false - }, { "specialValueType": null, "isIdentity": false, diff --git a/extensions/sql-migration/src/api/sqlUtils.ts b/extensions/sql-migration/src/api/sqlUtils.ts index 1c869cba12..7c463faaad 100644 --- a/extensions/sql-migration/src/api/sqlUtils.ts +++ b/extensions/sql-migration/src/api/sqlUtils.ts @@ -184,7 +184,7 @@ function getSqlDbConnectionProfile( savePassword: false, saveProfile: false, options: { - conectionName: '', + connectionName: '', server: serverName, database: databaseName, authenticationType: azdata.connection.AuthenticationType.SqlLogin, @@ -197,7 +197,7 @@ function getSqlDbConnectionProfile( trustServerCertificate: false, connectRetryCount: '1', connectRetryInterval: '10', - applicationName: 'azdata', + applicationName: 'azdata-sqlMigration', azureTenantId: tenantId, originalDatabase: databaseName, databaseDisplayName: databaseName, @@ -228,7 +228,7 @@ export function getTargetConnectionProfile( providerName: 'MSSQL', saveProfile: false, options: { - conectionName: connectId, + connectionName: connectId, server: serverName, authenticationType: azdata.connection.AuthenticationType.SqlLogin, user: userName, @@ -239,9 +239,9 @@ export function getTargetConnectionProfile( trustServerCertificate: trustServerCert, connectRetryCount: '1', connectRetryInterval: '10', - applicationName: 'azdata', + applicationName: 'azdata-sqlMigration', }, - }; + } } export async function getSourceConnectionString(): Promise { diff --git a/src/sql/azdata.d.ts b/src/sql/azdata.d.ts index 93cdde60cf..aeb7c089f6 100644 --- a/src/sql/azdata.d.ts +++ b/src/sql/azdata.d.ts @@ -2879,7 +2879,7 @@ declare module 'azdata' { * @param title The title shown in the editor tab * @param options Options to configure the editor * @param name The name used to identify the editor in telemetry - */ + */ export function createModelViewEditor(title: string, options?: ModelViewEditorOptions, name?: string): ModelViewEditor; export interface ModelViewEditor extends window.ModelViewPanel { diff --git a/src/sql/platform/connection/common/connectionProfile.ts b/src/sql/platform/connection/common/connectionProfile.ts index 3839a216c2..e26492b343 100644 --- a/src/sql/platform/connection/common/connectionProfile.ts +++ b/src/sql/platform/connection/common/connectionProfile.ts @@ -13,6 +13,7 @@ import { isString } from 'vs/base/common/types'; import { deepClone } from 'vs/base/common/objects'; import * as Constants from 'sql/platform/connection/common/constants'; import { URI } from 'vs/base/common/uri'; +import { adjustForMssqlAppName } from 'sql/platform/connection/common/utils'; export interface IconPath { light: URI; @@ -65,10 +66,17 @@ export class ConnectionProfile extends ProviderConnectionInfo implements interfa let capabilities = this.capabilitiesService.getCapabilities(this.providerName); if (capabilities && capabilities.connection && capabilities.connection.connectionOptions) { const options = capabilities.connection.connectionOptions; + // MSSQL Provider doesn't treat appName as special type anymore. let appNameOption = options.find(option => option.specialValueType === interfaces.ConnectionOptionSpecialType.appName); if (appNameOption) { let appNameKey = appNameOption.name; this.options[appNameKey] = Constants.applicationName; + } else if (this.providerName === Constants.mssqlProviderName || this.providerName === Constants.mssqlCmsProviderName) { + // Update AppName here for MSSQL and MSSQL-CMS provider to be able to match connection URI with STS. + appNameOption = options.find(option => option.name === Constants.mssqlApplicationNameOption); + if (appNameOption) { + this.options[Constants.mssqlApplicationNameOption] = adjustForMssqlAppName(model.options[Constants.mssqlApplicationNameOption]); + } } // Set values for advanced options received in model. Object.keys(model.options).forEach(a => { diff --git a/src/sql/platform/connection/common/constants.ts b/src/sql/platform/connection/common/constants.ts index b6fc242f2f..6ce872631b 100644 --- a/src/sql/platform/connection/common/constants.ts +++ b/src/sql/platform/connection/common/constants.ts @@ -11,12 +11,14 @@ export const outputChannelName = 'MSSQL'; export const capabilitiesOptions = 'OPTIONS_METADATA'; export const mssqlProviderName = 'MSSQL'; +export const mssqlCmsProviderName = 'MSSQL-CMS'; export const mysqlProviderName = 'MYSQL'; export const pgsqlProviderName = 'PGSQL'; export const anyProviderName = '*'; export const connectionProviderContextKey = 'connectionProvider'; export const applicationName = 'azdata'; +export const mssqlApplicationNameOption = 'applicationName'; export const defaultEngine = 'defaultEngine'; diff --git a/src/sql/platform/connection/common/utils.ts b/src/sql/platform/connection/common/utils.ts index 9f0ed7ce54..0434d75851 100644 --- a/src/sql/platform/connection/common/utils.ts +++ b/src/sql/platform/connection/common/utils.ts @@ -7,6 +7,7 @@ import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { ConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import * as sqlExtHostTypes from 'sql/workbench/api/common/sqlExtHostTypes'; +import { applicationName } from 'sql/platform/connection/common/constants'; // CONSTANTS ////////////////////////////////////////////////////////////////////////////////////// const msInH = 3.6e6; @@ -170,3 +171,11 @@ export function convertToRpcConnectionProfile(profile: IConnectionProfile | unde return connection; } + +export function adjustForMssqlAppName(currentAppName: string, suffix?: string): string { + let appName = suffix ? applicationName + '-' + suffix : applicationName; + let finalSuffix = '-' + appName; + return (currentAppName && currentAppName !== appName && !currentAppName.endsWith(finalSuffix)) + ? currentAppName + finalSuffix + : currentAppName ?? appName; +} diff --git a/src/sql/workbench/contrib/commandLine/electron-browser/commandLine.ts b/src/sql/workbench/contrib/commandLine/electron-browser/commandLine.ts index 6b0b3ad3c4..1d2c06c7a5 100644 --- a/src/sql/workbench/contrib/commandLine/electron-browser/commandLine.ts +++ b/src/sql/workbench/contrib/commandLine/electron-browser/commandLine.ts @@ -41,6 +41,7 @@ export interface SqlArgs { aad?: boolean; // deprecated - used by SSMS - authenticationType should be used instead integrated?: boolean; // deprecated - used by SSMS - authenticationType should be used instead. showDashboard?: boolean; + applicationName?: string; } //#region decorators @@ -307,7 +308,10 @@ export class CommandLineWorkbenchContribution implements IWorkbenchContribution, Constants.AuthenticationType.Integrated; profile.connectionName = ''; - profile.setOptionValue('applicationName', Constants.applicationName); + const applicationName = args.applicationName + ? args.applicationName + '-' + Constants.applicationName + : Constants.applicationName; + profile.setOptionValue('applicationName', applicationName); profile.setOptionValue('databaseDisplayName', profile.databaseName); profile.setOptionValue('groupId', profile.groupId); return this._connectionManagementService ? this.tryMatchSavedProfile(profile) : profile; diff --git a/src/sql/workbench/contrib/commandLine/test/electron-browser/commandLine.test.ts b/src/sql/workbench/contrib/commandLine/test/electron-browser/commandLine.test.ts index 39ed967175..f548e4143e 100644 --- a/src/sql/workbench/contrib/commandLine/test/electron-browser/commandLine.test.ts +++ b/src/sql/workbench/contrib/commandLine/test/electron-browser/commandLine.test.ts @@ -95,6 +95,7 @@ class TestParsedArgs implements NativeParsedArgs, SqlArgs { wait?: boolean; waitMarkerFilePath?: string; authenticationType?: string; + applicationName?: string; } suite('commandLineService tests', () => { @@ -196,12 +197,14 @@ suite('commandLineService tests', () => { args.database = 'mydatabase'; args.user = 'myuser'; args.authenticationType = Constants.AuthenticationType.SqlLogin; + args.applicationName = 'myapplication'; connectionManagementService.setup((c) => c.showConnectionDialog()).verifiable(TypeMoq.Times.never()); connectionManagementService.setup(c => c.hasRegisteredServers()).returns(() => true).verifiable(TypeMoq.Times.atMostOnce()); connectionManagementService.setup(c => c.getConnectionGroups(TypeMoq.It.isAny())).returns(() => []); let originalProfile: IConnectionProfile = undefined; - connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is(p => p.serverName === 'myserver' && p.authenticationType === Constants.AuthenticationType.SqlLogin), 'connection', true)) + connectionManagementService.setup(c => c.connectIfNotConnected(TypeMoq.It.is( + p => p.serverName === 'myserver' && p.authenticationType === Constants.AuthenticationType.SqlLogin && p.options['applicationName'] === 'myapplication-azdata'), 'connection', true)) .returns((conn) => { originalProfile = conn; return Promise.resolve('unused'); @@ -212,6 +215,7 @@ suite('commandLineService tests', () => { const logService = new NullLogService(); let contribution = getCommandLineContribution(connectionManagementService.object, configurationService.object, capabilitiesService, undefined, undefined, logService); await contribution.processCommandLine(args); + assert.equal(originalProfile.options['applicationName'], 'myapplication-azdata', 'Application Name not received as expected.'); connectionManagementService.verifyAll(); }); diff --git a/src/sql/workbench/services/connection/browser/connectionController.ts b/src/sql/workbench/services/connection/browser/connectionController.ts index d58fe77361..800ba47411 100644 --- a/src/sql/workbench/services/connection/browser/connectionController.ts +++ b/src/sql/workbench/services/connection/browser/connectionController.ts @@ -160,10 +160,16 @@ export class ConnectionController implements IConnectionComponentController { this._connectionWidget.updateServerGroup(this.getAllServerGroups(providers)); this._model = connectionInfo; this._model.providerName = this._providerName; + // MSSQL and MSSQL-CMS Provider don't treat appName as special type anymore. let appNameOption = this._providerOptions.find(option => option.specialValueType === ConnectionOptionSpecialType.appName); if (appNameOption) { let appNameKey = appNameOption.name; this._model.options[appNameKey] = Constants.applicationName; + } else { + appNameOption = this._providerOptions.find(option => option.name === Constants.mssqlApplicationNameOption); + if (appNameOption && (this._model.providerName === Constants.mssqlProviderName || this._model.providerName === Constants.mssqlCmsProviderName)) { + this._model.options[Constants.mssqlApplicationNameOption] = Utils.adjustForMssqlAppName(this._model.options[Constants.mssqlApplicationNameOption]); + } } this._connectionWidget.initDialog(this._model); } diff --git a/src/sql/workbench/services/connection/browser/connectionWidget.ts b/src/sql/workbench/services/connection/browser/connectionWidget.ts index e0cae7637f..2a7b928b55 100644 --- a/src/sql/workbench/services/connection/browser/connectionWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionWidget.ts @@ -38,10 +38,11 @@ import { ConnectionStringOptions } from 'sql/platform/capabilities/common/capabi import { isFalsyOrWhitespace } from 'vs/base/common/strings'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { filterAccounts } from 'sql/workbench/services/accountManagement/browser/accountDialog'; -import { AuthenticationType, Actions } from 'sql/platform/connection/common/constants'; +import { AuthenticationType, Actions, mssqlApplicationNameOption, applicationName, mssqlProviderName, mssqlCmsProviderName } from 'sql/platform/connection/common/constants'; import { AdsWidget } from 'sql/base/browser/ui/adsWidget'; import { createCSSRule } from 'vs/base/browser/dom'; import { AuthLibrary, getAuthLibrary } from 'sql/workbench/services/accountManagement/utils'; +import { adjustForMssqlAppName } from 'sql/platform/connection/common/utils'; const ConnectionStringText = localize('connectionWidget.connectionString', "Connection string"); @@ -1253,6 +1254,11 @@ export class ConnectionWidget extends lifecycle.Disposable { }); } } + // Fix Application Name for MSSQL/MSSQL-CMS Providers, to handle special case as we need to apply custom application name in ADS Core connection profile. + if ((model.providerName === mssqlProviderName || model.providerName === mssqlCmsProviderName) + && model.options[mssqlApplicationNameOption] && !model.options[mssqlApplicationNameOption].endsWith(applicationName)) { + model.options[mssqlApplicationNameOption] = adjustForMssqlAppName(model.options[mssqlApplicationNameOption]); + } model.connectionName = this.connectionName; if (this._serverGroupSelectBox) { if (this._serverGroupSelectBox.value === this.DefaultServerGroup.name) {