diff --git a/AzureDataStudioExtension/CHANGELOG.md b/AzureDataStudioExtension/CHANGELOG.md index 375c94e9..92262a10 100644 --- a/AzureDataStudioExtension/CHANGELOG.md +++ b/AzureDataStudioExtension/CHANGELOG.md @@ -1,5 +1,27 @@ # Change Log +## [v9.5.0](https://github.com/MarkMpn/Sql4Cds/releases/tag/v9.4.1) - 2024-12-07 + +Updated to .NET 8 + +Bulk DML improvements +* Automatically adjust batch size to keep requests within timeout limits +* Automatically adjust thread count to avoid hitting service protection limits +* Provide better feedback when queries pause due to service protection limits +* Automatically retry requests that have failed due to a transient error +* Added DML support for `solutioncomponent` table + +Metadata improvements +* Expose optionset values via `metadata.globaloptionsetvalue` and `metadata.optionsetvalue` tables +* Reduced amount of metadata required to execute queries + +Bug fixes +* Use correct scale when displaying numeric results +* Fixed "Must declare the scalar variable @Cond" error when using nested loop for single-record joins +* Do not trust `RetrieveTotalRecordCount` for certain metadata-related entities that give incorrect results +* Avoid errors when using cross-table column comparisons and nested link entities +* Handle nested primary functions + ## [v9.4.1](https://github.com/MarkMpn/Sql4Cds/releases/tag/v9.4.1) - 2024-11-10 Fixed Intellisense with trailing comments diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.csproj b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.csproj index fb51d2ca..5b80dd55 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.csproj +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.csproj @@ -1,7 +1,7 @@  - net6.0;net462 + net8.0;net462 MarkMpn.Sql4Cds.Engine MarkMpn.Sql4Cds.Engine Copyright © 2020 - 2024 Mark Carrington @@ -30,7 +30,7 @@ - + diff --git a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec index 038c56d9..9a1ffa19 100644 --- a/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec +++ b/MarkMpn.Sql4Cds.Engine/MarkMpn.Sql4Cds.Engine.nuspec @@ -11,9 +11,24 @@ https://markcarrington.dev/sql4cds-icon/ Convert SQL queries to FetchXml and execute them against Dataverse / D365 Convert SQL queries to FetchXml and execute them against Dataverse / D365 - Include join alias in output column aliases when converting from Fetch XML to SQL -Improved SQL to Fetch XML conversion of datetime filters -Fixed use of case-insensitive table names in INSERT statements + Updated to .NET 8 + +Bulk DML improvements +* Automatically adjust batch size to keep requests within timeout limits +* Automatically adjust thread count to avoid hitting service protection limits +* Provide better feedback when queries pause due to service protection limits +* Automatically retry requests that have failed due to a transient error +* Added DML support for `solutioncomponent` table + +Metadata improvements +* Expose optionset values via `metadata.globaloptionsetvalue` and `metadata.optionsetvalue` tables +* Reduced amount of metadata required to execute queries + +Bug fixes +* Fixed "Must declare the scalar variable @Cond" error when using nested loop for single-record joins +* Do not trust `RetrieveTotalRecordCount` for certain metadata-related entities that give incorrect results +* Avoid errors when using cross-table column comparisons and nested link entities +* Handle nested primary functions Copyright © 2020 Mark Carrington en-GB @@ -27,8 +42,8 @@ Fixed use of case-insensitive table names in INSERT statements - - + + @@ -39,7 +54,7 @@ Fixed use of case-insensitive table names in INSERT statements - + \ No newline at end of file diff --git a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs index 830d58ea..6dfa32e7 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/Autocomplete/Autocomplete.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Reflection; using System.Text; -using Data8.PowerPlatform.Dataverse.Client.Wsdl; using MarkMpn.Sql4Cds.Engine; using Microsoft.Crm.Sdk.Messages; using Microsoft.VisualStudio.LanguageServer.Protocol; @@ -314,7 +313,7 @@ public IEnumerable GetSuggestions(string text, int pos) var availableParameters = message.InputParameters .Concat(message.OutputParameters) .OrderBy(p => p.Name) - .Select(p => new SprocParameterAutocompleteItem(message, p, currentLength)); + .Select(p => new SprocParameterAutocompleteItem(message, p, instance, currentLength)); return FilterList(availableParameters, currentWord); } @@ -540,7 +539,7 @@ public IEnumerable GetSuggestions(string text, int pos) message.IsValidAsTableValuedFunction()) { if (!Guid.TryParse(table.Key, out _)) - items.Add(new TVFAutocompleteItem(message, table.Key, currentLength)); + items.Add(new TVFAutocompleteItem(message, instance, table.Key, currentLength)); attributes.AddRange(GetMessageOutputAttributes(message, instance)); } @@ -786,7 +785,7 @@ private IEnumerable AutocompleteTableName(string currentWor // Show TVF list if (fromClause && ds.Metadata != null) - list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsTableValuedFunction()).Select(x => new TVFAutocompleteItem(x, _columnOrdering, currentLength))); + list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsTableValuedFunction()).Select(x => new TVFAutocompleteItem(x, _columnOrdering, ds, currentLength))); } } else if (TryParseTableName(currentWord, out var instanceName, out var schemaName, out var tableName, out var parts, out var lastPartLength)) @@ -856,7 +855,7 @@ private IEnumerable AutocompleteTableName(string currentWor if (fromClause) { messages = messages.Where(e => e.IsValidAsTableValuedFunction() && e.Name.StartsWith(lastPart, StringComparison.OrdinalIgnoreCase)); - list.AddRange(messages.Select(e => new TVFAutocompleteItem(e, _columnOrdering, lastPartLength))); + list.AddRange(messages.Select(e => new TVFAutocompleteItem(e, _columnOrdering, instance, lastPartLength))); } } } @@ -877,7 +876,7 @@ private IEnumerable AutocompleteSprocName(string currentWor list.AddRange(_dataSources.Values.Select(x => new InstanceAutocompleteItem(x, currentLength))); if (_dataSources.TryGetValue(_primaryDataSource, out var ds) && ds.MessageCache != null) - list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(x => new SprocAutocompleteItem(x, _columnOrdering, currentLength))); + list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(x => new SprocAutocompleteItem(x, _columnOrdering, ds, currentLength))); } else if (TryParseTableName(currentWord, out var instanceName, out var schemaName, out var tableName, out var parts, out var lastPartLength)) { @@ -905,7 +904,7 @@ private IEnumerable AutocompleteSprocName(string currentWor // Could be a sproc name if (schemaName.Equals("dbo", StringComparison.OrdinalIgnoreCase) && instance?.MessageCache != null) - list.AddRange(instance.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(e => new SprocAutocompleteItem(e, _columnOrdering, lastPartLength))); + list.AddRange(instance.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(e => new SprocAutocompleteItem(e, _columnOrdering, instance, lastPartLength))); } list.Sort(); @@ -1552,16 +1551,19 @@ class TVFAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly ColumnOrdering _columnOrdering; + private readonly DataSource _dataSource; - public TVFAutocompleteItem(Message message, ColumnOrdering columnOrdering, int replaceLength) : base(message.Name, replaceLength, CompletionItemKind.Function) + public TVFAutocompleteItem(Message message, ColumnOrdering columnOrdering, DataSource dataSource, int replaceLength) : base(message.Name, replaceLength, CompletionItemKind.Function) { _message = message; _columnOrdering = columnOrdering; + _dataSource = dataSource; } - public TVFAutocompleteItem(Message message, string alias, int replaceLength) : base(alias, replaceLength, CompletionItemKind.Function) + public TVFAutocompleteItem(Message message, DataSource dataSource, string alias, int replaceLength) : base(alias, replaceLength, CompletionItemKind.Function) { _message = message; + _dataSource = dataSource; } public override string ToolTipTitle @@ -1582,7 +1584,7 @@ public override string ToolTipText else parameters = parameters.OrderBy(p => p.Position); - return _message.Name + "(" + String.Join(", ", parameters.Select(p => p.Name + " " + p.GetSqlDataType(null).ToSql())) + ")"; + return _message.Name + "(" + String.Join(", ", parameters.Select(p => p.Name + " " + p.GetSqlDataType(_dataSource).ToSql())) + ")"; } set => base.ToolTipText = value; } @@ -1597,11 +1599,13 @@ class SprocAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly ColumnOrdering _columnOrdering; + private readonly DataSource _dataSource; - public SprocAutocompleteItem(Message message, ColumnOrdering columnOrdering, int replaceLength) : base(message.Name, replaceLength, CompletionItemKind.Method) + public SprocAutocompleteItem(Message message, ColumnOrdering columnOrdering, DataSource dataSource, int replaceLength) : base(message.Name, replaceLength, CompletionItemKind.Method) { _message = message; _columnOrdering = columnOrdering; + _dataSource = dataSource; } public override string ToolTipTitle @@ -1622,7 +1626,7 @@ public override string ToolTipText else parameters = parameters.OrderBy(p => p.Position); - return _message.Name + " " + String.Join(", ", parameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + " OUTPUT]")))); + return _message.Name + " " + String.Join(", ", parameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + " OUTPUT]")))); } set => base.ToolTipText = value; } @@ -1632,22 +1636,24 @@ class SprocParameterAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly MessageParameter _parameter; + private readonly DataSource _dataSource; - public SprocParameterAutocompleteItem(Message message, MessageParameter parameter, int replaceLength) : base("@" + parameter.Name, replaceLength, CompletionItemKind.Variable) + public SprocParameterAutocompleteItem(Message message, MessageParameter parameter, DataSource dataSource, int replaceLength) : base("@" + parameter.Name, replaceLength, CompletionItemKind.Variable) { _message = message; _parameter = parameter; + _dataSource = dataSource; } public override string ToolTipTitle { - get => _parameter.Name + (_message.OutputParameters.Contains(_parameter) ? " output" : " input") + " parameter (" + _parameter.GetSqlDataType(null).ToSql() + ")"; + get => _parameter.Name + (_message.OutputParameters.Contains(_parameter) ? " output" : " input") + " parameter (" + _parameter.GetSqlDataType(_dataSource).ToSql() + ")"; set => base.ToolTipTitle = value; } public override string ToolTipText { - get => _message.Name + " " + string.Join(", ", _message.InputParameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : (_message.InputParameters.Count == 0 ? "" : ",") + " " + string.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + " OUTPUT]"))); + get => _message.Name + " " + string.Join(", ", _message.InputParameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : (_message.InputParameters.Count == 0 ? "" : ",") + " " + string.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + " OUTPUT]"))); set => base.ToolTipText = value; } } diff --git a/MarkMpn.Sql4Cds.LanguageServer/MarkMpn.Sql4Cds.LanguageServer.csproj b/MarkMpn.Sql4Cds.LanguageServer/MarkMpn.Sql4Cds.LanguageServer.csproj index b434010a..f4ecf78e 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/MarkMpn.Sql4Cds.LanguageServer.csproj +++ b/MarkMpn.Sql4Cds.LanguageServer/MarkMpn.Sql4Cds.LanguageServer.csproj @@ -2,17 +2,17 @@ Exe - net7.0 + net8.0 Copyright © 2022 - 2024 Mark Carrington - - - + + + - - + + diff --git a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs index 5cfe7993..24bd5e58 100644 --- a/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs +++ b/MarkMpn.Sql4Cds.LanguageServer/QueryExecution/QueryExecutionHandler.cs @@ -349,7 +349,7 @@ private async Task ExecuteAsync(Connection.Session session, ExecuteRequestParams var schemaTable = reader.GetSchemaTable(); for (var i = 0; i < reader.FieldCount; i++) - resultSet.ColumnInfo[i] = new DbColumnWrapper((string)schemaTable.Rows[i]["ColumnName"], (string)schemaTable.Rows[i]["DataTypeName"], (short?)schemaTable.Rows[i]["NumericScale"]); + resultSet.ColumnInfo[i] = new DbColumnWrapper(schemaTable.Rows[i]["ColumnName"] as string, (string)schemaTable.Rows[i]["DataTypeName"], (short?)schemaTable.Rows[i]["NumericScale"]); resultSetInProgress = resultSet; resultSets.Add(resultSet); diff --git a/MarkMpn.Sql4Cds.XTB/Autocomplete.cs b/MarkMpn.Sql4Cds.XTB/Autocomplete.cs index 930eb269..63b8ba4e 100644 --- a/MarkMpn.Sql4Cds.XTB/Autocomplete.cs +++ b/MarkMpn.Sql4Cds.XTB/Autocomplete.cs @@ -313,7 +313,7 @@ public IEnumerable GetSuggestions(string text, int pos) var availableParameters = message.InputParameters .Concat(message.OutputParameters) .OrderBy(p => p.Name) - .Select(p => new SprocParameterAutocompleteItem(message, p, currentLength)); + .Select(p => new SprocParameterAutocompleteItem(message, p, instance, currentLength)); return FilterList(availableParameters, currentWord); } @@ -539,7 +539,7 @@ public IEnumerable GetSuggestions(string text, int pos) message.IsValidAsTableValuedFunction()) { if (!Guid.TryParse(table.Key, out _)) - items.Add(new TVFAutocompleteItem(message, table.Key, currentLength)); + items.Add(new TVFAutocompleteItem(message, instance, table.Key, currentLength)); attributes.AddRange(GetMessageOutputAttributes(message, instance)); } @@ -785,7 +785,7 @@ private IEnumerable AutocompleteTableName(string currentWor // Show TVF list if (fromClause && ds.MessageCache != null) - list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsTableValuedFunction()).Select(x => new TVFAutocompleteItem(x, _columnOrdering, currentLength))); + list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsTableValuedFunction()).Select(x => new TVFAutocompleteItem(x, _columnOrdering, ds, currentLength))); } } else if (TryParseTableName(currentWord, out var instanceName, out var schemaName, out var tableName, out var parts, out var lastPartLength)) @@ -855,7 +855,7 @@ private IEnumerable AutocompleteTableName(string currentWor if (fromClause) { messages = messages.Where(e => e.IsValidAsTableValuedFunction() && e.Name.StartsWith(lastPart, StringComparison.OrdinalIgnoreCase)); - list.AddRange(messages.Select(e => new TVFAutocompleteItem(e, _columnOrdering, lastPartLength))); + list.AddRange(messages.Select(e => new TVFAutocompleteItem(e, _columnOrdering, instance, lastPartLength))); } } } @@ -876,7 +876,7 @@ private IEnumerable AutocompleteSprocName(string currentWor list.AddRange(_dataSources.Values.Select(x => new InstanceAutocompleteItem(x, currentLength))); if (_dataSources.TryGetValue(_primaryDataSource, out var ds) && ds.MessageCache != null) - list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(x => new SprocAutocompleteItem(x, _columnOrdering, currentLength))); + list.AddRange(ds.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(x => new SprocAutocompleteItem(x, _columnOrdering, ds, currentLength))); } else if (TryParseTableName(currentWord, out var instanceName, out var schemaName, out var tableName, out var parts, out var lastPartLength)) { @@ -904,7 +904,7 @@ private IEnumerable AutocompleteSprocName(string currentWor // Could be a sproc name if (schemaName.Equals("dbo", StringComparison.OrdinalIgnoreCase) && instance?.MessageCache != null) - list.AddRange(instance.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(e => new SprocAutocompleteItem(e, _columnOrdering, lastPartLength))); + list.AddRange(instance.MessageCache.GetAllMessages().Where(x => x.IsValidAsStoredProcedure()).Select(e => new SprocAutocompleteItem(e, _columnOrdering, instance, lastPartLength))); } list.Sort(); @@ -1534,16 +1534,19 @@ class TVFAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly ColumnOrdering _columnOrdering; + private readonly DataSource _dataSource; - public TVFAutocompleteItem(Message message, ColumnOrdering columnOrdering, int replaceLength) : base(message.Name, replaceLength, 25) + public TVFAutocompleteItem(Message message, ColumnOrdering columnOrdering, DataSource dataSource, int replaceLength) : base(message.Name, replaceLength, 25) { _message = message; _columnOrdering = columnOrdering; + _dataSource = dataSource; } - public TVFAutocompleteItem(Message message, string alias, int replaceLength) : base(alias, replaceLength, 25) + public TVFAutocompleteItem(Message message, DataSource dataSource, string alias, int replaceLength) : base(alias, replaceLength, 25) { _message = message; + _dataSource = dataSource; } public override string ToolTipTitle @@ -1564,7 +1567,7 @@ public override string ToolTipText else parameters = parameters.OrderBy(p => p.Position); - return _message.Name + "(" + String.Join(", ", parameters.Select(p => p.Name + " " + p.GetSqlDataType(null).ToSql())) + ")"; + return _message.Name + "(" + String.Join(", ", parameters.Select(p => p.Name + " " + p.GetSqlDataType(_dataSource).ToSql())) + ")"; } set => base.ToolTipText = value; } @@ -1579,11 +1582,13 @@ class SprocAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly ColumnOrdering _columnOrdering; + private readonly DataSource _dataSource; - public SprocAutocompleteItem(Message message, ColumnOrdering columnOrdering, int replaceLength) : base(message.Name, replaceLength, 26) + public SprocAutocompleteItem(Message message, ColumnOrdering columnOrdering, DataSource dataSource, int replaceLength) : base(message.Name, replaceLength, 26) { _message = message; _columnOrdering = columnOrdering; + _dataSource = dataSource; } public override string ToolTipTitle @@ -1604,7 +1609,7 @@ public override string ToolTipText else parameters = parameters.OrderBy(p => p.Position); - return _message.Name + " " + String.Join(", ", parameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + " OUTPUT]")))); + return _message.Name + " " + String.Join(", ", parameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + " OUTPUT]")))); } set => base.ToolTipText = value; } @@ -1614,22 +1619,24 @@ class SprocParameterAutocompleteItem : SqlAutocompleteItem { private readonly Message _message; private readonly MessageParameter _parameter; + private readonly DataSource _dataSource; - public SprocParameterAutocompleteItem(Message message, MessageParameter parameter, int replaceLength) : base("@" + parameter.Name, replaceLength, 26) + public SprocParameterAutocompleteItem(Message message, MessageParameter parameter, DataSource dataSource, int replaceLength) : base("@" + parameter.Name, replaceLength, 26) { _message = message; _parameter = parameter; + _dataSource = dataSource; } public override string ToolTipTitle { - get => _parameter.Name + (_message.OutputParameters.Contains(_parameter) ? " output" : " input") + " parameter (" + _parameter.GetSqlDataType(null).ToSql() + ")"; + get => _parameter.Name + (_message.OutputParameters.Contains(_parameter) ? " output" : " input") + " parameter (" + _parameter.GetSqlDataType(_dataSource).ToSql() + ")"; set => base.ToolTipTitle = value; } public override string ToolTipText { - get => _message.Name + " " + String.Join(", ", _message.InputParameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(null).ToSql() + " OUTPUT]")))); + get => _message.Name + " " + String.Join(", ", _message.InputParameters.Select(p => (p.Optional ? "[" : "") + "@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + (p.Optional ? "]" : ""))) + (_message.OutputParameters.Count == 0 ? "" : ((_message.InputParameters.Count == 0 ? "" : ",") + " " + String.Join(", ", _message.OutputParameters.Select(p => "[@" + p.Name + " = " + p.GetSqlDataType(_dataSource).ToSql() + " OUTPUT]")))); set => base.ToolTipText = value; } } diff --git a/MarkMpn.Sql4Cds.XTB/ObjectExplorer.cs b/MarkMpn.Sql4Cds.XTB/ObjectExplorer.cs index c66e491f..4218bccb 100644 --- a/MarkMpn.Sql4Cds.XTB/ObjectExplorer.cs +++ b/MarkMpn.Sql4Cds.XTB/ObjectExplorer.cs @@ -737,7 +737,10 @@ private void tableContextMenuStrip_Opening(object sender, System.ComponentModel. private void functionContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) { var tvf = (Engine.Message)treeView.SelectedNode.Tag; - selectToToolStripMenuItem.Tag = (Func)(() => GenerateSelectQuery(tvf)); + var connection = GetService(treeView.SelectedNode); + var dataSource = _dataSources[connection.ConnectionName]; + + selectToToolStripMenuItem.Tag = (Func)(() => GenerateSelectQuery(tvf, dataSource)); selectToToolStripMenuItem.Enabled = true; insertToToolStripMenuItem.Enabled = false; @@ -749,7 +752,10 @@ private void functionContextMenuStrip_Opening(object sender, System.ComponentMod private void procedureContextMenuStrip_Opening(object sender, System.ComponentModel.CancelEventArgs e) { var sproc = (Engine.Message)treeView.SelectedNode.Tag; - executeToToolStripMenuItem.Tag = (Func)(() => GenerateExecuteQuery(sproc)); + var connection = GetService(treeView.SelectedNode); + var dataSource = _dataSources[connection.ConnectionName]; + + executeToToolStripMenuItem.Tag = (Func)(() => GenerateExecuteQuery(sproc, dataSource)); selectToToolStripMenuItem.Enabled = false; insertToToolStripMenuItem.Enabled = false; @@ -758,7 +764,7 @@ private void procedureContextMenuStrip_Opening(object sender, System.ComponentMo executeToToolStripMenuItem.Enabled = true; } - private string GenerateSelectQuery(Engine.Message tvf) + private string GenerateSelectQuery(Engine.Message tvf, DataSource dataSource) { var querySpec = new QuerySpecification(); querySpec.SelectElements.Add(new SelectScalarExpression { Expression = new ColumnReferenceExpression { ColumnType = ColumnType.Wildcard } }); @@ -789,7 +795,7 @@ private string GenerateSelectQuery(Engine.Message tvf) { tvfReference.Parameters.Add(new VariableReference { - Name = $"<@{param.Name}, {param.GetSqlDataType(null).ToSql()}>" + Name = $"<@{param.Name}, {param.GetSqlDataType(dataSource).ToSql()}>" }); } @@ -801,7 +807,7 @@ private string GenerateSelectQuery(Engine.Message tvf) return querySpec.ToSql(); } - private string GenerateExecuteQuery(Engine.Message sproc) + private string GenerateExecuteQuery(Engine.Message sproc, DataSource dataSource) { var batch = new TSqlBatch(); var declare = new DeclareVariableStatement(); @@ -826,7 +832,7 @@ private string GenerateExecuteQuery(Engine.Message sproc) declare.Declarations.Add(new DeclareVariableElement { VariableName = new Identifier { Value = $"@{param.Name}" }, - DataType = param.GetSqlDataType(null) + DataType = param.GetSqlDataType(dataSource) }); } diff --git a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec index 35c4ec79..7d455060 100644 --- a/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec +++ b/MarkMpn.Sql4Cds/MarkMpn.SQL4CDS.nuspec @@ -23,10 +23,25 @@ plugins or integrations by writing familiar SQL and converting it. Queries can also run using the preview TDS Endpoint. A wide range of SQL functionality is also built in to allow running queries that aren't directly supported by either FetchXML or the TDS Endpoint. Convert SQL queries to FetchXML and execute them against Dataverse / D365 - Fixed Intellisense with trailing comments -Include join alias in output column aliases when converting from Fetch XML to SQL -Improved SQL to Fetch XML conversion of datetime filters -Fixed use of case-insensitive table names in INSERT statements + Bulk DML improvements +* Automatically adjust batch size to keep requests within timeout limits +* Automatically adjust thread count to avoid hitting service protection limits +* Provide better feedback when queries pause due to service protection limits +* Automatically retry requests that have failed due to a transient error +* Added DML support for `solutioncomponent` table + +Metadata improvements +* Expose optionset values via `metadata.globaloptionsetvalue` and `metadata.optionsetvalue` tables +* Reduced amount of metadata required to execute queries + +Bug fixes +* Fixed "Must declare the scalar variable @Cond" error when using nested loop for single-record joins +* Do not trust `RetrieveTotalRecordCount` for certain metadata-related entities that give incorrect results +* Avoid errors when using cross-table column comparisons and nested link entities +* Handle nested primary functions +* Improved handling of comments and whitespace when reformatting queries +* Fixed generating TVF and sproc scripts +* Show confirmation dialog when closing unsaved scripts Copyright © 2019 Mark Carrington en-GB