Merge from Master

This commit is contained in:
Kevin Cunnane
2017-03-06 17:56:04 -08:00
14 changed files with 1593 additions and 1417 deletions

View File

@@ -12,16 +12,89 @@ using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
{
/// <summary>
/// This class caches server information for subsequent use
/// </summary>
internal static class CachedServerInfo
internal class CachedServerInfo
{
/// <summary>
/// Singleton service instance
/// </summary>
private static readonly Lazy<CachedServerInfo> instance
= new Lazy<CachedServerInfo>(() => new CachedServerInfo());
/// <summary>
/// Gets the singleton instance
/// </summary>
public static CachedServerInfo Instance
{
get
{
return instance.Value;
}
}
public enum CacheVariable {
IsSqlDw,
IsAzure
}
#region CacheKey implementation
internal class CacheKey : IEquatable<CacheKey>
{
private string dataSource;
private string dbName;
public CacheKey(SqlConnectionStringBuilder builder)
{
Validate.IsNotNull(nameof(builder), builder);
dataSource = builder.DataSource;
dbName = GetDatabaseName(builder);
}
internal static string GetDatabaseName(SqlConnectionStringBuilder builder)
{
string dbName = string.Empty;
if (!string.IsNullOrEmpty((builder.InitialCatalog)))
{
dbName = builder.InitialCatalog;
}
else if (!string.IsNullOrEmpty((builder.AttachDBFilename)))
{
dbName = builder.AttachDBFilename;
}
return dbName;
}
public override bool Equals(object obj)
{
if (obj == null) { return false; }
CacheKey keyObj = obj as CacheKey;
if (keyObj == null) { return false; }
else { return Equals(keyObj); }
}
public override int GetHashCode()
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
hash = (hash * 23) + (dataSource != null ? dataSource.GetHashCode() : 0);
hash = (hash * 23) + (dbName != null ? dbName.GetHashCode() : 0);
return hash;
}
}
public bool Equals(CacheKey other)
{
return string.Equals(dataSource, other.dataSource, StringComparison.OrdinalIgnoreCase)
&& string.Equals(dbName, other.dbName, StringComparison.OrdinalIgnoreCase);
}
}
#endregion
private struct CachedInfo
{
public bool IsAzure;
@@ -29,38 +102,43 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
public bool IsSqlDw;
}
private static ConcurrentDictionary<string, CachedInfo> _cache;
private static object _cacheLock;
private const int _maxCacheSize = 1024;
private const int _deleteBatchSize = 512;
private const int MinimalQueryTimeoutSecondsForAzure = 300;
static CachedServerInfo()
private ConcurrentDictionary<CacheKey, CachedInfo> _cache;
private object _cacheLock;
/// <summary>
/// Internal constructor for testing purposes. For all code use, please use the <see cref="CachedServerInfo.Instance"/>
/// default instance.
/// </summary>
internal CachedServerInfo()
{
_cache = new ConcurrentDictionary<string, CachedInfo>(StringComparer.OrdinalIgnoreCase);
_cache = new ConcurrentDictionary<CacheKey, CachedInfo>();
_cacheLock = new object();
}
public static int GetQueryTimeoutSeconds(IDbConnection connection)
public int GetQueryTimeoutSeconds(IDbConnection connection)
{
string dataSource = SafeGetDataSourceFromConnection(connection);
return GetQueryTimeoutSeconds(dataSource);
SqlConnectionStringBuilder connStringBuilder = SafeGetConnectionStringFromConnection(connection);
return GetQueryTimeoutSeconds(connStringBuilder);
}
public static int GetQueryTimeoutSeconds(string dataSource)
public int GetQueryTimeoutSeconds(SqlConnectionStringBuilder builder)
{
//keep existing behavior and return the default ambient settings
//if the provided data source is null or whitespace, or the original
//setting is already 0 which means no limit.
int originalValue = AmbientSettings.QueryTimeoutSeconds;
if (string.IsNullOrWhiteSpace(dataSource)
if (builder == null || string.IsNullOrWhiteSpace(builder.DataSource)
|| (originalValue == 0))
{
return originalValue;
}
CachedInfo info;
bool hasFound = _cache.TryGetValue(dataSource, out info);
bool hasFound = TryGetCacheValue(builder, out info);
if (hasFound && info.IsAzure
&& originalValue < MinimalQueryTimeoutSecondsForAzure)
@@ -73,55 +151,43 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
}
}
public static void AddOrUpdateIsAzure(IDbConnection connection, bool isAzure)
public void AddOrUpdateIsAzure(IDbConnection connection, bool isAzure)
{
AddOrUpdateCache(connection, isAzure, CacheVariable.IsAzure);
}
public static void AddOrUpdateIsSqlDw(IDbConnection connection, bool isSqlDw)
public void AddOrUpdateIsSqlDw(IDbConnection connection, bool isSqlDw)
{
AddOrUpdateCache(connection, isSqlDw, CacheVariable.IsSqlDw);
}
private static void AddOrUpdateCache(IDbConnection connection, bool newState, CacheVariable cacheVar)
private void AddOrUpdateCache(IDbConnection connection, bool newState, CacheVariable cacheVar)
{
Validate.IsNotNull(nameof(connection), connection);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
AddOrUpdateCache(builder.DataSource, newState, cacheVar);
AddOrUpdateCache(builder, newState, cacheVar);
}
internal static void AddOrUpdateCache(string dataSource, bool newState, CacheVariable cacheVar)
internal void AddOrUpdateCache(SqlConnectionStringBuilder builder, bool newState, CacheVariable cacheVar)
{
Validate.IsNotNullOrWhitespaceString(nameof(dataSource), dataSource);
Validate.IsNotNull(nameof(builder), builder);
Validate.IsNotNullOrWhitespaceString(nameof(builder) + ".DataSource", builder.DataSource);
CachedInfo info;
bool hasFound = _cache.TryGetValue(dataSource, out info);
bool hasFound = TryGetCacheValue(builder, out info);
if ((cacheVar == CacheVariable.IsSqlDw && hasFound && info.IsSqlDw == newState) ||
(cacheVar == CacheVariable.IsAzure && hasFound && info.IsAzure == newState))
{
// No change needed
return;
}
else
{
lock (_cacheLock)
{
if (! _cache.ContainsKey(dataSource))
{
//delete a batch of old elements when we try to add a new one and
//the capacity limitation is hit
if (_cache.Keys.Count > _maxCacheSize - 1)
{
var keysToDelete = _cache
.OrderBy(x => x.Value.LastUpdate)
.Take(_deleteBatchSize)
.Select(pair => pair.Key);
foreach (string key in keysToDelete)
{
_cache.TryRemove(key, out info);
}
}
}
// Clean older keys, update info, and add this back into the cache
CacheKey key = new CacheKey(builder);
CleanupCache(key);
if (cacheVar == CacheVariable.IsSqlDw)
{
@@ -132,24 +198,47 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
info.IsAzure = newState;
}
info.LastUpdate = DateTime.UtcNow;
_cache.AddOrUpdate(dataSource, info, (key, oldValue) => info);
_cache.AddOrUpdate(key, info, (k, oldValue) => info);
}
}
}
public static bool TryGetIsSqlDw(IDbConnection connection, out bool isSqlDw)
private void CleanupCache(CacheKey newKey)
{
if (!_cache.ContainsKey(newKey))
{
//delete a batch of old elements when we try to add a new one and
//the capacity limitation is hit
if (_cache.Keys.Count > _maxCacheSize - 1)
{
var keysToDelete = _cache
.OrderBy(x => x.Value.LastUpdate)
.Take(_deleteBatchSize)
.Select(pair => pair.Key);
foreach (CacheKey key in keysToDelete)
{
CachedInfo info;
_cache.TryRemove(key, out info);
}
}
}
}
public bool TryGetIsSqlDw(IDbConnection connection, out bool isSqlDw)
{
Validate.IsNotNull(nameof(connection), connection);
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
return TryGetIsSqlDw(builder.DataSource, out isSqlDw);
return TryGetIsSqlDw(builder, out isSqlDw);
}
public static bool TryGetIsSqlDw(string dataSource, out bool isSqlDw)
public bool TryGetIsSqlDw(SqlConnectionStringBuilder builder, out bool isSqlDw)
{
Validate.IsNotNullOrWhitespaceString(nameof(dataSource), dataSource);
Validate.IsNotNull(nameof(builder), builder);
Validate.IsNotNullOrWhitespaceString(nameof(builder) + ".DataSource", builder.DataSource);
CachedInfo info;
bool hasFound = _cache.TryGetValue(dataSource, out info);
bool hasFound = TryGetCacheValue(builder, out info);
if(hasFound)
{
@@ -161,7 +250,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
return false;
}
private static string SafeGetDataSourceFromConnection(IDbConnection connection)
private static SqlConnectionStringBuilder SafeGetConnectionStringFromConnection(IDbConnection connection)
{
if (connection == null)
{
@@ -171,7 +260,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
try
{
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connection.ConnectionString);
return builder.DataSource;
return builder;
}
catch
{
@@ -179,5 +268,11 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
return null;
}
}
private bool TryGetCacheValue(SqlConnectionStringBuilder builder, out CachedInfo value)
{
CacheKey key = new CacheKey(builder);
return _cache.TryGetValue(key, out value);
}
}
}

View File

@@ -407,7 +407,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
public static void SetCommandTimeout(IDbCommand cmd)
{
Validate.IsNotNull(nameof(cmd), cmd);
cmd.CommandTimeout = CachedServerInfo.GetQueryTimeoutSeconds(cmd.Connection);
cmd.CommandTimeout = CachedServerInfo.Instance.GetQueryTimeoutSeconds(cmd.Connection);
}
@@ -773,7 +773,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
try
{
CachedServerInfo.AddOrUpdateIsAzure(connection, serverInfo.IsCloud);
CachedServerInfo.Instance.AddOrUpdateIsAzure(connection, serverInfo.IsCloud);
}
catch (Exception ex)
{

View File

@@ -109,10 +109,10 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
//This is assuming that it is highly unlikely for a connection to change between instances.
//Hence any subsequent calls to this method will just return the cached value and not
//verify again if this is a SQL DW database connection or not.
if (!CachedServerInfo.TryGetIsSqlDw(conn, out _isSqlDwDatabase))
if (!CachedServerInfo.Instance.TryGetIsSqlDw(conn, out _isSqlDwDatabase))
{
_isSqlDwDatabase = ReliableConnectionHelper.IsSqlDwDatabase(conn);
CachedServerInfo.AddOrUpdateIsSqlDw(conn, _isSqlDwDatabase);;
CachedServerInfo.Instance.AddOrUpdateIsSqlDw(conn, _isSqlDwDatabase);;
}
return _isSqlDwDatabase;
@@ -137,7 +137,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
{
cmd.CommandText = string.Format(CultureInfo.InvariantCulture, setLockTimeout, AmbientSettings.LockTimeoutMilliSeconds);
cmd.CommandType = CommandType.Text;
cmd.CommandTimeout = CachedServerInfo.GetQueryTimeoutSeconds(conn);
cmd.CommandTimeout = CachedServerInfo.Instance.GetQueryTimeoutSeconds(conn);
cmd.ExecuteNonQuery();
}
}
@@ -157,7 +157,7 @@ namespace Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection
// Configure the connection with proper ANSI settings and lock timeout
using (IDbCommand cmd = conn.CreateCommand())
{
cmd.CommandTimeout = CachedServerInfo.GetQueryTimeoutSeconds(conn);
cmd.CommandTimeout = CachedServerInfo.Instance.GetQueryTimeoutSeconds(conn);
if (!isSqlDw)
{
cmd.CommandText = @"SET ANSI_NULLS, ANSI_PADDING, ANSI_WARNINGS, ARITHABORT, CONCAT_NULL_YIELDS_NULL, QUOTED_IDENTIFIER ON;

View File

@@ -1,199 +1,199 @@
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
private void Initialize()
{
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
AddSupportedType(DeclarationType.UserDefinedDataType, GetUserDefinedDataTypeScripts, "Type", "user-defined data type");
AddSupportedType(DeclarationType.UserDefinedTableType, GetUserDefinedTableTypeScripts, "Type", "user-defined table type");
AddSupportedType(DeclarationType.Synonym, GetSynonymScripts, "Synonym", "");
AddSupportedType(DeclarationType.ScalarValuedFunction, GetScalarValuedFunctionScripts, "Function", "scalar-valued function");
AddSupportedType(DeclarationType.TableValuedFunction, GetTableValuedFunctionScripts, "Function", "table-valued function");
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
private void Initialize()
{
AddSupportedType(DeclarationType.Table, GetTableScripts, "Table", "table");
AddSupportedType(DeclarationType.View, GetViewScripts, "View", "view");
AddSupportedType(DeclarationType.StoredProcedure, GetStoredProcedureScripts, "Procedure", "stored procedure");
AddSupportedType(DeclarationType.UserDefinedDataType, GetUserDefinedDataTypeScripts, "Type", "user-defined data type");
AddSupportedType(DeclarationType.UserDefinedTableType, GetUserDefinedTableTypeScripts, "Type", "user-defined table type");
AddSupportedType(DeclarationType.Synonym, GetSynonymScripts, "Synonym", "");
AddSupportedType(DeclarationType.ScalarValuedFunction, GetScalarValuedFunctionScripts, "Function", "scalar-valued function");
AddSupportedType(DeclarationType.TableValuedFunction, GetTableValuedFunctionScripts, "Function", "table-valued function");
}
/// <summary>
/// Script a Table using SMO
/// </summary>
/// <param name="objectName">Table name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableScripts(string objectName, string schemaName)
{
try
{
Table smoObject = string.IsNullOrEmpty(schemaName) ? new Table(this.Database, objectName) : new Table(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a Table using SMO
/// </summary>
/// <param name="objectName">Table name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableScripts(string objectName, string schemaName)
{
try
{
Table smoObject = string.IsNullOrEmpty(schemaName) ? new Table(this.Database, objectName) : new Table(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a View using SMO
/// </summary>
/// <param name="objectName">View name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetViewScripts(string objectName, string schemaName)
{
try
{
View smoObject = string.IsNullOrEmpty(schemaName) ? new View(this.Database, objectName) : new View(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a View using SMO
/// </summary>
/// <param name="objectName">View name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetViewScripts(string objectName, string schemaName)
{
try
{
View smoObject = string.IsNullOrEmpty(schemaName) ? new View(this.Database, objectName) : new View(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetViewScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a StoredProcedure using SMO
/// </summary>
/// <param name="objectName">StoredProcedure name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetStoredProcedureScripts(string objectName, string schemaName)
{
try
{
StoredProcedure smoObject = string.IsNullOrEmpty(schemaName) ? new StoredProcedure(this.Database, objectName) : new StoredProcedure(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a StoredProcedure using SMO
/// </summary>
/// <param name="objectName">StoredProcedure name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetStoredProcedureScripts(string objectName, string schemaName)
{
try
{
StoredProcedure smoObject = string.IsNullOrEmpty(schemaName) ? new StoredProcedure(this.Database, objectName) : new StoredProcedure(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetStoredProcedureScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a UserDefinedDataType using SMO
/// </summary>
/// <param name="objectName">UserDefinedDataType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedDataTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedDataType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedDataType(this.Database, objectName) : new UserDefinedDataType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedDataTypeScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a UserDefinedDataType using SMO
/// </summary>
/// <param name="objectName">UserDefinedDataType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedDataTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedDataType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedDataType(this.Database, objectName) : new UserDefinedDataType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedDataTypeScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a UserDefinedTableType using SMO
/// </summary>
/// <param name="objectName">UserDefinedTableType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedTableTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedTableType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedTableType(this.Database, objectName) : new UserDefinedTableType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedTableTypeScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a UserDefinedTableType using SMO
/// </summary>
/// <param name="objectName">UserDefinedTableType name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetUserDefinedTableTypeScripts(string objectName, string schemaName)
{
try
{
UserDefinedTableType smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedTableType(this.Database, objectName) : new UserDefinedTableType(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetUserDefinedTableTypeScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a Synonym using SMO
/// </summary>
/// <param name="objectName">Synonym name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetSynonymScripts(string objectName, string schemaName)
{
try
{
Synonym smoObject = string.IsNullOrEmpty(schemaName) ? new Synonym(this.Database, objectName) : new Synonym(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSynonymScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a Synonym using SMO
/// </summary>
/// <param name="objectName">Synonym name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetSynonymScripts(string objectName, string schemaName)
{
try
{
Synonym smoObject = string.IsNullOrEmpty(schemaName) ? new Synonym(this.Database, objectName) : new Synonym(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetSynonymScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a ScalarValuedFunction using SMO
/// </summary>
/// <param name="objectName">ScalarValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetScalarValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetScalarValuedFunctionScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a ScalarValuedFunction using SMO
/// </summary>
/// <param name="objectName">ScalarValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetScalarValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetScalarValuedFunctionScripts : " + ex.Message);
return null;
}
}
/// <summary>
/// Script a TableValuedFunction using SMO
/// </summary>
/// <param name="objectName">TableValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
return null;
}
/// <summary>
/// Script a TableValuedFunction using SMO
/// </summary>
/// <param name="objectName">TableValuedFunction name</param>
/// <param name="schemaName">Schema name</param>
/// <returns>String collection of scripts</returns>
internal StringCollection GetTableValuedFunctionScripts(string objectName, string schemaName)
{
try
{
UserDefinedFunction smoObject = string.IsNullOrEmpty(schemaName) ? new UserDefinedFunction(this.Database, objectName) : new UserDefinedFunction(this.Database, objectName, schemaName);
smoObject.Refresh();
return smoObject.Script();
}
catch (Exception ex)
{
Logger.Write(LogLevel.Error,"Exception at PeekDefinition GetTableValuedFunctionScripts : " + ex.Message);
return null;
}
}
}
}
}
}

View File

@@ -1,144 +1,144 @@
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.ServiceLayer.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
<#
///
/// Generate Initialize method
///
var indent = " ";
var directory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFile = Path.Combine(directory, "PeekDefinitionSupportedTypes.xml");
var supportedTypes = GetSupportedTypes(xmlFile);
if (supportedTypes != null && supportedTypes.Count > 0)
{
WriteLine("private void Initialize()");
PushIndent(indent);
PushIndent(indent);
WriteLine("{");
PushIndent(indent);
foreach(var typeProperty in supportedTypes)
{
string functionCall = string.Format("AddSupportedType(DeclarationType.{0}, Get{0}Scripts, \"{1}\", \"{2}\");", typeProperty["Name"], typeProperty["CreateSyntax"], typeProperty["QuickInfoType"]);
WriteLine(functionCall);
}
PopIndent();
WriteLine("}\n");
///
/// Generate scriptGetters for each type
///
foreach(var typeProperty in supportedTypes)
{
string statement;
// Write comments
WriteLine("/// <summary>");
WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"]));
WriteLine("/// </summary>");
WriteLine(string.Format("/// <param name=\"objectName\">{0} name</param>", typeProperty["Name"]));
WriteLine(string.Format("/// <param name=\"schemaName\">Schema name</param>"));
WriteLine("/// <returns>String collection of scripts</returns>");
WriteLine(string.Format("internal StringCollection Get{0}Scripts(string objectName, string schemaName)", typeProperty["Name"]));
WriteLine("{");
PushIndent(indent);
// Write try block to retrieve object and return script
WriteLine("try");
WriteLine("{");
if(typeProperty["SupportsSchemaQuery"].IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0)
{
statement = string.Format("{0} smoObject = string.IsNullOrEmpty(schemaName) ? new {0}(this.Database, objectName) : new {0}(this.Database, objectName, schemaName);", typeProperty["AccessClass"]);
}
else
{
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
}
PushIndent(indent);
WriteLine(statement);
WriteLine("smoObject.Refresh();");
WriteLine("return smoObject.Script();");
PopIndent();
WriteLine("}");
// Write catch block to catch and log exceptions
WriteLine("catch (Exception ex)");
WriteLine("{");
PushIndent(indent);
statement = string.Format("LogLevel.Error,\"Exception at PeekDefinition Get{0}Scripts : \" + ex.Message", typeProperty["Name"]);
WriteLine("Logger.Write(" + statement + ");");
WriteLine("return null;");
PopIndent();
WriteLine("}");
PopIndent();
WriteLine("}\n");
}
}
PopIndent();
PopIndent();
#>
}
}
<#+
///
/// Get the supported types from the xml file
///
public static List<Dictionary<string, string>> GetSupportedTypes(string xmlFile)
{
List<Dictionary<string, string>> typeList = null;
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type");
if (supportedTypes != null)
{
typeList = new List<Dictionary<string, string>>();
foreach (var type in supportedTypes)
{
XmlElement node = type as XmlElement;
if (node != null)
{
string typeName = (node["Name"] != null) ? node["Name"].InnerText : null;
string createSyntax = (node["CreateSyntax"] != null) ? node["CreateSyntax"].InnerText : null;
string accessClass = (node["AccessClass"] != null) ? node["AccessClass"].InnerText : null;
string supportsSchemaQuery = (node["SupportsSchemaQuery"] != null) ? node["SupportsSchemaQuery"].InnerText : null;
string quickInfoType = (node["QuickInfoType"] != null) ? node["QuickInfoType"].InnerText : null;
if (typeName != null && createSyntax != null && accessClass != null && supportsSchemaQuery!= null)
{
Dictionary<string, string> typeProperties = new Dictionary<string, string>();
typeProperties.Add("Name", typeName);
typeProperties.Add("CreateSyntax", createSyntax);
typeProperties.Add("AccessClass", accessClass);
typeProperties.Add("SupportsSchemaQuery", supportsSchemaQuery);
typeProperties.Add("QuickInfoType", quickInfoType);
typeList.Add(typeProperties);
}
}
}
}
return typeList;
}
<#@ template debug="false" hostspecific="true" language="C#" #>
<#@ output extension=".cs" #>
<#@ assembly name="System.Xml.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Globalization" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Xml" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.IO" #>
//
// 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.IO;
using System.Collections.Generic;
using System.Collections.Specialized;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.SqlParser.Intellisense;
using Microsoft.SqlTools.Utility;
namespace Microsoft.SqlTools.ServiceLayer.LanguageServices
{
internal partial class PeekDefinition
{
<#
///
/// Generate Initialize method
///
var indent = " ";
var directory = Path.GetDirectoryName(Host.TemplateFile);
string xmlFile = Path.Combine(directory, "PeekDefinitionSupportedTypes.xml");
var supportedTypes = GetSupportedTypes(xmlFile);
if (supportedTypes != null && supportedTypes.Count > 0)
{
WriteLine("private void Initialize()");
PushIndent(indent);
PushIndent(indent);
WriteLine("{");
PushIndent(indent);
foreach(var typeProperty in supportedTypes)
{
string functionCall = string.Format("AddSupportedType(DeclarationType.{0}, Get{0}Scripts, \"{1}\", \"{2}\");", typeProperty["Name"], typeProperty["CreateSyntax"], typeProperty["QuickInfoType"]);
WriteLine(functionCall);
}
PopIndent();
WriteLine("}\n");
///
/// Generate scriptGetters for each type
///
foreach(var typeProperty in supportedTypes)
{
string statement;
// Write comments
WriteLine("/// <summary>");
WriteLine(string.Format("/// Script a {0} using SMO", typeProperty["Name"]));
WriteLine("/// </summary>");
WriteLine(string.Format("/// <param name=\"objectName\">{0} name</param>", typeProperty["Name"]));
WriteLine(string.Format("/// <param name=\"schemaName\">Schema name</param>"));
WriteLine("/// <returns>String collection of scripts</returns>");
WriteLine(string.Format("internal StringCollection Get{0}Scripts(string objectName, string schemaName)", typeProperty["Name"]));
WriteLine("{");
PushIndent(indent);
// Write try block to retrieve object and return script
WriteLine("try");
WriteLine("{");
if(typeProperty["SupportsSchemaQuery"].IndexOf("true", StringComparison.OrdinalIgnoreCase) >= 0)
{
statement = string.Format("{0} smoObject = string.IsNullOrEmpty(schemaName) ? new {0}(this.Database, objectName) : new {0}(this.Database, objectName, schemaName);", typeProperty["AccessClass"]);
}
else
{
statement = string.Format("{0} smoObject = new {0}(this.Database, objectName);", typeProperty["Name"]);
}
PushIndent(indent);
WriteLine(statement);
WriteLine("smoObject.Refresh();");
WriteLine("return smoObject.Script();");
PopIndent();
WriteLine("}");
// Write catch block to catch and log exceptions
WriteLine("catch (Exception ex)");
WriteLine("{");
PushIndent(indent);
statement = string.Format("LogLevel.Error,\"Exception at PeekDefinition Get{0}Scripts : \" + ex.Message", typeProperty["Name"]);
WriteLine("Logger.Write(" + statement + ");");
WriteLine("return null;");
PopIndent();
WriteLine("}");
PopIndent();
WriteLine("}\n");
}
}
PopIndent();
PopIndent();
#>
}
}
<#+
///
/// Get the supported types from the xml file
///
public static List<Dictionary<string, string>> GetSupportedTypes(string xmlFile)
{
List<Dictionary<string, string>> typeList = null;
XmlDocument doc = new XmlDocument();
doc.Load(xmlFile);
XmlNodeList supportedTypes = doc.SelectNodes("/SupportedTypes/Type");
if (supportedTypes != null)
{
typeList = new List<Dictionary<string, string>>();
foreach (var type in supportedTypes)
{
XmlElement node = type as XmlElement;
if (node != null)
{
string typeName = (node["Name"] != null) ? node["Name"].InnerText : null;
string createSyntax = (node["CreateSyntax"] != null) ? node["CreateSyntax"].InnerText : null;
string accessClass = (node["AccessClass"] != null) ? node["AccessClass"].InnerText : null;
string supportsSchemaQuery = (node["SupportsSchemaQuery"] != null) ? node["SupportsSchemaQuery"].InnerText : null;
string quickInfoType = (node["QuickInfoType"] != null) ? node["QuickInfoType"].InnerText : null;
if (typeName != null && createSyntax != null && accessClass != null && supportsSchemaQuery!= null)
{
Dictionary<string, string> typeProperties = new Dictionary<string, string>();
typeProperties.Add("Name", typeName);
typeProperties.Add("CreateSyntax", createSyntax);
typeProperties.Add("AccessClass", accessClass);
typeProperties.Add("SupportsSchemaQuery", supportsSchemaQuery);
typeProperties.Add("QuickInfoType", quickInfoType);
typeList.Add(typeProperties);
}
}
}
}
return typeList;
}
#>

View File

@@ -1,123 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="TestLocalizationConstant" xml:space="preserve">
<value>ES_LOCALIZATION</value>
</data>
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="TestLocalizationConstant" xml:space="preserve">
<value>ES_LOCALIZATION</value>
</data>
</root>

File diff suppressed because it is too large Load Diff