Adding decoding of multipart identifiers, default schema workaround (#295)

This change adds a couple things

_Multipart Identifier Decoding_
The ability to decode a multipart identifier (with or without escaping) has been added to the SqlScriptFormatter utility class. This code is utilized to split a table name provided to the edit/initialize request into schema and table name.

_Default Schema Workaround_
The code that retrieves the SMO metadata objects originally used the `[]` operator to access the objects. Due to a bug(?) in SMO, this results in problems when loading tables without a default schema (in our case if you're logged in as SA). Using the metadata object constructors gets around this issue, we are explicitly using them.

* Adding decoding of multipart identifiers
Adding code fix for default schema issue

* Adding some more localizable strings for errors when loading metadata

* Adding localization files... again?

* Changes as per pull request comments
This commit is contained in:
Benjamin Russell
2017-03-27 17:14:21 -07:00
committed by GitHub
parent 1909310a92
commit f7036f3f73
11 changed files with 235 additions and 17 deletions

View File

@@ -176,6 +176,83 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
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();
}
#region Private Helpers
private static string SimpleFormatter(object value)
@@ -260,6 +337,12 @@ namespace Microsoft.SqlTools.ServiceLayer.Utility
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>