mirror of
https://github.com/ckaczor/sqltoolsservice.git
synced 2026-01-21 01:25:42 -05:00
Edit Data: Better Formatting Errors (#562)
* Refactoring sql script formatting helpers into To and From helpers * Updates to make error messages for formatting errors more useful * Fixing dumb breaks in unit tests * Addressing comments from PR * Updates to the SR files...
This commit is contained in:
@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
Keys.Culture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string CredentialsServiceInvalidCriticalHandle
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceInvalidCriticalHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServicePasswordLengthExceeded
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServicePasswordLengthExceeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServiceTargetForDelete
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceTargetForDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServiceTargetForLookup
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceTargetForLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialServiceWin32CredentialDisposed
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialServiceWin32CredentialDisposed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
@@ -75,22 +75,22 @@ namespace Microsoft.SqlTools.Credentials
|
||||
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.Credentials.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
|
||||
|
||||
static CultureInfo _culture = null;
|
||||
|
||||
|
||||
public const string CredentialsServiceInvalidCriticalHandle = "CredentialsServiceInvalidCriticalHandle";
|
||||
|
||||
|
||||
public const string CredentialsServicePasswordLengthExceeded = "CredentialsServicePasswordLengthExceeded";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForDelete = "CredentialsServiceTargetForDelete";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForLookup = "CredentialsServiceTargetForLookup";
|
||||
|
||||
|
||||
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
|
||||
|
||||
|
||||
|
||||
public const string CredentialsServiceInvalidCriticalHandle = "CredentialsServiceInvalidCriticalHandle";
|
||||
|
||||
|
||||
public const string CredentialsServicePasswordLengthExceeded = "CredentialsServicePasswordLengthExceeded";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForDelete = "CredentialsServiceTargetForDelete";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForLookup = "CredentialsServiceTargetForLookup";
|
||||
|
||||
|
||||
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
@@ -111,7 +111,7 @@ namespace Microsoft.SqlTools.Credentials
|
||||
{
|
||||
return resourceManager.GetString(key, _culture);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,21 +120,21 @@
|
||||
<data name="CredentialsServiceInvalidCriticalHandle" xml:space="preserve">
|
||||
<value>Invalid CriticalHandle!</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServicePasswordLengthExceeded" xml:space="preserve">
|
||||
<value>The password has exceeded 512 bytes</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServiceTargetForDelete" xml:space="preserve">
|
||||
<value>Target must be specified to delete a credential</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServiceTargetForLookup" xml:space="preserve">
|
||||
<value>Target must be specified to check existance of a credential</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialServiceWin32CredentialDisposed" xml:space="preserve">
|
||||
<value>Win32Credential object is already disposed</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
Keys.Culture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string CredentialsServiceInvalidCriticalHandle
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceInvalidCriticalHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServicePasswordLengthExceeded
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServicePasswordLengthExceeded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServiceTargetForDelete
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceTargetForDelete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialsServiceTargetForLookup
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialsServiceTargetForLookup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string CredentialServiceWin32CredentialDisposed
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.CredentialServiceWin32CredentialDisposed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ServiceAlreadyRegistered
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.ServiceAlreadyRegistered);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string MultipleServicesFound
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.MultipleServicesFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string IncompatibleServiceForExtensionLoader
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.IncompatibleServiceForExtensionLoader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ServiceProviderNotSet
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.ServiceProviderNotSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ServiceNotFound
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.ServiceNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string ServiceNotOfExpectedType
|
||||
{
|
||||
@@ -115,7 +115,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.ServiceNotOfExpectedType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string HostingUnexpectedEndOfStream
|
||||
{
|
||||
@@ -123,7 +123,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.HostingUnexpectedEndOfStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string HostingHeaderMissingColon
|
||||
{
|
||||
@@ -131,7 +131,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.HostingHeaderMissingColon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string HostingHeaderMissingContentLengthHeader
|
||||
{
|
||||
@@ -139,7 +139,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.HostingHeaderMissingContentLengthHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string HostingHeaderMissingContentLengthValue
|
||||
{
|
||||
@@ -147,7 +147,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return Keys.GetString(Keys.HostingHeaderMissingContentLengthValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
@@ -155,52 +155,52 @@ namespace Microsoft.SqlTools.Hosting
|
||||
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.Hosting.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
|
||||
|
||||
static CultureInfo _culture = null;
|
||||
|
||||
|
||||
public const string CredentialsServiceInvalidCriticalHandle = "CredentialsServiceInvalidCriticalHandle";
|
||||
|
||||
|
||||
public const string CredentialsServicePasswordLengthExceeded = "CredentialsServicePasswordLengthExceeded";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForDelete = "CredentialsServiceTargetForDelete";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForLookup = "CredentialsServiceTargetForLookup";
|
||||
|
||||
|
||||
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
|
||||
|
||||
|
||||
public const string ServiceAlreadyRegistered = "ServiceAlreadyRegistered";
|
||||
|
||||
|
||||
public const string MultipleServicesFound = "MultipleServicesFound";
|
||||
|
||||
|
||||
public const string IncompatibleServiceForExtensionLoader = "IncompatibleServiceForExtensionLoader";
|
||||
|
||||
|
||||
public const string ServiceProviderNotSet = "ServiceProviderNotSet";
|
||||
|
||||
|
||||
public const string ServiceNotFound = "ServiceNotFound";
|
||||
|
||||
|
||||
public const string ServiceNotOfExpectedType = "ServiceNotOfExpectedType";
|
||||
|
||||
|
||||
public const string HostingUnexpectedEndOfStream = "HostingUnexpectedEndOfStream";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingColon = "HostingHeaderMissingColon";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingContentLengthHeader = "HostingHeaderMissingContentLengthHeader";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingContentLengthValue = "HostingHeaderMissingContentLengthValue";
|
||||
|
||||
|
||||
|
||||
public const string CredentialsServiceInvalidCriticalHandle = "CredentialsServiceInvalidCriticalHandle";
|
||||
|
||||
|
||||
public const string CredentialsServicePasswordLengthExceeded = "CredentialsServicePasswordLengthExceeded";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForDelete = "CredentialsServiceTargetForDelete";
|
||||
|
||||
|
||||
public const string CredentialsServiceTargetForLookup = "CredentialsServiceTargetForLookup";
|
||||
|
||||
|
||||
public const string CredentialServiceWin32CredentialDisposed = "CredentialServiceWin32CredentialDisposed";
|
||||
|
||||
|
||||
public const string ServiceAlreadyRegistered = "ServiceAlreadyRegistered";
|
||||
|
||||
|
||||
public const string MultipleServicesFound = "MultipleServicesFound";
|
||||
|
||||
|
||||
public const string IncompatibleServiceForExtensionLoader = "IncompatibleServiceForExtensionLoader";
|
||||
|
||||
|
||||
public const string ServiceProviderNotSet = "ServiceProviderNotSet";
|
||||
|
||||
|
||||
public const string ServiceNotFound = "ServiceNotFound";
|
||||
|
||||
|
||||
public const string ServiceNotOfExpectedType = "ServiceNotOfExpectedType";
|
||||
|
||||
|
||||
public const string HostingUnexpectedEndOfStream = "HostingUnexpectedEndOfStream";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingColon = "HostingHeaderMissingColon";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingContentLengthHeader = "HostingHeaderMissingContentLengthHeader";
|
||||
|
||||
|
||||
public const string HostingHeaderMissingContentLengthValue = "HostingHeaderMissingContentLengthValue";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
@@ -221,7 +221,7 @@ namespace Microsoft.SqlTools.Hosting
|
||||
{
|
||||
return resourceManager.GetString(key, _culture);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,61 +120,61 @@
|
||||
<data name="CredentialsServiceInvalidCriticalHandle" xml:space="preserve">
|
||||
<value>Invalid CriticalHandle!</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServicePasswordLengthExceeded" xml:space="preserve">
|
||||
<value>The password has exceeded 512 bytes</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServiceTargetForDelete" xml:space="preserve">
|
||||
<value>Target must be specified to delete a credential</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialsServiceTargetForLookup" xml:space="preserve">
|
||||
<value>Target must be specified to check existance of a credential</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="CredentialServiceWin32CredentialDisposed" xml:space="preserve">
|
||||
<value>Win32Credential object is already disposed</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="ServiceAlreadyRegistered" xml:space="preserve">
|
||||
<value>Cannot register service for type {0}, one or more services already registered</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="MultipleServicesFound" xml:space="preserve">
|
||||
<value>Multiple services found for type {0}, expected only 1</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="IncompatibleServiceForExtensionLoader" xml:space="preserve">
|
||||
<value>Service of type {0} cannot be created by ExtensionLoader<{1}></value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="ServiceProviderNotSet" xml:space="preserve">
|
||||
<value>SetServiceProvider() was not called to establish the required service provider</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="ServiceNotFound" xml:space="preserve">
|
||||
<value>Service {0} was not found in the service provider</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="ServiceNotOfExpectedType" xml:space="preserve">
|
||||
<value>Service of Type {0} is not compatible with registered Type {1}</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="HostingUnexpectedEndOfStream" xml:space="preserve">
|
||||
<value>MessageReader's input stream ended unexpectedly, terminating</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="HostingHeaderMissingColon" xml:space="preserve">
|
||||
<value>Message header must separate key and value using ':'</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="HostingHeaderMissingContentLengthHeader" xml:space="preserve">
|
||||
<value>Fatal error: Content-Length header must be provided</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="HostingHeaderMissingContentLengthValue" xml:space="preserve">
|
||||
<value>Fatal error: Content-Length value is not an integer</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
Keys.Culture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string NoSubscriptionsFound
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.NoSubscriptionsFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string AzureServerNotFound
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.AzureServerNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string AzureSubscriptionFailedErrorMessage
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.AzureSubscriptionFailedErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string DatabaseDiscoveryFailedErrorMessage
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.DatabaseDiscoveryFailedErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleAccessForbidden
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleAccessForbidden);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleCreationFailed
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleCreationFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleCreationFailedWithError
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleCreationFailedWithError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string InvalidIpAddress
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.InvalidIpAddress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string InvalidServerTypeErrorMessage
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.InvalidServerTypeErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string LoadingExportableFailedGeneralErrorMessage
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.LoadingExportableFailedGeneralErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleUnsupportedConnectionType
|
||||
{
|
||||
@@ -115,7 +115,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleUnsupportedConnectionType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
@@ -123,40 +123,40 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ResourceProvider.Core.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
|
||||
|
||||
static CultureInfo _culture = null;
|
||||
|
||||
|
||||
public const string NoSubscriptionsFound = "NoSubscriptionsFound";
|
||||
|
||||
|
||||
public const string AzureServerNotFound = "AzureServerNotFound";
|
||||
|
||||
|
||||
public const string AzureSubscriptionFailedErrorMessage = "AzureSubscriptionFailedErrorMessage";
|
||||
|
||||
|
||||
public const string DatabaseDiscoveryFailedErrorMessage = "DatabaseDiscoveryFailedErrorMessage";
|
||||
|
||||
|
||||
public const string FirewallRuleAccessForbidden = "FirewallRuleAccessForbidden";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";
|
||||
|
||||
|
||||
public const string InvalidIpAddress = "InvalidIpAddress";
|
||||
|
||||
|
||||
public const string InvalidServerTypeErrorMessage = "InvalidServerTypeErrorMessage";
|
||||
|
||||
|
||||
public const string LoadingExportableFailedGeneralErrorMessage = "LoadingExportableFailedGeneralErrorMessage";
|
||||
|
||||
|
||||
public const string FirewallRuleUnsupportedConnectionType = "FirewallRuleUnsupportedConnectionType";
|
||||
|
||||
|
||||
|
||||
public const string NoSubscriptionsFound = "NoSubscriptionsFound";
|
||||
|
||||
|
||||
public const string AzureServerNotFound = "AzureServerNotFound";
|
||||
|
||||
|
||||
public const string AzureSubscriptionFailedErrorMessage = "AzureSubscriptionFailedErrorMessage";
|
||||
|
||||
|
||||
public const string DatabaseDiscoveryFailedErrorMessage = "DatabaseDiscoveryFailedErrorMessage";
|
||||
|
||||
|
||||
public const string FirewallRuleAccessForbidden = "FirewallRuleAccessForbidden";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";
|
||||
|
||||
|
||||
public const string InvalidIpAddress = "InvalidIpAddress";
|
||||
|
||||
|
||||
public const string InvalidServerTypeErrorMessage = "InvalidServerTypeErrorMessage";
|
||||
|
||||
|
||||
public const string LoadingExportableFailedGeneralErrorMessage = "LoadingExportableFailedGeneralErrorMessage";
|
||||
|
||||
|
||||
public const string FirewallRuleUnsupportedConnectionType = "FirewallRuleUnsupportedConnectionType";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
@@ -177,7 +177,7 @@ namespace Microsoft.SqlTools.ResourceProvider.Core
|
||||
{
|
||||
return resourceManager.GetString(key, _culture);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,45 +120,45 @@
|
||||
<data name="NoSubscriptionsFound" xml:space="preserve">
|
||||
<value>No subscriptions were found for the currently logged in user account.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="AzureServerNotFound" xml:space="preserve">
|
||||
<value>The server you specified {0} does not exist in any subscription in {1}. Either you have signed in with an incorrect account or your server was removed from subscription(s) in this account. Please check your account and try again.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="AzureSubscriptionFailedErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure subscriptions: {0}</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="DatabaseDiscoveryFailedErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting databases from servers of type {0} from {1}</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleAccessForbidden" xml:space="preserve">
|
||||
<value>{0} does not have permission to change the server firewall rule. Try again with a different account that is an Owner or Contributor of the Azure subscription or the server.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleCreationFailed" xml:space="preserve">
|
||||
<value>An error occurred while creating a new firewall rule.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleCreationFailedWithError" xml:space="preserve">
|
||||
<value>An error occurred while creating a new firewall rule: '{0}'</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="InvalidIpAddress" xml:space="preserve">
|
||||
<value>Invalid IP address</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="InvalidServerTypeErrorMessage" xml:space="preserve">
|
||||
<value>Server Type is invalid.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="LoadingExportableFailedGeneralErrorMessage" xml:space="preserve">
|
||||
<value>A required dll cannot be loaded. Please repair your application.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleUnsupportedConnectionType" xml:space="preserve">
|
||||
<value>Cannot open a firewall rule for the specified connection type</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
Keys.Culture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static string FailedToGetAzureDatabasesErrorMessage
|
||||
{
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToGetAzureDatabasesErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FailedToGetAzureSubscriptionsErrorMessage
|
||||
{
|
||||
@@ -43,7 +43,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToGetAzureSubscriptionsErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FailedToGetAzureResourceGroupsErrorMessage
|
||||
{
|
||||
@@ -51,7 +51,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToGetAzureResourceGroupsErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FailedToGetAzureSqlServersErrorMessage
|
||||
{
|
||||
@@ -59,7 +59,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToGetAzureSqlServersErrorMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FailedToGetAzureSqlServersWithError
|
||||
{
|
||||
@@ -67,7 +67,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FailedToGetAzureSqlServersWithError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleCreationFailed
|
||||
{
|
||||
@@ -75,7 +75,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleCreationFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string FirewallRuleCreationFailedWithError
|
||||
{
|
||||
@@ -83,7 +83,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.FirewallRuleCreationFailedWithError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string UnsupportedAuthType
|
||||
{
|
||||
@@ -91,7 +91,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.UnsupportedAuthType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string UserNotFoundError
|
||||
{
|
||||
@@ -99,7 +99,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.UserNotFoundError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string UserNeedsAuthenticationError
|
||||
{
|
||||
@@ -107,7 +107,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return Keys.GetString(Keys.UserNeedsAuthenticationError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
@@ -115,37 +115,37 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ResourceProvider.DefaultImpl.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
|
||||
|
||||
static CultureInfo _culture = null;
|
||||
|
||||
|
||||
public const string FailedToGetAzureDatabasesErrorMessage = "FailedToGetAzureDatabasesErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSubscriptionsErrorMessage = "FailedToGetAzureSubscriptionsErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureResourceGroupsErrorMessage = "FailedToGetAzureResourceGroupsErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSqlServersErrorMessage = "FailedToGetAzureSqlServersErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSqlServersWithError = "FailedToGetAzureSqlServersWithError";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";
|
||||
|
||||
|
||||
public const string UnsupportedAuthType = "UnsupportedAuthType";
|
||||
|
||||
|
||||
public const string UserNotFoundError = "UserNotFoundError";
|
||||
|
||||
|
||||
public const string UserNeedsAuthenticationError = "UserNeedsAuthenticationError";
|
||||
|
||||
|
||||
|
||||
public const string FailedToGetAzureDatabasesErrorMessage = "FailedToGetAzureDatabasesErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSubscriptionsErrorMessage = "FailedToGetAzureSubscriptionsErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureResourceGroupsErrorMessage = "FailedToGetAzureResourceGroupsErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSqlServersErrorMessage = "FailedToGetAzureSqlServersErrorMessage";
|
||||
|
||||
|
||||
public const string FailedToGetAzureSqlServersWithError = "FailedToGetAzureSqlServersWithError";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailed = "FirewallRuleCreationFailed";
|
||||
|
||||
|
||||
public const string FirewallRuleCreationFailedWithError = "FirewallRuleCreationFailedWithError";
|
||||
|
||||
|
||||
public const string UnsupportedAuthType = "UnsupportedAuthType";
|
||||
|
||||
|
||||
public const string UserNotFoundError = "UserNotFoundError";
|
||||
|
||||
|
||||
public const string UserNeedsAuthenticationError = "UserNeedsAuthenticationError";
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
@@ -166,7 +166,7 @@ namespace Microsoft.SqlTools.ResourceProvider.DefaultImpl
|
||||
{
|
||||
return resourceManager.GetString(key, _culture);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,41 +120,41 @@
|
||||
<data name="FailedToGetAzureDatabasesErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure databases</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FailedToGetAzureSubscriptionsErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure subscriptions: {0}</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FailedToGetAzureResourceGroupsErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure resource groups: {0}</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FailedToGetAzureSqlServersErrorMessage" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure Sql Servers</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FailedToGetAzureSqlServersWithError" xml:space="preserve">
|
||||
<value>An error occurred while getting Azure Sql Servers: '{0}'</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleCreationFailed" xml:space="preserve">
|
||||
<value>An error occurred while creating a new firewall rule.</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="FirewallRuleCreationFailedWithError" xml:space="preserve">
|
||||
<value>An error occurred while creating a new firewall rule: '{0}'</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="UnsupportedAuthType" xml:space="preserve">
|
||||
<value>Unsupported account type '{0}' for this provider</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="UserNotFoundError" xml:space="preserve">
|
||||
<value>No user was found, cannot execute the operation</value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</data>
|
||||
<data name="UserNeedsAuthenticationError" xml:space="preserve">
|
||||
<value>The current user must be reauthenticated before executing this operation </value>
|
||||
<comment></comment>
|
||||
</data>
|
||||
</root>
|
||||
</data>
|
||||
</root>
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Microsoft.SqlTools.ResourceProvider
|
||||
Keys.Culture = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
public class Keys
|
||||
@@ -35,7 +35,7 @@ namespace Microsoft.SqlTools.ResourceProvider
|
||||
static ResourceManager resourceManager = new ResourceManager("Microsoft.SqlTools.ResourceProvider.Localization.SR", typeof(SR).GetTypeInfo().Assembly);
|
||||
|
||||
static CultureInfo _culture = null;
|
||||
|
||||
|
||||
|
||||
private Keys()
|
||||
{ }
|
||||
@@ -56,7 +56,7 @@ namespace Microsoft.SqlTools.ResourceProvider
|
||||
{
|
||||
return resourceManager.GetString(key, _culture);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,4 +117,4 @@
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
</root>
|
||||
|
||||
@@ -15,7 +15,7 @@ using Microsoft.SqlTools.ServiceLayer.EditData.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData
|
||||
@@ -440,12 +440,9 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
|
||||
|
||||
public static string[] GetEditTargetName(EditInitializeParams initParams)
|
||||
{
|
||||
// Step 1) Look up the SMO metadata
|
||||
if (initParams.SchemaName != null)
|
||||
{
|
||||
return new [] { initParams.SchemaName, initParams.ObjectName };
|
||||
}
|
||||
return SqlScriptFormatter.DecodeMultipartIdenfitier(initParams.ObjectName);
|
||||
return initParams.SchemaName != null
|
||||
? new [] { initParams.SchemaName, initParams.ObjectName }
|
||||
: FromSqlScript.DecodeMultipartIdentifier(initParams.ObjectName);
|
||||
}
|
||||
|
||||
private async Task CommitEditsInternal(DbConnection connection, Func<Task> successHandler, Func<Exception, Task> errorHandler)
|
||||
|
||||
@@ -10,7 +10,7 @@ using System.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData
|
||||
@@ -92,12 +92,12 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
|
||||
// The default value may be escaped
|
||||
string defaultValue = smoColumn.DefaultConstraint == null
|
||||
? null
|
||||
: SqlScriptFormatter.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
|
||||
: FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
|
||||
|
||||
EditColumnMetadata column = new EditColumnMetadata
|
||||
{
|
||||
DefaultValue = defaultValue,
|
||||
EscapedName = SqlScriptFormatter.FormatIdentifier(smoColumn.Name),
|
||||
EscapedName = ToSqlScript.FormatIdentifier(smoColumn.Name),
|
||||
Ordinal = i,
|
||||
};
|
||||
editColumns.Add(column);
|
||||
@@ -114,14 +114,14 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData
|
||||
|
||||
// Escape the parts of the name
|
||||
string[] objectNameParts = {smoResult.Schema, smoResult.Name};
|
||||
string escapedMultipartName = SqlScriptFormatter.FormatMultipartIdentifier(objectNameParts);
|
||||
string escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts);
|
||||
|
||||
return new EditTableMetadata
|
||||
{
|
||||
Columns = editColumns.ToArray(),
|
||||
EscapedMultipartName = escapedMultipartName,
|
||||
IsMemoryOptimized = isMemoryOptimized,
|
||||
IsMemoryOptimized = isMemoryOptimized
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.SqlTools.ServiceLayer.EditData.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
@@ -34,50 +35,60 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
Validate.IsNotNull(nameof(valueAsString), valueAsString);
|
||||
|
||||
// Store the state that won't be changed
|
||||
Column = column;
|
||||
Type columnType = column.DataType;
|
||||
try
|
||||
{
|
||||
Column = column;
|
||||
Type columnType = column.DataType;
|
||||
|
||||
// Check for null
|
||||
if (valueAsString == NullString)
|
||||
{
|
||||
ProcessNullValue();
|
||||
// Check for null
|
||||
if (valueAsString == NullString)
|
||||
{
|
||||
ProcessNullValue();
|
||||
}
|
||||
else if (columnType == typeof(byte[]))
|
||||
{
|
||||
// Binary columns need special attention
|
||||
ProcessBinaryCell(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(string))
|
||||
{
|
||||
ProcessTextCell(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(Guid))
|
||||
{
|
||||
Value = Guid.Parse(valueAsString);
|
||||
ValueAsString = Value.ToString();
|
||||
}
|
||||
else if (columnType == typeof(TimeSpan))
|
||||
{
|
||||
ProcessTimespanColumn(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(DateTimeOffset))
|
||||
{
|
||||
Value = DateTimeOffset.Parse(valueAsString, CultureInfo.CurrentCulture);
|
||||
ValueAsString = Value.ToString();
|
||||
}
|
||||
else if (columnType == typeof(bool))
|
||||
{
|
||||
ProcessBooleanCell(valueAsString);
|
||||
}
|
||||
// @TODO: Microsoft.SqlServer.Types.SqlHierarchyId
|
||||
else
|
||||
{
|
||||
// Attempt to go straight to the destination type, if we know what it is, otherwise
|
||||
// leave it as a string
|
||||
Value = columnType != null
|
||||
? Convert.ChangeType(valueAsString, columnType, CultureInfo.CurrentCulture)
|
||||
: valueAsString;
|
||||
ValueAsString = Value.ToString();
|
||||
}
|
||||
}
|
||||
else if (columnType == typeof(byte[]))
|
||||
catch (FormatException fe)
|
||||
{
|
||||
// Binary columns need special attention
|
||||
ProcessBinaryCell(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(string))
|
||||
{
|
||||
ProcessTextCell(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(Guid))
|
||||
{
|
||||
Value = Guid.Parse(valueAsString);
|
||||
ValueAsString = Value.ToString();
|
||||
}
|
||||
else if (columnType == typeof(TimeSpan))
|
||||
{
|
||||
ProcessTimespanColumn(valueAsString);
|
||||
}
|
||||
else if (columnType == typeof(DateTimeOffset))
|
||||
{
|
||||
Value = DateTimeOffset.Parse(valueAsString, CultureInfo.CurrentCulture);
|
||||
ValueAsString = Value.ToString();
|
||||
}
|
||||
else if (columnType == typeof(bool))
|
||||
{
|
||||
ProcessBooleanCell(valueAsString);
|
||||
}
|
||||
// @TODO: Microsoft.SqlServer.Types.SqlHierarchyId
|
||||
else
|
||||
{
|
||||
// Attempt to go straight to the destination type, if we know what it is, otherwise
|
||||
// leave it as a string
|
||||
Value = columnType != null
|
||||
? Convert.ChangeType(valueAsString, columnType, CultureInfo.CurrentCulture)
|
||||
: valueAsString;
|
||||
ValueAsString = Value.ToString();
|
||||
// Pretty up the exception so the user can learn a bit from it
|
||||
// NOTE: Other formatting errors raised by helpers are InvalidOperationException to
|
||||
// avoid being prettied here
|
||||
throw new FormatException(SR.EditDataInvalidFormat(column.ColumnName, ToSqlScript.FormatColumnType(column)), fe);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,8 +192,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
}
|
||||
else
|
||||
{
|
||||
// Invalid format
|
||||
throw new FormatException(SR.EditDataInvalidFormatBinary);
|
||||
throw new InvalidOperationException(SR.EditDataInvalidFormatBinary);
|
||||
}
|
||||
|
||||
// Generate the hex string as the return value
|
||||
@@ -205,8 +215,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
Value = false;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException(nameof(valueAsString),
|
||||
SR.EditDataInvalidFormatBoolean);
|
||||
throw new InvalidOperationException(SR.EditDataInvalidFormatBoolean);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -253,7 +262,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
{
|
||||
string columnSizeString = $"({Column.ColumnSize.Value})";
|
||||
string columnTypeString = Column.DataTypeName.ToUpperInvariant() + columnSizeString;
|
||||
throw new FormatException(SR.EditDataValueTooLarge(valueAsString, columnTypeString));
|
||||
throw new InvalidOperationException(SR.EditDataValueTooLarge(valueAsString, columnTypeString));
|
||||
}
|
||||
|
||||
ValueAsString = valueAsString;
|
||||
|
||||
@@ -14,7 +14,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.EditData.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
@@ -202,7 +202,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
// Add an out column if we're doing this for a command
|
||||
if (forCommand)
|
||||
{
|
||||
outColumns.Add($"inserted.{SqlScriptFormatter.FormatIdentifier(column.ColumnName)}");
|
||||
outColumns.Add($"inserted.{ToSqlScript.FormatIdentifier(column.ColumnName)}");
|
||||
}
|
||||
|
||||
// Skip columns that cannot be updated
|
||||
@@ -237,11 +237,11 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
else
|
||||
{
|
||||
// This script isn't for command use, add the value, formatted for insertion
|
||||
inValues.Add(SqlScriptFormatter.FormatValue(cell.Value, column));
|
||||
inValues.Add(ToSqlScript.FormatValue(cell.Value, column));
|
||||
}
|
||||
|
||||
// Add the column to the in columns
|
||||
inColumns.Add(SqlScriptFormatter.FormatIdentifier(column.ColumnName));
|
||||
inColumns.Add(ToSqlScript.FormatIdentifier(column.ColumnName));
|
||||
}
|
||||
|
||||
// Begin the script (ie, INSERT INTO blah)
|
||||
|
||||
@@ -12,7 +12,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.EditData.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
{
|
||||
@@ -27,6 +27,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
/// <summary>
|
||||
/// Internal parameterless constructor, required for mocking
|
||||
/// </summary>
|
||||
// ReSharper disable once UnusedMember.Global
|
||||
protected internal RowEditBase() { }
|
||||
|
||||
/// <summary>
|
||||
@@ -204,7 +205,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
else
|
||||
{
|
||||
// Add the clause component with the formatted value
|
||||
cellDataClause = $"= {SqlScriptFormatter.FormatValue(cellData, col.DbColumn)}";
|
||||
cellDataClause = $"= {ToSqlScript.FormatValue(cellData, col.DbColumn)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ using System.Threading.Tasks;
|
||||
using Microsoft.SqlTools.ServiceLayer.EditData.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
@@ -81,7 +81,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
List<string> setComponents = new List<string>();
|
||||
foreach (var updateElement in cellUpdates)
|
||||
{
|
||||
string formattedColumnName = SqlScriptFormatter.FormatIdentifier(updateElement.Value.Column.ColumnName);
|
||||
string formattedColumnName = ToSqlScript.FormatIdentifier(updateElement.Value.Column.ColumnName);
|
||||
string paramName = $"@Value{RowId}_{updateElement.Key}";
|
||||
setComponents.Add($"{formattedColumnName} = {paramName}");
|
||||
SqlParameter parameter = new SqlParameter(paramName, updateElement.Value.Column.SqlDbType)
|
||||
@@ -94,7 +94,7 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
|
||||
// Build the "OUTPUT" portion of the statement
|
||||
var outColumns = from c in AssociatedResultSet.Columns
|
||||
let formatted = SqlScriptFormatter.FormatIdentifier(c.ColumnName)
|
||||
let formatted = ToSqlScript.FormatIdentifier(c.ColumnName)
|
||||
select $"inserted.{formatted}";
|
||||
string outColumnsJoined = string.Join(", ", outColumns);
|
||||
|
||||
@@ -148,8 +148,8 @@ namespace Microsoft.SqlTools.ServiceLayer.EditData.UpdateManagement
|
||||
// Build the "SET" portion of the statement
|
||||
var setComponents = cellUpdates.Values.Select(cellUpdate =>
|
||||
{
|
||||
string formattedColumnName = SqlScriptFormatter.FormatIdentifier(cellUpdate.Column.ColumnName);
|
||||
string formattedValue = SqlScriptFormatter.FormatValue(cellUpdate.Value, cellUpdate.Column);
|
||||
string formattedColumnName = ToSqlScript.FormatIdentifier(cellUpdate.Column.ColumnName);
|
||||
string formattedValue = ToSqlScript.FormatValue(cellUpdate.Value, cellUpdate.Column);
|
||||
return $"{formattedColumnName} = {formattedValue}";
|
||||
});
|
||||
string setClause = string.Join(", ", setComponents);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -208,6 +208,8 @@ EditDataUpdateNotPending = Given row ID does not have pending update
|
||||
|
||||
EditDataObjectMetadataNotFound = Table or view metadata could not be found
|
||||
|
||||
EditDataInvalidFormat(string colName, string colType) = Invalid format for column '{0}', column is defined as {1}
|
||||
|
||||
EditDataInvalidFormatBinary = Invalid format for binary column
|
||||
|
||||
EditDataInvalidFormatBoolean = Allowed values for boolean columns are 0, 1, "true", or "false"
|
||||
@@ -303,7 +305,11 @@ TestLocalizationConstant = test
|
||||
############################################################################
|
||||
# Utilities
|
||||
|
||||
SqlScriptFormatterDecimalMissingPrecision = Decimal column is missing numeric precision or numeric scale
|
||||
SqlScriptFormatterDecimalMissingPrecision = Exact numeric column is missing numeric precision or numeric scale
|
||||
|
||||
SqlScriptFormatterLengthTypeMissingSize = Column with length is missing size
|
||||
|
||||
SqlScriptFormatterScalarTypeMissingScale = Scalar column missing scale
|
||||
|
||||
############################################################################
|
||||
# Object Explorer Service
|
||||
|
||||
@@ -523,7 +523,7 @@
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SqlScriptFormatterDecimalMissingPrecision">
|
||||
<source>Decimal column is missing numeric precision or numeric scale</source>
|
||||
<source>Exact numeric column is missing numeric precision or numeric scale</source>
|
||||
<target state="new">Decimal column is missing numeric precision or numeric scale</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
@@ -2312,6 +2312,22 @@
|
||||
<note>.
|
||||
Parameters: 0 - value (string), 1 - columnType (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="EditDataInvalidFormat">
|
||||
<source>Invalid format for column '{0}', column is defined as {1}</source>
|
||||
<target state="new">Invalid format for column '{0}', column is defined as {1}</target>
|
||||
<note>.
|
||||
Parameters: 0 - colName (string), 1 - colType (string) </note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SqlScriptFormatterLengthTypeMissingSize">
|
||||
<source>Column with length is missing size</source>
|
||||
<target state="new">Column with length is missing size</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="SqlScriptFormatterScalarTypeMissingScale">
|
||||
<source>Scalar column missing scale</source>
|
||||
<target state="new">Scalar column missing scale</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="StoredProcedureScriptParameterComment">
|
||||
<source>-- TODO: Set parameter values here.</source>
|
||||
<target state="new">-- TODO: Set parameter values here.</target>
|
||||
@@ -2319,7 +2335,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingGeneralError">
|
||||
<source>An error occurred while scripting the objects.</source>
|
||||
<target state="new">An error occurred while scripting the objects</target>
|
||||
<target state="new">An error occurred while scripting the objects.</target>
|
||||
<note></note>
|
||||
</trans-unit>
|
||||
<trans-unit id="ScriptingExecuteNotSupportedError">
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@ using System.Data.SqlClient;
|
||||
using Microsoft.SqlServer.Management.Common;
|
||||
using Microsoft.SqlServer.Management.Smo;
|
||||
using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
||||
{
|
||||
@@ -92,13 +92,13 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
||||
// The default value may be escaped
|
||||
string defaultValue = smoColumn.DefaultConstraint == null
|
||||
? null
|
||||
: SqlScriptFormatter.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
|
||||
: FromSqlScript.UnwrapLiteral(smoColumn.DefaultConstraint.Text);
|
||||
|
||||
ColumnMetadata column = new ColumnMetadata
|
||||
{
|
||||
DefaultValue = defaultValue,
|
||||
EscapedName = SqlScriptFormatter.FormatIdentifier(smoColumn.Name),
|
||||
Ordinal = i,
|
||||
EscapedName = ToSqlScript.FormatIdentifier(smoColumn.Name),
|
||||
Ordinal = i
|
||||
};
|
||||
editColumns.Add(column);
|
||||
}
|
||||
@@ -109,7 +109,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Metadata
|
||||
|
||||
// Escape the parts of the name
|
||||
string[] objectNameParts = {smoResult.Schema, smoResult.Name};
|
||||
string escapedMultipartName = SqlScriptFormatter.FormatMultipartIdentifier(objectNameParts);
|
||||
string escapedMultipartName = ToSqlScript.FormatMultipartIdentifier(objectNameParts);
|
||||
|
||||
return new TableMetadata
|
||||
{
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
<Reference Include="System.Data.SqlClient" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Smo" Version="140.2.8" />
|
||||
<PackageReference Include="System.Data.SqlClient" Version="4.4.0" />
|
||||
<PackageReference Include="Microsoft.SqlServer.Smo" Version="140.2.8" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="**\*.cs" />
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides utilities for converting from SQL script syntax into POCOs.
|
||||
/// </summary>
|
||||
public static class FromSqlScript
|
||||
{
|
||||
// Regex: optionally starts with N, captures string wrapped in single quotes
|
||||
private static readonly Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled);
|
||||
|
||||
/// <summary>
|
||||
/// Decodes a multipart identifier as used in a SQL script into an array of the multiple
|
||||
/// parts of the identifier. Implemented as a state machine that iterates over the
|
||||
/// characters of the multipart identifier.
|
||||
/// </summary>
|
||||
/// <param name="multipartIdentifier">Multipart identifier to decode (eg, "[dbo].[test]")</param>
|
||||
/// <returns>The parts of the multipart identifier in an array (eg, "dbo", "test")</returns>
|
||||
/// <exception cref="FormatException">
|
||||
/// Thrown if an invalid state transition is made, indicating that the multipart identifer
|
||||
/// is not valid.
|
||||
/// </exception>
|
||||
public static string[] DecodeMultipartIdentifier(string multipartIdentifier)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<string> namedParts = new List<string>();
|
||||
bool insideBrackets = false;
|
||||
bool bracketsClosed = false;
|
||||
for (int i = 0; i < multipartIdentifier.Length; i++)
|
||||
{
|
||||
char iChar = multipartIdentifier[i];
|
||||
if (insideBrackets)
|
||||
{
|
||||
if (iChar == ']')
|
||||
{
|
||||
if (HasNextCharacter(multipartIdentifier, ']', i))
|
||||
{
|
||||
// This is an escaped ]
|
||||
sb.Append(iChar);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This bracket closes the bracket we were in
|
||||
insideBrackets = false;
|
||||
bracketsClosed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a standard character
|
||||
sb.Append(iChar);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (iChar)
|
||||
{
|
||||
case '[':
|
||||
if (bracketsClosed)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// We're opening a set of brackets
|
||||
insideBrackets = true;
|
||||
bracketsClosed = false;
|
||||
break;
|
||||
case '.':
|
||||
if (sb.Length == 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// We're splitting the identifier into a new part
|
||||
namedParts.Add(sb.ToString());
|
||||
sb = new StringBuilder();
|
||||
bracketsClosed = false;
|
||||
break;
|
||||
default:
|
||||
if (bracketsClosed)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// This is a standard character
|
||||
sb.Append(iChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sb.Length == 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
namedParts.Add(sb.ToString());
|
||||
return namedParts.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a value from a script into a plain version by unwrapping literal wrappers
|
||||
/// and unescaping characters.
|
||||
/// </summary>
|
||||
/// <param name="literal">The value to unwrap (eg, "(N'foo''bar')")</param>
|
||||
/// <returns>The unwrapped/unescaped literal (eg, "foo'bar")</returns>
|
||||
public static string UnwrapLiteral(string literal)
|
||||
{
|
||||
// Always remove parens
|
||||
literal = literal.Trim('(', ')');
|
||||
|
||||
// Attempt to unwrap inverted commas around a string
|
||||
Match match = StringRegex.Match(literal);
|
||||
if (match.Success)
|
||||
{
|
||||
// Like: N'stuff' or 'stuff'
|
||||
return UnEscapeString(match.Groups[1].Value, '\'');
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
#region Private Helpers
|
||||
|
||||
private static bool HasNextCharacter(string haystack, char needle, int position)
|
||||
{
|
||||
return position + 1 < haystack.Length
|
||||
&& haystack[position + 1] == needle;
|
||||
}
|
||||
|
||||
private static string UnEscapeString(string value, char escapeCharacter)
|
||||
{
|
||||
Validate.IsNotNull(nameof(value), value);
|
||||
|
||||
// Replace 2x of the escape character with 1x of the escape character
|
||||
return value.Replace(new string(escapeCharacter, 2), escapeCharacter.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -9,17 +9,16 @@ using System.Data.Common;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.Utility;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
namespace Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides utility for converting arbitrary objects into strings that are ready to be
|
||||
/// inserted into SQL strings
|
||||
/// </summary>
|
||||
public class SqlScriptFormatter
|
||||
public static class ToSqlScript
|
||||
{
|
||||
#region Constants
|
||||
|
||||
@@ -27,16 +26,16 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
|
||||
private static readonly Dictionary<string, Func<object, DbColumn, string>> FormatFunctions =
|
||||
new Dictionary<string, Func<object, DbColumn, string>>
|
||||
{ // CLR Type --------
|
||||
{ // CLR Type --------
|
||||
{"bigint", (val, col) => SimpleFormatter(val)}, // long
|
||||
{"bit", (val, col) => FormatBool(val)}, // bool
|
||||
{"int", (val, col) => SimpleFormatter(val)}, // int
|
||||
{"smallint", (val, col) => SimpleFormatter(val)}, // short
|
||||
{"tinyint", (val, col) => SimpleFormatter(val)}, // byte
|
||||
{"money", (val, col) => FormatMoney(val, "MONEY")}, // Decimal
|
||||
{"smallmoney", (val, col) => FormatMoney(val, "SMALLMONEY")}, // Decimal
|
||||
{"decimal", (val, col) => FormatPreciseNumeric(val, col, "DECIMAL")}, // Decimal
|
||||
{"numeric", (val, col) => FormatPreciseNumeric(val, col, "NUMERIC")}, // Decimal
|
||||
{"money", FormatDecimalLike}, // Decimal
|
||||
{"smallmoney", FormatDecimalLike}, // Decimal
|
||||
{"decimal", FormatDecimalLike}, // Decimal
|
||||
{"numeric", FormatDecimalLike}, // Decimal
|
||||
{"real", (val, col) => FormatFloat(val)}, // float
|
||||
{"float", (val, col) => FormatDouble(val)}, // double
|
||||
{"smalldatetime", (val, col) => FormatDateTime(val, "yyyy-MM-dd HH:mm:ss")}, // DateTime
|
||||
@@ -65,21 +64,105 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
// sysname - it doesn't appear possible to insert a sysname column
|
||||
};
|
||||
|
||||
private static readonly Type[] NumericTypes =
|
||||
{
|
||||
typeof(byte),
|
||||
typeof(short),
|
||||
typeof(int),
|
||||
typeof(long),
|
||||
typeof(decimal),
|
||||
typeof(float),
|
||||
typeof(double)
|
||||
};
|
||||
|
||||
private static Regex StringRegex = new Regex("^N?'(.*)'$", RegexOptions.Compiled);
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Extracts a DbColumn's datatype and turns it into script ready
|
||||
/// </summary>
|
||||
/// <param name="column"></param>
|
||||
/// <returns></returns>
|
||||
/// <seealso cref="Microsoft.SqlTools.ServiceLayer.ObjectExplorer.SmoModel.SmoColumnCustomNodeHelper.GetTypeSpecifierLabel"/>
|
||||
/// <exception cref="InvalidOperationException"></exception>
|
||||
public static string FormatColumnType(DbColumn column)
|
||||
{
|
||||
string typeName = column.DataTypeName.ToUpperInvariant();
|
||||
|
||||
// TODO: This doesn't support UDTs at all.
|
||||
// TODO: It's unclear if this will work on a case-sensitive db collation
|
||||
|
||||
// If the type supports length parameters, the add those
|
||||
switch (column.DataTypeName.ToLowerInvariant())
|
||||
{
|
||||
// Types with length
|
||||
case "char":
|
||||
case "nchar":
|
||||
case "varchar":
|
||||
case "nvarchar":
|
||||
case "binary":
|
||||
case "varbinary":
|
||||
if (!column.ColumnSize.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException(SR.SqlScriptFormatterLengthTypeMissingSize);
|
||||
}
|
||||
|
||||
string length = column.ColumnSize.Value == int.MaxValue
|
||||
? "MAX"
|
||||
: column.ColumnSize.Value.ToString();
|
||||
|
||||
typeName += $"({length})";
|
||||
break;
|
||||
|
||||
// Types with precision and scale
|
||||
case "numeric":
|
||||
case "decimal":
|
||||
if (!column.NumericPrecision.HasValue || !column.NumericScale.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException(SR.SqlScriptFormatterDecimalMissingPrecision);
|
||||
}
|
||||
typeName += $"({column.NumericPrecision}, {column.NumericScale})";
|
||||
break;
|
||||
|
||||
// Types with scale only
|
||||
case "datetime2":
|
||||
case "datetimeoffset":
|
||||
case "time":
|
||||
if (!column.NumericScale.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException(SR.SqlScriptFormatterScalarTypeMissingScale);
|
||||
}
|
||||
typeName += $"({column.NumericScale})";
|
||||
break;
|
||||
}
|
||||
|
||||
return typeName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes an identifier such as a table name or column name by wrapping it in square brackets
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier to format</param>
|
||||
/// <returns>Identifier formatted for use in a SQL script</returns>
|
||||
public static string FormatIdentifier(string identifier)
|
||||
{
|
||||
return $"[{EscapeString(identifier, ']')}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes a multi-part identifier such as a table name or column name with multiple
|
||||
/// parts split by '.'
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier to escape (eg, "dbo.test")</param>
|
||||
/// <returns>The escaped identifier (eg, "[dbo].[test]")</returns>
|
||||
public static string FormatMultipartIdentifier(string identifier)
|
||||
{
|
||||
// If the object is a multi-part identifier (eg, dbo.tablename) split it, and escape as necessary
|
||||
return FormatMultipartIdentifier(identifier.Split('.'));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes a multipart identifier such as a table name, given an array of the parts of the
|
||||
/// multipart identifier.
|
||||
/// </summary>
|
||||
/// <param name="identifiers">The parts of the identifier to escape (eg, "dbo", "test")</param>
|
||||
/// <returns>An escaped version of the multipart identifier (eg, "[dbo].[test]")</returns>
|
||||
public static string FormatMultipartIdentifier(string[] identifiers)
|
||||
{
|
||||
IEnumerable<string> escapedParts = identifiers.Select(FormatIdentifier);
|
||||
return string.Join(".", escapedParts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts an object into a string for SQL script
|
||||
/// </summary>
|
||||
@@ -107,7 +190,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
}
|
||||
return FormatFunctions[dataType](value, column);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Converts a cell value into a string for SQL script
|
||||
/// </summary>
|
||||
@@ -120,229 +203,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
|
||||
return FormatValue(value.RawObject, column);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes an identifier such as a table name or column name by wrapping it in square brackets
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier to format</param>
|
||||
/// <returns>Identifier formatted for use in a SQL script</returns>
|
||||
public static string FormatIdentifier(string identifier)
|
||||
{
|
||||
return $"[{EscapeString(identifier, ']')}]";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes a multi-part identifier such as a table name or column name with multiple
|
||||
/// parts split by '.'
|
||||
/// </summary>
|
||||
/// <param name="identifier">The identifier to escape</param>
|
||||
/// <returns>The escaped identifier</returns>
|
||||
public static string FormatMultipartIdentifier(string identifier)
|
||||
{
|
||||
// If the object is a multi-part identifier (eg, dbo.tablename) split it, and escape as necessary
|
||||
return FormatMultipartIdentifier(identifier.Split('.'));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Escapes a multipart identifier such as a table name, given an array of the parts of the
|
||||
/// multipart identifier.
|
||||
/// </summary>
|
||||
/// <param name="identifiers">The parts of the identifier to escape</param>
|
||||
/// <returns>An escaped version of the multipart identifier</returns>
|
||||
public static string FormatMultipartIdentifier(string[] identifiers)
|
||||
{
|
||||
IEnumerable<string> escapedParts = identifiers.Select(FormatIdentifier);
|
||||
return string.Join(".", escapedParts);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts a value from a script into a plain version by unwrapping literal wrappers
|
||||
/// and unescaping characters.
|
||||
/// </summary>
|
||||
/// <param name="literal">The value to unwrap</param>
|
||||
/// <returns>The unwrapped/unescaped literal</returns>
|
||||
public static string UnwrapLiteral(string literal)
|
||||
{
|
||||
// Always remove parens
|
||||
literal = literal.Trim('(', ')');
|
||||
|
||||
// Attempt to unwrap inverted commas around a string
|
||||
Match match = StringRegex.Match(literal);
|
||||
if (match.Success)
|
||||
{
|
||||
// Like: N'stuff' or 'stuff'
|
||||
return UnEscapeString(match.Groups[1].Value, '\'');
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
|
||||
public static string[] DecodeMultipartIdenfitier(string multipartIdentifier)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
List<string> namedParts = new List<string>();
|
||||
bool insideBrackets = false;
|
||||
bool bracketsClosed = false;
|
||||
for (int i = 0; i < multipartIdentifier.Length; i++)
|
||||
{
|
||||
char iChar = multipartIdentifier[i];
|
||||
if (insideBrackets)
|
||||
{
|
||||
if (iChar == ']')
|
||||
{
|
||||
if (HasNextCharacter(multipartIdentifier, ']', i))
|
||||
{
|
||||
// This is an escaped ]
|
||||
sb.Append(iChar);
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// This bracket closes the bracket we were in
|
||||
insideBrackets = false;
|
||||
bracketsClosed = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a standard character
|
||||
sb.Append(iChar);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (iChar)
|
||||
{
|
||||
case '[':
|
||||
if (bracketsClosed)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// We're opening a set of brackets
|
||||
insideBrackets = true;
|
||||
bracketsClosed = false;
|
||||
break;
|
||||
case '.':
|
||||
if (sb.Length == 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// We're splitting the identifier into a new part
|
||||
namedParts.Add(sb.ToString());
|
||||
sb = new StringBuilder();
|
||||
bracketsClosed = false;
|
||||
break;
|
||||
default:
|
||||
if (bracketsClosed)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
|
||||
// This is a standard character
|
||||
sb.Append(iChar);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sb.Length == 0)
|
||||
{
|
||||
throw new FormatException();
|
||||
}
|
||||
namedParts.Add(sb.ToString());
|
||||
return namedParts.ToArray();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helpers
|
||||
|
||||
private static string SimpleFormatter(object value)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
private static string SimpleStringFormatter(object value)
|
||||
{
|
||||
return EscapeQuotedSqlString(value.ToString());
|
||||
}
|
||||
|
||||
private static string FormatMoney(object value, string type)
|
||||
{
|
||||
// we have to manually format the string by ToStringing the value first, and then converting
|
||||
// the potential (European formatted) comma to a period.
|
||||
string numericString = ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
return $"CAST({numericString} AS {type})";
|
||||
}
|
||||
|
||||
private static string FormatFloat(object value)
|
||||
{
|
||||
// The "R" formatting means "Round Trip", which preserves fidelity
|
||||
return ((float)value).ToString("R");
|
||||
}
|
||||
|
||||
private static string FormatDouble(object value)
|
||||
{
|
||||
// The "R" formatting means "Round Trip", which preserves fidelity
|
||||
return ((double)value).ToString("R");
|
||||
}
|
||||
|
||||
private static string FormatBool(object value)
|
||||
{
|
||||
// Attempt to cast to bool
|
||||
bool boolValue = (bool)value;
|
||||
return boolValue ? "1" : "0";
|
||||
}
|
||||
|
||||
private static string FormatPreciseNumeric(object value, DbColumn column, string type)
|
||||
{
|
||||
// Make sure we have numeric precision and numeric scale
|
||||
if (!column.NumericPrecision.HasValue || !column.NumericScale.HasValue)
|
||||
{
|
||||
throw new InvalidOperationException(SR.SqlScriptFormatterDecimalMissingPrecision);
|
||||
}
|
||||
|
||||
// Convert the value to a decimal, then convert that to a string
|
||||
string numericString = ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
return string.Format(CultureInfo.InvariantCulture, "CAST({0} AS {1}({2}, {3}))",
|
||||
numericString, type, column.NumericPrecision.Value, column.NumericScale.Value);
|
||||
}
|
||||
|
||||
private static string FormatTimeSpan(object value)
|
||||
{
|
||||
// "c" provides "HH:mm:ss.FFFFFFF", and time column accepts up to 7 precision
|
||||
string timeSpanString = ((TimeSpan)value).ToString("c", CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(timeSpanString);
|
||||
}
|
||||
|
||||
private static string FormatDateTime(object value, string format)
|
||||
{
|
||||
string dateTimeString = ((DateTime)value).ToString(format, CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(dateTimeString);
|
||||
}
|
||||
|
||||
private static string FormatDateTimeOffset(object value)
|
||||
{
|
||||
string dateTimeString = ((DateTimeOffset)value).ToString(CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(dateTimeString);
|
||||
}
|
||||
|
||||
private static string FormatBinary(object value)
|
||||
{
|
||||
byte[] bytes = value as byte[];
|
||||
if (bytes == null)
|
||||
{
|
||||
// Bypass processing if we can't turn this into a byte[]
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
return "0x" + BitConverter.ToString(bytes).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
private static bool HasNextCharacter(string haystack, char needle, int position)
|
||||
{
|
||||
return position + 1 < haystack.Length
|
||||
&& haystack[position + 1] == needle;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a valid SQL string packaged in single quotes with single quotes inside escaped
|
||||
/// </summary>
|
||||
@@ -352,7 +217,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
{
|
||||
return $"N'{EscapeString(rawString, '\'')}'";
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Replaces all instances of <paramref name="escapeCharacter"/> with a duplicate of
|
||||
/// <paramref name="escapeCharacter"/>. For example "can't" becomes "can''t"
|
||||
@@ -375,15 +240,74 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static string UnEscapeString(string value, char escapeCharacter)
|
||||
|
||||
private static string FormatBinary(object value)
|
||||
{
|
||||
Validate.IsNotNull(nameof(value), value);
|
||||
byte[] bytes = value as byte[];
|
||||
if (bytes == null)
|
||||
{
|
||||
// Bypass processing if we can't turn this into a byte[]
|
||||
return "NULL";
|
||||
}
|
||||
|
||||
// Replace 2x of the escape character with 1x of the escape character
|
||||
return value.Replace(new string(escapeCharacter, 2), escapeCharacter.ToString());
|
||||
return "0x" + BitConverter.ToString(bytes).Replace("-", string.Empty);
|
||||
}
|
||||
|
||||
private static string FormatBool(object value)
|
||||
{
|
||||
// Attempt to cast to bool
|
||||
bool boolValue = (bool)value;
|
||||
return boolValue ? "1" : "0";
|
||||
}
|
||||
|
||||
private static string FormatDateTime(object value, string format)
|
||||
{
|
||||
string dateTimeString = ((DateTime)value).ToString(format, CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(dateTimeString);
|
||||
}
|
||||
|
||||
private static string FormatDateTimeOffset(object value)
|
||||
{
|
||||
string dateTimeString = ((DateTimeOffset)value).ToString(CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(dateTimeString);
|
||||
}
|
||||
|
||||
private static string FormatDouble(object value)
|
||||
{
|
||||
// The "R" formatting means "Round Trip", which preserves fidelity
|
||||
return ((double)value).ToString("R");
|
||||
}
|
||||
|
||||
private static string FormatFloat(object value)
|
||||
{
|
||||
// The "R" formatting means "Round Trip", which preserves fidelity
|
||||
return ((float)value).ToString("R");
|
||||
}
|
||||
|
||||
private static string FormatDecimalLike(object value, DbColumn column)
|
||||
{
|
||||
string numericString = ((decimal)value).ToString(CultureInfo.InvariantCulture);
|
||||
string typeString = FormatColumnType(column);
|
||||
return $"CAST({numericString} AS {typeString})";
|
||||
}
|
||||
|
||||
private static string FormatTimeSpan(object value)
|
||||
{
|
||||
// "c" provides "HH:mm:ss.FFFFFFF", and time column accepts up to 7 precision
|
||||
string timeSpanString = ((TimeSpan)value).ToString("c", CultureInfo.InvariantCulture);
|
||||
return EscapeQuotedSqlString(timeSpanString);
|
||||
}
|
||||
|
||||
private static string SimpleFormatter(object value)
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
private static string SimpleStringFormatter(object value)
|
||||
{
|
||||
return EscapeQuotedSqlString(value.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
|
||||
// If: I attempt to create a CellUpdate to set it to a large string
|
||||
// Then: I should get an exception thrown
|
||||
DbColumnWrapper col = GetWrapper<string>("nvarchar", false, 6);
|
||||
Assert.Throws<FormatException>(() => new CellUpdate(col, value));
|
||||
Assert.Throws<InvalidOperationException>(() => new CellUpdate(col, value));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -140,7 +140,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
|
||||
// If: I attempt to create a CellUpdate for a binary column
|
||||
// Then: It should throw an exception
|
||||
DbColumnWrapper col = GetWrapper<byte[]>("binary");
|
||||
Assert.Throws<FormatException>(() => new CellUpdate(col, "this is totally invalid"));
|
||||
Assert.Throws<InvalidOperationException>(() => new CellUpdate(col, "this is totally invalid"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
@@ -175,7 +175,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.EditData
|
||||
// If: I create a CellUpdate for a bool column and provide an invalid numeric value
|
||||
// Then: It should throw an exception
|
||||
DbColumnWrapper col = GetWrapper<bool>("bit");
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => new CellUpdate(col, "12345"));
|
||||
Assert.Throws<InvalidOperationException>(() => new CellUpdate(col, "12345"));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests
|
||||
{
|
||||
public class FromSqlScriptTests
|
||||
{
|
||||
#region DecodeMultipartIdentifier Tests
|
||||
|
||||
public static IEnumerable<object> DecodeMultipartIdentifierTestData
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] {"identifier", new[] {"identifier"}};
|
||||
yield return new object[] {"simple.split", new[] {"simple", "split"}};
|
||||
yield return new object[] {"multi.simple.split", new[] {"multi", "simple", "split"}};
|
||||
yield return new object[] {"[escaped]", new[] {"escaped"}};
|
||||
yield return new object[] {"[escaped].[split]", new[] {"escaped", "split"}};
|
||||
yield return new object[] {"[multi].[escaped].[split]", new[] {"multi", "escaped", "split"}};
|
||||
yield return new object[] {"[escaped]]characters]", new[] {"escaped]characters"}};
|
||||
yield return new object[] {"[multi]]escaped]]chars]", new[] {"multi]escaped]chars"}};
|
||||
yield return new object[] {"[multi]]]]chars]", new[] {"multi]]chars"}};
|
||||
yield return new object[] {"unescaped]chars", new[] {"unescaped]chars"}};
|
||||
yield return new object[] {"multi]unescaped]chars", new[] {"multi]unescaped]chars"}};
|
||||
yield return new object[] {"multi]]chars", new[] {"multi]]chars"}};
|
||||
yield return new object[] {"[escaped.dot]", new[] {"escaped.dot"}};
|
||||
yield return new object[] {"mixed.[escaped]", new[] {"mixed", "escaped"}};
|
||||
yield return new object[] {"[escaped].mixed", new[] {"escaped", "mixed"}};
|
||||
yield return new object[] {"dbo.[[].weird", new[] {"dbo", "[", "weird"}};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(DecodeMultipartIdentifierTestData))]
|
||||
public void DecodeMultipartIdentifierTest(string input, string[] output)
|
||||
{
|
||||
// If: I decode the input
|
||||
string[] decoded = FromSqlScript.DecodeMultipartIdentifier(input);
|
||||
|
||||
// Then: The output should match what was expected
|
||||
Assert.Equal(output, decoded);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("[bracket]closed")]
|
||||
[InlineData("[bracket][closed")]
|
||||
[InlineData(".stuff")]
|
||||
[InlineData(".")]
|
||||
public void DecodeMultipartIdentifierFailTest(string input)
|
||||
{
|
||||
// If: I decode an invalid input
|
||||
// Then: It should throw an exception
|
||||
Assert.Throws<FormatException>(() => FromSqlScript.DecodeMultipartIdentifier(input));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Theory]
|
||||
[InlineData("(0)", "0")]
|
||||
[InlineData("((0))", "0")]
|
||||
[InlineData("('')", "")]
|
||||
[InlineData("('stuff')", "stuff")]
|
||||
[InlineData("(N'')", "")]
|
||||
[InlineData("(N'stuff')", "stuff")]
|
||||
[InlineData("('''stuff')", "'stuff")]
|
||||
[InlineData("(N'stu''''ff')", "stu''ff")]
|
||||
public void UnescapeTest(string input, string output)
|
||||
{
|
||||
Assert.Equal(output, FromSqlScript.UnwrapLiteral(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,83 +1,16 @@
|
||||
//
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.SqlTools.ServiceLayer.QueryExecution.Contracts;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.UnitTests.Utility;
|
||||
using Microsoft.SqlTools.ServiceLayer.Utility.SqlScriptFormatters;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
namespace Microsoft.SqlTools.ServiceLayer.UnitTests.UtilityTests
|
||||
{
|
||||
public class SqlScriptFormatterTests
|
||||
public class ToSqlScriptTests
|
||||
{
|
||||
#region Format Identifier Tests
|
||||
|
||||
[Fact]
|
||||
public void FormatIdentifierNull()
|
||||
{
|
||||
// If: I attempt to format null as an identifier
|
||||
// Then: I should get an exception thrown
|
||||
Assert.Throws<ArgumentNullException>(() => SqlScriptFormatter.FormatIdentifier(null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("test", "[test]")] // No escape characters
|
||||
[InlineData("]test", "[]]test]")] // Escape character at beginning
|
||||
[InlineData("te]st", "[te]]st]")] // Escape character in middle
|
||||
[InlineData("test]", "[test]]]")] // Escape character at end
|
||||
[InlineData("t]]est", "[t]]]]est]")] // Multiple escape characters
|
||||
public void FormatIdentifierTest(string value, string expectedOutput)
|
||||
{
|
||||
// If: I attempt to format a value as an identifier
|
||||
string output = SqlScriptFormatter.FormatIdentifier(value);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("test", "[test]")] // No splits, no escape characters
|
||||
[InlineData("test.test", "[test].[test]")] // One split, no escape characters
|
||||
[InlineData("test.te]st", "[test].[te]]st]")] // One split, one escape character
|
||||
[InlineData("test.test.test", "[test].[test].[test]")] // Two splits, no escape characters
|
||||
public void FormatMultipartIdentifierTest(string value, string expectedOutput)
|
||||
{
|
||||
// If: I attempt to format a value as a multipart identifier
|
||||
string output = SqlScriptFormatter.FormatMultipartIdentifier(value);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(GetMultipartIdentifierArrays))]
|
||||
public void FormatMultipartIdentifierArrayTest(string expectedOutput, string[] splits)
|
||||
{
|
||||
// If: I attempt to format a value as a multipart identifier
|
||||
string output = SqlScriptFormatter.FormatMultipartIdentifier(splits);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetMultipartIdentifierArrays
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] {"[test]", new[] {"test"}}; // No splits, no escape characters
|
||||
yield return new object[] {"[test].[test]", new[] {"test", "test"}}; // One split, no escape characters
|
||||
yield return new object[] {"[test].[te]]st]", new[] {"test", "te]st"}}; // One split, one escape character
|
||||
yield return new object[] {"[test].[test].[test]", new[] {"test", "test", "test"}}; // Two splits, no escape characters
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region FormatValue Tests
|
||||
|
||||
[Fact]
|
||||
@@ -85,7 +18,8 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
{
|
||||
// If: I attempt to format a null db cell
|
||||
// Then: It should throw
|
||||
Assert.Throws<ArgumentNullException>(() => SqlScriptFormatter.FormatValue(null, new FormatterTestDbColumn(null)));
|
||||
DbColumn column = new FormatterTestDbColumn(null);
|
||||
Assert.Throws<ArgumentNullException>(() => ToSqlScript.FormatValue(null, column));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -93,7 +27,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
{
|
||||
// If: I attempt to format a null db column
|
||||
// Then: It should throw
|
||||
Assert.Throws<ArgumentNullException>(() => SqlScriptFormatter.FormatValue(new DbCellValue(), null));
|
||||
Assert.Throws<ArgumentNullException>(() => ToSqlScript.FormatValue(new DbCellValue(), null));
|
||||
}
|
||||
|
||||
public void UnsupportedColumnTest()
|
||||
@@ -101,7 +35,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
// If: I attempt to format an unsupported datatype
|
||||
// Then: It should throw
|
||||
DbColumn column = new FormatterTestDbColumn("unsupported");
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => SqlScriptFormatter.FormatValue(new DbCellValue(), column));
|
||||
Assert.Throws<ArgumentOutOfRangeException>(() => ToSqlScript.FormatValue(new DbCellValue(), column));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -109,8 +43,9 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
{
|
||||
// If: I attempt to format a db cell that contains null
|
||||
// Then: I should get the null string back
|
||||
string formattedString = SqlScriptFormatter.FormatValue(new DbCellValue(), new FormatterTestDbColumn(null));
|
||||
Assert.Equal(SqlScriptFormatter.NullString, formattedString);
|
||||
DbColumn column = new FormatterTestDbColumn(null);
|
||||
string formattedString = ToSqlScript.FormatValue(new DbCellValue(), new FormatterTestDbColumn(null));
|
||||
Assert.Equal(ToSqlScript.NullString, formattedString);
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +61,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = (long)123 };
|
||||
|
||||
// If: I attempt to format an integer type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a long
|
||||
Assert.Equal(cell.RawObject, long.Parse(output));
|
||||
@@ -144,7 +79,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = 123.45m };
|
||||
|
||||
// If: I attempt to format a decimal type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: It should match a something like CAST(123.45 AS MONEY)
|
||||
Regex castRegex = new Regex($@"CAST\([\d\.]+ AS {regex}", RegexOptions.IgnoreCase);
|
||||
@@ -159,7 +94,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = 3.14159d };
|
||||
|
||||
// If: I attempt to format a approx numeric type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a double
|
||||
Assert.Equal(cell.RawObject, double.Parse(output));
|
||||
@@ -173,7 +108,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = (float)3.14159 };
|
||||
|
||||
// If: I attempt to format a approx numeric type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a double
|
||||
Assert.Equal(cell.RawObject, float.Parse(output));
|
||||
@@ -191,7 +126,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = DateTime.Now };
|
||||
|
||||
// If: I attempt to format a datetime type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a datetime
|
||||
Regex dateTimeRegex = new Regex("N'(.*)'");
|
||||
@@ -207,7 +142,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = DateTimeOffset.Now };
|
||||
|
||||
// If: I attempt to format a datetime offset type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a datetime offset
|
||||
Regex dateTimeRegex = new Regex("N'(.*)'");
|
||||
@@ -223,7 +158,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = TimeSpan.FromHours(12) };
|
||||
|
||||
// If: I attempt to format a time type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be able to be converted back into a timespan
|
||||
Regex dateTimeRegex = new Regex("N'(.*)'");
|
||||
@@ -244,7 +179,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = input };
|
||||
|
||||
// If: I attempt to format a string type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should be quoted and escaped properly
|
||||
Assert.Equal(expectedOutput, output);
|
||||
@@ -264,7 +199,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = "test string" };
|
||||
|
||||
// If: I attempt to format a string type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should match the output string
|
||||
Assert.Equal("N'test string'", output);
|
||||
@@ -284,7 +219,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
};
|
||||
|
||||
// If: I attempt to format a string type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should match the output string
|
||||
Regex regex = new Regex("0x[0-9A-F]+", RegexOptions.IgnoreCase);
|
||||
@@ -299,7 +234,7 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
DbCellValue cell = new DbCellValue { RawObject = Guid.NewGuid() };
|
||||
|
||||
// If: I attempt to format a string type column
|
||||
string output = SqlScriptFormatter.FormatValue(cell, column);
|
||||
string output = ToSqlScript.FormatValue(cell, column);
|
||||
|
||||
// Then: The output string should match the output string
|
||||
Regex regex = new Regex(@"N'[0-9A-F]{8}(-[0-9A-F]{4}){3}-[0-9A-F]{12}'", RegexOptions.IgnoreCase);
|
||||
@@ -307,79 +242,146 @@ namespace Microsoft.SqlTools.ServiceLayer.UnitTests.Utility
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Format Identifier Tests
|
||||
|
||||
#region DecodeMultipartIdentifier Tests
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(DecodeMultipartIdentifierTestData))]
|
||||
public void DecodeMultipartIdentifierTest(string input, string[] output)
|
||||
[Fact]
|
||||
public void FormatIdentifierNull()
|
||||
{
|
||||
// If: I decode the input
|
||||
string[] decoded = SqlScriptFormatter.DecodeMultipartIdenfitier(input);
|
||||
|
||||
// Then: The output should match what was expected
|
||||
Assert.Equal(output, decoded);
|
||||
// If: I attempt to format null as an identifier
|
||||
// Then: I should get an exception thrown
|
||||
Assert.Throws<ArgumentNullException>(() => ToSqlScript.FormatIdentifier(null));
|
||||
}
|
||||
|
||||
public static IEnumerable<object> DecodeMultipartIdentifierTestData
|
||||
[Theory]
|
||||
[InlineData("test", "[test]")] // No escape characters
|
||||
[InlineData("]test", "[]]test]")] // Escape character at beginning
|
||||
[InlineData("te]st", "[te]]st]")] // Escape character in middle
|
||||
[InlineData("test]", "[test]]]")] // Escape character at end
|
||||
[InlineData("t]]est", "[t]]]]est]")] // Multiple escape characters
|
||||
public void FormatIdentifierTest(string value, string expectedOutput)
|
||||
{
|
||||
// If: I attempt to format a value as an identifier
|
||||
string output = ToSqlScript.FormatIdentifier(value);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("test", "[test]")] // No splits, no escape characters
|
||||
[InlineData("test.test", "[test].[test]")] // One split, no escape characters
|
||||
[InlineData("test.te]st", "[test].[te]]st]")] // One split, one escape character
|
||||
[InlineData("test.test.test", "[test].[test].[test]")] // Two splits, no escape characters
|
||||
public void FormatMultipartIdentifierTest(string value, string expectedOutput)
|
||||
{
|
||||
// If: I attempt to format a value as a multipart identifier
|
||||
string output = ToSqlScript.FormatMultipartIdentifier(value);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> GetMultipartIdentifierArrays
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return new object[] {"identifier", new[] {"identifier"}};
|
||||
yield return new object[] {"simple.split", new[] {"simple", "split"}};
|
||||
yield return new object[] {"multi.simple.split", new[] {"multi", "simple", "split"}};
|
||||
yield return new object[] {"[escaped]", new[] {"escaped"}};
|
||||
yield return new object[] {"[escaped].[split]", new[] {"escaped", "split"}};
|
||||
yield return new object[] {"[multi].[escaped].[split]", new[] {"multi", "escaped", "split"}};
|
||||
yield return new object[] {"[escaped]]characters]", new[] {"escaped]characters"}};
|
||||
yield return new object[] {"[multi]]escaped]]chars]", new[] {"multi]escaped]chars"}};
|
||||
yield return new object[] {"[multi]]]]chars]", new[] {"multi]]chars"}};
|
||||
yield return new object[] {"unescaped]chars", new[] {"unescaped]chars"}};
|
||||
yield return new object[] {"multi]unescaped]chars", new[] {"multi]unescaped]chars"}};
|
||||
yield return new object[] {"multi]]chars", new[] {"multi]]chars"}};
|
||||
yield return new object[] {"[escaped.dot]", new[] {"escaped.dot"}};
|
||||
yield return new object[] {"mixed.[escaped]", new[] {"mixed", "escaped"}};
|
||||
yield return new object[] {"[escaped].mixed", new[] {"escaped", "mixed"}};
|
||||
yield return new object[] {"dbo.[[].weird", new[] {"dbo", "[", "weird"}};
|
||||
yield return new object[] {"[test]", new[] {"test"}}; // No splits, no escape characters
|
||||
yield return new object[] {"[test].[test]", new[] {"test", "test"}}; // One split, no escape characters
|
||||
yield return new object[] {"[test].[te]]st]", new[] {"test", "te]st"}}; // One split, one escape character
|
||||
yield return new object[] {"[test].[test].[test]", new[] {"test", "test", "test"}}; // Two splits, no escape characters
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[Theory]
|
||||
[InlineData("[bracket]closed")]
|
||||
[InlineData("[bracket][closed")]
|
||||
[InlineData(".stuff")]
|
||||
[InlineData(".")]
|
||||
public void DecodeMultipartIdentifierFailTest(string input)
|
||||
[MemberData(nameof(GetMultipartIdentifierArrays))]
|
||||
public void FormatMultipartIdentifierArrayTest(string expectedOutput, string[] splits)
|
||||
{
|
||||
// If: I decode an invalid input
|
||||
// Then: It should throw an exception
|
||||
Assert.Throws<FormatException>(() => SqlScriptFormatter.DecodeMultipartIdenfitier(input));
|
||||
// If: I attempt to format a value as a multipart identifier
|
||||
string output = ToSqlScript.FormatMultipartIdentifier(splits);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
[Theory]
|
||||
[InlineData("(0)", "0")]
|
||||
[InlineData("((0))", "0")]
|
||||
[InlineData("('')", "")]
|
||||
[InlineData("('stuff')", "stuff")]
|
||||
[InlineData("(N'')", "")]
|
||||
[InlineData("(N'stuff')", "stuff")]
|
||||
[InlineData("('''stuff')", "'stuff")]
|
||||
[InlineData("(N'stu''''ff')", "stu''ff")]
|
||||
public void UnescapeTest(string input, string output)
|
||||
#region FormatColumnType Tests
|
||||
|
||||
public static IEnumerable<object[]> FormatColumnTypeData
|
||||
{
|
||||
Assert.Equal(output, SqlScriptFormatter.UnwrapLiteral(input));
|
||||
get
|
||||
{
|
||||
yield return new object[] {new FormatterTestDbColumn("biGint"), "BIGINT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("biT"), "BIT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("deCimal", precision: 18, scale: 0), "DECIMAL(18, 0)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("deCimal", precision: 22, scale: 2), "DECIMAL(22, 2)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("inT"), "INT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("moNey"), "MONEY"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nuMeric", precision: 18, scale: 0), "NUMERIC(18, 0)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nuMeric", precision: 22, scale: 2), "NUMERIC(22, 2)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("smAllint"), "SMALLINT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("smAllmoney"), "SMALLMONEY"};
|
||||
yield return new object[] {new FormatterTestDbColumn("tiNyint"), "TINYINT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("biNary", size: 255), "BINARY(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("biNary", size: 10), "BINARY(10)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRbinary", size: 255), "VARBINARY(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRbinary", size: 10), "VARBINARY(10)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRbinary", size: int.MaxValue), "VARBINARY(MAX)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("imAge"), "IMAGE"};
|
||||
yield return new object[] {new FormatterTestDbColumn("smAlldatetime"), "SMALLDATETIME"};
|
||||
yield return new object[] {new FormatterTestDbColumn("daTetime"), "DATETIME"};
|
||||
yield return new object[] {new FormatterTestDbColumn("daTetime2", scale: 7), "DATETIME2(7)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("daTetime2", scale: 0), "DATETIME2(0)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("daTetimeoffset", scale: 7), "DATETIMEOFFSET(7)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("daTetimeoffset", scale: 0), "DATETIMEOFFSET(0)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("tiMe", scale: 7), "TIME(7)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("flOat"), "FLOAT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("reAl"), "REAL"};
|
||||
yield return new object[] {new FormatterTestDbColumn("chAr", size: 1), "CHAR(1)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("chAr", size: 255), "CHAR(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("ncHar", size: 1), "NCHAR(1)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("ncHar", size: 255), "NCHAR(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRchar", size: 1), "VARCHAR(1)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRchar", size: 255), "VARCHAR(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("vaRchar", size: int.MaxValue), "VARCHAR(MAX)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nvArchar", size: 1), "NVARCHAR(1)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nvArchar", size: 255), "NVARCHAR(255)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nvArchar", size: int.MaxValue), "NVARCHAR(MAX)"};
|
||||
yield return new object[] {new FormatterTestDbColumn("teXt"), "TEXT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("nteXt"), "NTEXT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("unIqueidentifier"), "UNIQUEIDENTIFIER"};
|
||||
yield return new object[] {new FormatterTestDbColumn("sqL_variant"), "SQL_VARIANT"};
|
||||
yield return new object[] {new FormatterTestDbColumn("somEthing.sys.hierarchyid"), "SOMETHING.SYS.HIERARCHYID"};
|
||||
yield return new object[] {new FormatterTestDbColumn("geOgraphy"), "GEOGRAPHY"};
|
||||
yield return new object[] {new FormatterTestDbColumn("geOmetry"), "GEOMETRY"};
|
||||
yield return new object[] {new FormatterTestDbColumn("sySname"), "SYSNAME"};
|
||||
yield return new object[] {new FormatterTestDbColumn("tiMestamp"), "TIMESTAMP"};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(FormatColumnTypeData))]
|
||||
public void FormatColumnType(DbColumn input, string expectedOutput)
|
||||
{
|
||||
// If: I supply the input columns
|
||||
string output = ToSqlScript.FormatColumnType(input);
|
||||
|
||||
// Then: The output should match the expected output
|
||||
Assert.Equal(expectedOutput, output);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private class FormatterTestDbColumn : DbColumn
|
||||
{
|
||||
public FormatterTestDbColumn(string dataType, int? precision = null, int? scale = null)
|
||||
public FormatterTestDbColumn(string dataType, int? precision = null, int? scale = null, int? size = null)
|
||||
{
|
||||
DataTypeName = dataType;
|
||||
NumericPrecision = precision;
|
||||
NumericScale = scale;
|
||||
ColumnSize = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user