From d917d2c29709e3e911b23c7a839e99420d37d688 Mon Sep 17 00:00:00 2001 From: Monica Gupta Date: Wed, 12 Aug 2020 15:34:38 -0700 Subject: [PATCH] Added new Kusto ServiceLayer (#1009) * Copy smoModel some rename * Copy entire service layer * Building copy * Fixing some references * Launch profile * Resolve namespace issues * Compiling tests. Correct manifest. * Fixing localization resources * ReliableKustoClient * Some trimming of extra code and Kusto code * Kusto client creation in bindingContent * Removing Smo and new Kusto classes * More trimming * Kusto schema hookup * Solidying DataSource abstraction * Solidifying further * Latest refatoring * More refactoring * Building and launching Kusto service layer * Working model which enumerates databases * Refactoring to pass IDataSource to all tree nodes * Removing some dependencies on the context * Working with tables and schema * Comment checkin * Refactoring to give out select script * Query created and sent back to ADS * Fix query generation * Fix listing of databases * Tunneling the query through. * Successful query execution * Return only results table * Deleting Cms * Delete DacFx * Delete SchemaCompare and TaskServices * Change build definition to not stop at launch * Fix error after merge * Save Kusto results in different formats (#935) * save results as csv etc * some fixes Co-authored-by: Monica Gupta * 2407 Added OrderBy clause in KustoDataSource > GetDatabaseMetaData and GetColumnMetadata (#959) * 2405 Defaulted Options when setting ServerInfo in ConnectionService > GetConnectionCompleteParams (#965) * 2747 Fixed IsUnknownType error for Kusto (#989) * 2747 Removed unused directives in Kusto > DbColumnWrapper. Refactored IsUnknownType to handle null DataTypeName * 2747 Reverted IsUnknownType change in DbColumnWrapper. Changed DataTypeName to get calue from ColumnType. Refactored SafeGetValue to type check before hard casting to reduce case exceptions. * Added EmbeddedResourceUseDependentUponConvention to Microsoft.Kusto.ServiceLayer.csproj. Also renamed DACfx to match Microsoft.SqlTools.ServiceLayer. Added to compile Exclude="**/obj/**/*.cs" * Srahman cleanup sql code (#992) * Removed Management and Security Service Code. * Remove FileBrowser service * Comment why we are using SqlServer library * Remove SQL specific type definitions * clean up formatter service (#996) Co-authored-by: Monica Gupta * Code clean up and Kusto intellisense (#994) * Code clean up and Kusto intellisense * Addressed few comments * Addressed few comments * addressed comments Co-authored-by: Monica Gupta * Return multiple tables for Kusto * Changes required for Kusto manage dashboard (#1039) * Changes required for manage dashboard * Addressed comments Co-authored-by: Monica Gupta * 2728 Kusto function support (#1038) * loc update (#914) * loc update * loc updates * 2728 moved ColumnInfo and KustoResultsReader to separate files. Added Folder and Function to TreeNode.cs * 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey * 2728 Added FunctionInfo. Added Folder to ColumnInfo. Removed partial class from KustoResultsReader. Set Function.IsAlwaysLeaf=true in TreeNode.cs. In KustoDataSource changed tableMetadata type to TableMetaData. Added folder and function dictionaries. Refactored GetSchema function. Renamed GenerateColumnMetadataKey to GenerateMetadataKey * 2728 Created new SqlConnection within using block. Refactored KustoDataSource > columnmetadata to sort on get instead of insert. * 2728 Added GetFunctionInfo function to KustoDataSource. * 2728 Reverted change to Microsoft.Kusto.ServiceLayer.csproj from merge * 2728 Reverted change to SqlTools.ServiceLayer\Localization\transXliff * 2728 Reverted change to sr.de.xlf and sr.zh-hans.xlf * 2728 Refactored KustoDataSource Function folders to support subfolders * 2728 Refactored KustoDataSource to use urn for folders, functions, and tables instead of name. * Merge remote-tracking branch 'origin/main' into feature-ADE # Conflicts: # Packages.props * 2728 Moved metadata files into Metadata subdirectory. Added GenerateAlterFunction to IDataSource and DataSourceBase. * 2728 Added summary information to SafeAdd in SystemExtensions. Renamed local variable in SetTableMetadata * 2728 Moved SafeAdd from SystemExtensions to KustoQueryUtils. Added check when getting database schema to return existing records before querying again. Added AddRange function to KustoQueryUtils. Created SetFolderMetadataForFunctions method. * 2728 Added DatabaseKeyPrefix to only return tables to a database for the dashboard. Added logic to store all database tables within the tableMetadata dictionary for the dashboard. * 2728 Created TableInfo and moved info objects into Models directory. Refactored KustoDataSource to lazy load columns for tables. Refactored logic to load tables using cslschema instead of schema. * 2728 Renamed LoadColumnSchema to GetTableSchema to be consistent. Co-authored-by: khoiph1 * Addressed comments Co-authored-by: Shafiq Rahman Co-authored-by: Monica Gupta Co-authored-by: Justin M <63619224+JustinMDotNet@users.noreply.github.com> Co-authored-by: rkselfhost Co-authored-by: khoiph1 --- .vscode/launch.json | 23 + Packages.props | 2 + sqltoolsservice.sln | 9 + .../Admin/AdminService.cs | 136 + .../Admin/Contracts/DatabaseInfo.cs | 23 + .../Admin/Contracts/GetDatabaseInfoRequest.cs | 41 + .../Connection/CancelTokenKey.cs | 36 + .../Connection/ConnectionInfo.cs | 162 + .../ConnectionProviderOptionsHelper.cs | 302 ++ .../Connection/ConnectionService.cs | 1513 ++++++ .../Connection/ConnectionType.cs | 23 + .../Contracts/BuildConnectionInfoRequest.cs | 19 + .../Contracts/CancelConnectParams.cs | 24 + .../Contracts/CancelConnectRequest.cs | 19 + .../Contracts/ChangeDatabaseParams.cs | 23 + .../Contracts/ChangeDatabaseRequest.cs | 19 + .../Connection/Contracts/ConnectParams.cs | 37 + .../Contracts/ConnectParamsExtensions.cs | 48 + .../ConnectionChangedNotification.cs | 19 + .../Contracts/ConnectionChangedParams.cs | 23 + .../ConnectionCompleteNotification.cs | 66 + .../Connection/Contracts/ConnectionDetails.cs | 540 ++ .../Contracts/ConnectionDetailsExtensions.cs | 52 + .../Connection/Contracts/ConnectionRequest.cs | 19 + .../Connection/Contracts/ConnectionSummary.cs | 48 + .../Contracts/ConnectionSummaryComparer.cs | 53 + .../Contracts/ConnectionSummaryExtensions.cs | 26 + .../Connection/Contracts/DisconnectParams.cs | 25 + .../Connection/Contracts/DisconnectRequest.cs | 19 + .../Contracts/GetConnectionStringParams.cs | 23 + .../Contracts/GetConnectionStringRequest.cs | 19 + .../Contracts/LanguageFlavorChange.cs | 42 + .../Contracts/ListDatabasesParams.cs | 23 + .../Contracts/ListDatabasesRequest.cs | 19 + .../Contracts/ListDatabasesResponse.cs | 24 + .../Connection/Contracts/ServerInfo.cs | 75 + .../Connection/DataSourceConnectionFactory.cs | 29 + .../Connection/DatabaseFullAccessException.cs | 28 + .../Connection/DatabaseLocksManager.cs | 114 + .../Connection/FeatureWithFullDbAccess.cs | 40 + .../IDataSourceConnectionFactory.cs | 20 + .../RetryCallbackEventArgs.cs | 58 + .../DataSource/DataReaderWrapper.cs | 59 + .../DataSource/DataSourceBase.cs | 132 + .../DataSource/DataSourceFactory.cs | 159 + .../KustoIntellisenseHelper.cs | 329 ++ .../DataSourceIntellisense/ScriptParseInfo.cs | 48 + .../DataSource/DataSourceType.cs | 28 + .../DataSource/DiagnosticsInfo.cs | 17 + .../DataSource/IDataSource.cs | 132 + .../DataSource/KustoDataSource.cs | 1045 ++++ .../DataSource/KustoQueryUtils.cs | 115 + .../DataSource/KustoResultsReader.cs | 22 + .../DataSource/Metadata/ColumnMetadata.cs | 11 + .../Metadata/DataSourceMetadataType.cs | 15 + .../Metadata/DataSourceObjectMetadata.cs | 20 + .../DataSource/Metadata/DatabaseMetadata.cs | 10 + .../DataSource/Metadata/FolderMetadata.cs | 10 + .../DataSource/Metadata/FunctionMetadata.cs | 11 + .../DataSource/Metadata/TableMetadata.cs | 11 + .../DataSource/Models/ColumnInfo.cs | 26 + .../DataSource/Models/FunctionInfo.cs | 11 + .../DataSource/Models/TableInfo.cs | 8 + .../ReliableDataSourceConnection.cs | 258 + .../Formatter/Contracts/DocumentFormatting.cs | 113 + .../Formatter/Impl/FormatOptions.cs | 171 + .../Formatter/TSqlFormatterService.cs | 320 ++ .../HostLoader.cs | 136 + .../LanguageServices/AutoCompleteHelper.cs | 112 + .../LanguageServices/BindingQueue.cs | 502 ++ .../ConnectedBindingContext.cs | 223 + .../LanguageServices/ConnectedBindingQueue.cs | 234 + .../LanguageServices/Contracts/Completion.cs | 111 + .../LanguageServices/Contracts/Definition.cs | 18 + .../LanguageServices/Contracts/Diagnostics.cs | 72 + .../Contracts/DocumentHighlight.cs | 32 + .../Contracts/ExpandAliasRequest.cs | 16 + .../Contracts/FindModuleRequest.cs | 24 + .../LanguageServices/Contracts/Hover.cs | 33 + .../Contracts/InstallModuleRequest.cs | 16 + .../Contracts/IntelliSenseReady.cs | 30 + .../RebuildIntelliSenseNotification.cs | 30 + .../LanguageServices/Contracts/References.cs | 28 + .../Contracts/ShowOnlineHelpRequest.cs | 16 + .../Contracts/SignatureHelp.cs | 43 + .../Contracts/StatusChangedNotification.cs | 35 + .../LanguageServices/Contracts/SyntaxParse.cs | 31 + .../Contracts/TelemetryNotification.cs | 100 + .../LanguageServices/Contracts/TextEdit.cs | 20 + .../LanguageServices/DiagnosticsHelper.cs | 124 + .../LanguageServices/DocumentStatusHelper.cs | 77 + .../LanguageServices/IBindingContext.cs | 88 + .../LanguageServices/InteractionMetrics.cs | 98 + .../LanguageServices/LanguageService.cs | 1200 +++++ .../LanguageServices/PeekDefinitionResult.cs | 28 + .../LanguageServices/QueueItem.cs | 77 + .../LanguageServices/ScriptDocumentInfo.cs | 107 + .../Localization/sr.cs | 4365 +++++++++++++++++ .../Localization/sr.de.resx | 490 ++ .../Localization/sr.es.resx | 489 ++ .../Localization/sr.fr.resx | 489 ++ .../Localization/sr.it.resx | 489 ++ .../Localization/sr.ja.resx | 490 ++ .../Localization/sr.ko.resx | 491 ++ .../Localization/sr.pt-BR.resx | 490 ++ .../Localization/sr.resx | 1745 +++++++ .../Localization/sr.ru.resx | 483 ++ .../Localization/sr.strings | 808 +++ .../Localization/sr.xlf | 2029 ++++++++ .../Localization/sr.zh-hans.resx | 489 ++ .../Localization/sr.zh-hant.resx | 491 ++ .../Localization/transXliff/sr.de.xlf | 2776 +++++++++++ .../Localization/transXliff/sr.es.xlf | 2775 +++++++++++ .../Localization/transXliff/sr.fr.xlf | 2775 +++++++++++ .../Localization/transXliff/sr.it.xlf | 2775 +++++++++++ .../Localization/transXliff/sr.ja.xlf | 2776 +++++++++++ .../Localization/transXliff/sr.ko.xlf | 2777 +++++++++++ .../Localization/transXliff/sr.pt-BR.xlf | 2776 +++++++++++ .../Localization/transXliff/sr.ru.xlf | 2769 +++++++++++ .../Localization/transXliff/sr.zh-hans.xlf | 2775 +++++++++++ .../Localization/transXliff/sr.zh-hant.xlf | 2777 +++++++++++ .../Metadata/Contracts/MetadataListRequest.cs | 26 + .../Metadata/Contracts/ObjectMetadata.cs | 33 + .../Metadata/MetadataService.cs | 109 + .../Microsoft.Kusto.ServiceLayer.csproj | 43 + .../Contracts/CloseSessionRequest.cs | 86 + .../Contracts/CreateSessionRequest.cs | 76 + .../ObjectExplorer/Contracts/ExpandRequest.cs | 76 + .../Contracts/FindNodesRequest.cs | 55 + .../ObjectExplorer/Contracts/NodeInfo.cs | 62 + .../Contracts/RefreshRequest.cs | 29 + .../ObjectExplorer/Nodes/ChildFactory.cs | 74 + .../ObjectExplorer/Nodes/NodeFilter.cs | 107 + .../Nodes/NodeObservableCollection.cs | 190 + .../ObjectExplorer/Nodes/NodeSmoProperty.cs | 24 + .../ObjectExplorer/Nodes/NodeTypes.cs | 144 + .../ObjectExplorer/Nodes/TreeNode.cs | 539 ++ .../Nodes/TreeNodeWithContext.cs | 11 + .../ObjectExplorer/ObjectExplorerService.cs | 839 ++++ .../ObjectExplorer/ObjectExplorerUtils.cs | 79 + .../SmoModel/DataSourceQueryModel.cs | 52 + .../ObjectExplorer/SmoModel/FolderNode.cs | 39 + .../SmoModel/NodePathGenerator.cs | 268 + .../ObjectExplorer/SmoModel/ServerNode.cs | 129 + .../SmoModel/SmoChildFactoryBase.cs | 178 + .../SmoModel/SmoCollectionWrapper.cs | 57 + .../SmoModel/SmoColumnCustomNode.cs | 356 ++ .../SmoModel/SmoDatabaseCustomNode.cs | 55 + .../SmoModel/SmoKeyCustomNode.cs | 115 + .../SmoModel/SmoLoginCustomNode.cs | 52 + .../SmoModel/SmoParamterCustomNode.cs | 137 + .../ObjectExplorer/SmoModel/SmoQuerier.cs | 85 + .../SmoModel/SmoQueryContext.cs | 66 + .../ObjectExplorer/SmoModel/SmoQueryModel.tt | 320 ++ .../SmoModel/SmoQueryModelDefinition.xml | 164 + .../SmoModel/SmoTableCustomNode.cs | 34 + .../ObjectExplorer/SmoModel/SmoTreeNode.cs | 79 + .../SmoModel/TreeNodeDefinition.xml | 467 ++ .../SmoModel/TreeNodeGenerator.tt | 564 +++ .../ObjectExplorer/ValidForFlag.cs | 28 + src/Microsoft.Kusto.ServiceLayer/Program.cs | 63 + .../Properties/AssemblyInfo.cs | 50 + .../QueryExecution/Batch.cs | 649 +++ .../QueryExecution/Contracts/BatchSummary.cs | 55 + .../QueryExecution/Contracts/DbCellValue.cs | 56 + .../Contracts/DbColumnWrapper.cs | 352 ++ .../Contracts/ExecuteRequests/BatchEvents.cs | 39 + .../ExecuteDocumentSelectionRequest.cs | 27 + .../ExecuteDocumentStatementRequest.cs | 32 + .../ExecuteRequestParamsBase.cs | 28 + .../ExecuteRequests/ExecuteRequestResult.cs | 13 + .../ExecuteRequests/ExecuteStringRequest.cs | 27 + .../Contracts/ExecuteRequests/MessageEvent.cs | 32 + .../ExecuteRequests/QueryCompleteEvent.cs | 32 + .../ExecuteRequests/ResultSetEvents.cs | 67 + .../ExecuteRequests/SimpleExecuteRequest.cs | 54 + .../QueryExecution/Contracts/ExecutionPlan.cs | 23 + .../Contracts/ExecutionPlanOptions.cs | 23 + .../Contracts/QueryCancelRequest.cs | 36 + .../Contracts/QueryDisposeRequest.cs | 31 + .../Contracts/QueryExecutionPlanRequest.cs | 49 + .../QueryExecution/Contracts/ResultMessage.cs | 56 + .../Contracts/ResultSetSubset.cs | 24 + .../Contracts/ResultSetSummary.cs | 46 + .../Contracts/SaveResultsRequest.cs | 188 + .../QueryExecution/Contracts/SelectionData.cs | 52 + .../QueryExecution/Contracts/Serialization.cs | 180 + .../QueryExecution/Contracts/SubsetRequest.cs | 61 + .../DataStorage/FileStreamReadResult.cs | 44 + .../DataStorage/IFileStreamFactory.cs | 22 + .../DataStorage/IFileStreamReader.cs | 19 + .../DataStorage/IFileStreamWriter.cs | 23 + .../DataStorage/SaveAsCsvFileStreamFactory.cs | 73 + .../DataStorage/SaveAsCsvFileStreamWriter.cs | 161 + .../SaveAsExcelFileStreamFactory.cs | 73 + .../SaveAsExcelFileStreamWriter.cs | 87 + .../SaveAsExcelFileStreamWriterHelper.cs | 805 +++ .../SaveAsJsonFileStreamFactory.cs | 71 + .../DataStorage/SaveAsJsonFileStreamWriter.cs | 111 + .../DataStorage/SaveAsWriterBase.cs | 123 + .../DataStorage/SaveAsXmlFileStreamFactory.cs | 71 + .../DataStorage/SaveAsXmlFileStreamWriter.cs | 142 + .../ServiceBufferFileStreamFactory.cs | 66 + .../ServiceBufferFileStreamReader.cs | 552 +++ .../ServiceBufferFileStreamWriter.cs | 587 +++ .../DataStorage/StorageDataReader.cs | 309 ++ .../QueryExecution/Query.cs | 456 ++ .../QueryExecutionOptionsRequest.cs | 27 + .../QueryExecution/QueryExecutionService.cs | 1076 ++++ .../QueryExecution/QuerySettingsHelper.cs | 223 + .../QueryExecution/ResultOnlyContext.cs | 36 + .../QueryExecution/ResultSet.cs | 748 +++ .../QueryExecution/SerializationService.cs | 318 ++ .../QueryExecution/SpecialAction.cs | 80 + .../Contracts/ScriptingCancelRequest.cs | 28 + .../Contracts/ScriptingCompleteEvent.cs | 49 + .../Contracts/ScriptingEventParams.cs | 24 + .../Contracts/ScriptingListObjectsEvent.cs | 35 + .../Contracts/ScriptingListObjectsRequest.cs | 35 + .../Scripting/Contracts/ScriptingObject.cs | 93 + .../Contracts/ScriptingOperationType.cs | 21 + .../Scripting/Contracts/ScriptingOptions.cs | 261 + .../ScriptingPlanNotificationEvent.cs | 34 + .../ScriptingProgressNotificationEvent.cs | 57 + .../Scripting/Contracts/ScriptingRequest.cs | 101 + .../Scripting/ScriptAsOptions.cs | 712 +++ .../Scripting/ScriptAsScriptingOperation.cs | 552 +++ .../Scripting/Scripter.cs | 75 + .../Scripting/ScripterCore.cs | 683 +++ .../Scripting/ScriptingExtensionMethods.cs | 130 + .../ScriptingListObjectsOperation.cs | 134 + .../Scripting/ScriptingObjectMatcher.cs | 245 + .../Scripting/ScriptingOperation.cs | 57 + .../Scripting/ScriptingScriptOperation.cs | 298 ++ .../Scripting/ScriptingService.cs | 254 + .../Scripting/SmoScriptingOperation.cs | 188 + .../ServiceHost.cs | 231 + .../CompoundSqlToolsSettingsValues.cs | 102 + .../SqlContext/FormatterSettings.cs | 88 + .../SqlContext/ISqlToolsSettingsValues.cs | 33 + .../SqlContext/IntelliSenseSettings.cs | 68 + .../SqlContext/ObjectExplorerSettings.cs | 32 + .../SqlContext/QueryExecutionSettings.cs | 698 +++ .../SqlContext/SqlToolsSettings.cs | 146 + .../SqlContext/SqlToolsSettingsValues.cs | 56 + .../Utility/AccessTokenProvider.cs | 24 + .../Utility/CommonConstants.cs | 21 + .../Utility/DatabaseUtils.cs | 26 + .../Utility/FeaturesMetadataProviderHelper.cs | 28 + .../Utility/FileUtils.cs | 161 + .../Utility/IRequestParams.cs | 16 + .../Utility/LongList.cs | 336 ++ .../Utility/ResolvedFile.cs | 43 + .../Utility/ResultStatus.cs | 14 + .../Utility/ServiceLayerCommandOptions.cs | 36 + .../SqlScriptFormatters/FromSqlScript.cs | 157 + .../SqlScriptFormatters/ToSqlScript.cs | 326 ++ .../Utility/SystemExtensions.cs | 202 + .../Utility/TaskExtensions.cs | 135 + .../Utility/ValidationUtils.cs | 147 + .../Workspace/Contracts/BufferPosition.cs | 110 + .../Workspace/Contracts/BufferRange.cs | 120 + .../Workspace/Contracts/Configuration.cs | 21 + .../Workspace/Contracts/FileChange.cs | 38 + .../Workspace/Contracts/FilePosition.cs | 110 + .../Workspace/Contracts/ScriptFile.cs | 450 ++ .../Workspace/Contracts/ScriptFileMarker.cs | 56 + .../Workspace/Contracts/ScriptRegion.cs | 89 + .../Workspace/Contracts/TextDocument.cs | 295 ++ .../Workspace/Contracts/WorkspaceSymbols.cs | 70 + .../Workspace/Workspace.cs | 365 ++ .../Workspace/WorkspaceService.cs | 373 ++ .../Extensibility/ExtensionServiceProvider.cs | 3 +- .../Properties/AssemblyInfo.cs | 1 + .../Properties/AssemblyInfo.cs | 1 + ...Tools.ServiceLayer.IntegrationTests.csproj | 1 + 276 files changed, 75983 insertions(+), 1 deletion(-) create mode 100644 src/Microsoft.Kusto.ServiceLayer/Admin/AdminService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/DatabaseInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/GetDatabaseInfoRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/CancelTokenKey.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionProviderOptionsHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionType.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/BuildConnectionInfoRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParamsExtensions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedNotification.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionCompleteNotification.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetails.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummary.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryComparer.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/LanguageFlavorChange.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesResponse.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ServerInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseFullAccessException.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseLocksManager.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/FeatureWithFullDbAccess.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Connection/ReliableConnection/RetryCallbackEventArgs.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataReaderWrapper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceType.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/DiagnosticsInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/KustoResultsReader.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/ColumnMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceMetadataType.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceObjectMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DatabaseMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FolderMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FunctionMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/TableMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Models/ColumnInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Models/FunctionInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/Models/TableInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Formatter/Impl/FormatOptions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Formatter/TSqlFormatterService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/HostLoader.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/AutoCompleteHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingContext.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Completion.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Definition.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Diagnostics.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/DocumentHighlight.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ExpandAliasRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/FindModuleRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Hover.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/InstallModuleRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/IntelliSenseReady.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/RebuildIntelliSenseNotification.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/References.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ShowOnlineHelpRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SignatureHelp.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/StatusChangedNotification.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SyntaxParse.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TelemetryNotification.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TextEdit.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/DiagnosticsHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/DocumentStatusHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/IBindingContext.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/InteractionMetrics.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/PeekDefinitionResult.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/QueueItem.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.de.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.es.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.fr.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.it.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.ja.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.ko.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.pt-BR.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.ru.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.strings create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hans.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hant.resx create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.de.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.es.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.fr.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.it.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ja.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ko.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.pt-BR.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ru.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hans.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hant.xlf create mode 100644 src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/MetadataListRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Metadata/MetadataService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CloseSessionRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CreateSessionRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/FindNodesRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeFilter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeSmoProperty.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeTypes.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNodeWithContext.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/DataSourceQueryModel.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/FolderNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/NodePathGenerator.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/ServerNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoCollectionWrapper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoColumnCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQuerier.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModel.tt create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModelDefinition.xml create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeDefinition.xml create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeGenerator.tt create mode 100644 src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ValidForFlag.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Program.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Properties/AssemblyInfo.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbColumnWrapper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/BatchEvents.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentSelectionRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestParamsBase.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestResult.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteStringRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/MessageEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/QueryCompleteEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ResultSetEvents.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/SimpleExecuteRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlan.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlanOptions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryCancelRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryExecutionPlanRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SelectionData.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/Serialization.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SubsetRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/FileStreamReadResult.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsWriterBase.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/StorageDataReader.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionOptionsRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/QuerySettingsHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultOnlyContext.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/ResultSet.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/SerializationService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/QueryExecution/SpecialAction.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingCancelRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingCompleteEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingEventParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingListObjectsEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingListObjectsRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingObject.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingOperationType.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingOptions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingPlanNotificationEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingProgressNotificationEvent.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Contracts/ScriptingRequest.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsOptions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptAsScriptingOperation.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/Scripter.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScripterCore.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingExtensionMethods.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingListObjectsOperation.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingObjectMatcher.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingOperation.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingScriptOperation.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/ScriptingService.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Scripting/SmoScriptingOperation.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/ServiceHost.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/CompoundSqlToolsSettingsValues.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/FormatterSettings.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/ISqlToolsSettingsValues.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/IntelliSenseSettings.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/ObjectExplorerSettings.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/QueryExecutionSettings.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/SqlToolsSettings.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/SqlContext/SqlToolsSettingsValues.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/AccessTokenProvider.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/CommonConstants.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/DatabaseUtils.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/FeaturesMetadataProviderHelper.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/FileUtils.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/IRequestParams.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/LongList.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/ResolvedFile.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/ResultStatus.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/ServiceLayerCommandOptions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/FromSqlScript.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/SqlScriptFormatters/ToSqlScript.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/SystemExtensions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/TaskExtensions.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Utility/ValidationUtils.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/BufferPosition.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/BufferRange.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/Configuration.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/FileChange.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/FilePosition.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFile.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptFileMarker.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/ScriptRegion.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/TextDocument.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Contracts/WorkspaceSymbols.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/Workspace.cs create mode 100644 src/Microsoft.Kusto.ServiceLayer/Workspace/WorkspaceService.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index e6ab5c0d07..208aac21e1 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -18,6 +18,20 @@ "stopAtEntry": false, "internalConsoleOptions": "openOnSessionStart" }, + { + "name": "Kusto service Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/src/Microsoft.Kusto.ServiceLayer/bin/Debug/netcoreapp3.1/MicrosoftKustoServiceLayer.dll", + "args": [], + "cwd": "${workspaceFolder}/src/Microsoft.Kusto.ServiceLayer", + // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window + "console": "externalTerminal", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + }, { "name": ".NET Core Attach", "type": "coreclr", @@ -26,6 +40,15 @@ "requireExactSource": false, "justMyCode": false, "enableStepFiltering": false + }, + { + "name": "Kusto Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}", + "requireExactSource": false, + "justMyCode": false, + "enableStepFiltering": false } ,] } \ No newline at end of file diff --git a/Packages.props b/Packages.props index 352c518963..6b4e111665 100644 --- a/Packages.props +++ b/Packages.props @@ -20,6 +20,8 @@ + + diff --git a/sqltoolsservice.sln b/sqltoolsservice.sln index f0803e4380..fd58bf2063 100644 --- a/sqltoolsservice.sln +++ b/sqltoolsservice.sln @@ -104,6 +104,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlTools.ManagedB EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.SqlTools.Test.CompletionExtension", "test\Microsoft.SqlTools.Test.CompletionExtension\Microsoft.SqlTools.Test.CompletionExtension.csproj", "{0EC2B30C-0652-49AE-9594-85B3C3E9CA21}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Kusto.ServiceLayer", "src\Microsoft.Kusto.ServiceLayer\Microsoft.Kusto.ServiceLayer.csproj", "{E0C941C8-91F2-4BE1-8B79-AC88EDB78729}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "azure-pipelines", "azure-pipelines", "{48D5C134-4091-438D-9D35-6EB8CF0D1DCC}" ProjectSection(SolutionItems) = preProject azure-pipelines\build.yml = azure-pipelines\build.yml @@ -249,6 +251,12 @@ Global {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Integration|Any CPU.Build.0 = Debug|Any CPU {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.ActiveCfg = Release|Any CPU {0EC2B30C-0652-49AE-9594-85B3C3E9CA21}.Release|Any CPU.Build.0 = Release|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Integration|Any CPU.ActiveCfg = Debug|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Integration|Any CPU.Build.0 = Debug|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -278,6 +286,7 @@ Global {3F82F298-700A-48DF-8A69-D048DFBA782C} = {2BBD7364-054F-4693-97CD-1C395E3E84A9} {D3696EFA-FB1E-4848-A726-FF7B168AFB96} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} {0EC2B30C-0652-49AE-9594-85B3C3E9CA21} = {AB9CA2B8-6F70-431C-8A1D-67479D8A7BE4} + {E0C941C8-91F2-4BE1-8B79-AC88EDB78729} = {2BBD7364-054F-4693-97CD-1C395E3E84A9} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B31CDF4B-2851-45E5-8C5F-BE97125D9DD8} diff --git a/src/Microsoft.Kusto.ServiceLayer/Admin/AdminService.cs b/src/Microsoft.Kusto.ServiceLayer/Admin/AdminService.cs new file mode 100644 index 0000000000..3c86dbbd97 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Admin/AdminService.cs @@ -0,0 +1,136 @@ +// +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Admin.Contracts; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.Admin +{ + /// + /// Admin task service class + /// + public class AdminService + { + private static readonly Lazy instance = new Lazy(() => new AdminService()); + + private static ConnectionService connectionService = null; + + /// + /// Default, parameterless constructor. + /// + internal AdminService() + { + } + + /// + /// Internal for testing purposes only + /// + internal static ConnectionService ConnectionServiceInstance + { + get + { + if (AdminService.connectionService == null) + { + AdminService.connectionService = ConnectionService.Instance; + } + return AdminService.connectionService; + } + + set + { + AdminService.connectionService = value; + } + } + + /// + /// Gets the singleton instance object + /// + public static AdminService Instance + { + get { return instance.Value; } + } + + /// + /// Initializes the service instance + /// + public void InitializeService(ServiceHost serviceHost) + { + serviceHost.SetRequestHandler(GetDatabaseInfoRequest.Type, HandleGetDatabaseInfoRequest); + } + + /// + /// Handle get database info request + /// + internal static async Task HandleGetDatabaseInfoRequest( + GetDatabaseInfoParams databaseParams, + RequestContext requestContext) + { + try + { + Func requestHandler = async () => + { + ConnectionInfo connInfo; + AdminService.ConnectionServiceInstance.TryFindConnection( + databaseParams.OwnerUri, + out connInfo); + DatabaseInfo info = null; + + if (connInfo != null) + { + info = GetDatabaseInfo(connInfo); + } + + await requestContext.SendResult(new GetDatabaseInfoResponse() + { + DatabaseInfo = info + }); + }; + + Task task = Task.Run(async () => await requestHandler()).ContinueWithOnFaulted(async t => + { + await requestContext.SendError(t.Exception.ToString()); + }); + + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Return database info for a specific database + /// + /// + /// + internal static DatabaseInfo GetDatabaseInfo(ConnectionInfo connInfo) + { + if(!string.IsNullOrEmpty(connInfo.ConnectionDetails.DatabaseName)){ + ReliableDataSourceConnection connection; + connInfo.TryGetConnection("Default", out connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + DataSourceObjectMetadata objectMetadata = DataSourceFactory.CreateClusterMetadata(connInfo.ConnectionDetails.ServerName); + + List metadata = dataSource.GetChildObjects(objectMetadata, true).ToList(); + var databaseMetadata = metadata.Where(o => o.Name == connInfo.ConnectionDetails.DatabaseName); + + List databaseInfo = DataSourceFactory.ConvertToDatabaseInfo(databaseMetadata); + + return databaseInfo.ElementAtOrDefault(0); + } + + return null; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/DatabaseInfo.cs b/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/DatabaseInfo.cs new file mode 100644 index 0000000000..b03e6ed632 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/DatabaseInfo.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.Kusto.ServiceLayer.Admin.Contracts +{ + public class DatabaseInfo + { + /// + /// Gets or sets the options + /// + public Dictionary Options { get; set; } + + public DatabaseInfo() + { + Options = new Dictionary(); + } + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/GetDatabaseInfoRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/GetDatabaseInfoRequest.cs new file mode 100644 index 0000000000..de1c5bea3d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Admin/Contracts/GetDatabaseInfoRequest.cs @@ -0,0 +1,41 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Admin.Contracts +{ + /// + /// Params for a get database info request + /// + public class GetDatabaseInfoParams + { + /// + /// Uri identifier for the connection to get the database info for + /// + public string OwnerUri { get; set; } + } + + /// + /// Response object for get database info + /// + public class GetDatabaseInfoResponse + { + /// + /// The object containing the database info + /// + public DatabaseInfo DatabaseInfo { get; set; } + } + + /// + /// Get database info request mapping + /// + public class GetDatabaseInfoRequest + { + public static readonly + RequestType Type = + RequestType.Create("admin/getdatabaseinfo"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/CancelTokenKey.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/CancelTokenKey.cs new file mode 100644 index 0000000000..5b046ad42f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/CancelTokenKey.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Used to uniquely identify a CancellationTokenSource associated with both + /// a string URI and a string connection type. + /// + public class CancelTokenKey : CancelConnectParams, IEquatable + { + public override bool Equals(object obj) + { + CancelTokenKey other = obj as CancelTokenKey; + if (other == null) + { + return false; + } + + return other.OwnerUri == OwnerUri && other.Type == Type; + } + + public bool Equals(CancelTokenKey obj) + { + return obj.OwnerUri == OwnerUri && obj.Type == Type; + } + + public override int GetHashCode() + { + return OwnerUri.GetHashCode() ^ Type.GetHashCode(); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs new file mode 100644 index 0000000000..fdaa738174 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionInfo.cs @@ -0,0 +1,162 @@ +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Data.Common; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Information pertaining to a unique connection instance. + /// + public class ConnectionInfo + { + /// + /// Constructor + /// + public ConnectionInfo(IDataSourceConnectionFactory factory, string ownerUri, ConnectionDetails details) + { + Factory = factory; + OwnerUri = ownerUri; + ConnectionDetails = details; + ConnectionId = Guid.NewGuid(); + IntellisenseMetrics = new InteractionMetrics(new int[] {50, 100, 200, 500, 1000, 2000}); + } + + /// + /// Unique Id, helpful to identify a connection info object + /// + public Guid ConnectionId { get; private set; } + + /// + /// URI identifying the owner/user of the connection. Could be a file, service, resource, etc. + /// + public string OwnerUri { get; private set; } + + /// + /// Factory used for creating the SQL connection associated with the connection info. + /// + public IDataSourceConnectionFactory Factory { get; private set; } + + /// + /// Properties used for creating/opening the SQL connection. + /// + public ConnectionDetails ConnectionDetails { get; private set; } + + /// + /// A map containing all connections to the database that are associated with + /// this ConnectionInfo's OwnerUri. + /// This is internal for testing access only + /// + internal readonly ConcurrentDictionary ConnectionTypeToConnectionMap = + new ConcurrentDictionary(); + + /// + /// Intellisense Metrics + /// + public InteractionMetrics IntellisenseMetrics { get; private set; } + + /// + /// Returns true if the db connection is to any cloud instance + /// + public bool IsCloud { get; set; } + + /// + /// Returns the major version number of the db we are connected to + /// + public int MajorVersion { get; set; } + + /// + /// All DbConnection instances held by this ConnectionInfo + /// + public ICollection AllConnections + { + get + { + return ConnectionTypeToConnectionMap.Values; + } + } + + /// + /// All connection type strings held by this ConnectionInfo + /// + /// + public ICollection AllConnectionTypes + { + get + { + return ConnectionTypeToConnectionMap.Keys; + } + } + + public bool HasConnectionType(string connectionType) + { + connectionType = connectionType ?? ConnectionType.Default; + return ConnectionTypeToConnectionMap.ContainsKey(connectionType); + } + + /// + /// The count of DbConnectioninstances held by this ConnectionInfo + /// + public int CountConnections + { + get + { + return ConnectionTypeToConnectionMap.Count; + } + } + + /// + /// Try to get the DbConnection associated with the given connection type string. + /// + /// true if a connection with type connectionType was located and out connection was set, + /// false otherwise + /// Thrown when connectionType is null or empty + public bool TryGetConnection(string connectionType, out ReliableDataSourceConnection connection) + { + Validate.IsNotNullOrEmptyString("Connection Type", connectionType); + return ConnectionTypeToConnectionMap.TryGetValue(connectionType, out connection); + } + + /// + /// Adds a DbConnection to this object and associates it with the given + /// connection type string. If a connection already exists with an identical + /// connection type string, it is not overwritten. Ignores calls where connectionType = null + /// + /// Thrown when connectionType is null or empty + public void AddConnection(string connectionType, ReliableDataSourceConnection connection) + { + Validate.IsNotNullOrEmptyString("Connection Type", connectionType); + ConnectionTypeToConnectionMap.TryAdd(connectionType, connection); + } + + /// + /// Removes the single DbConnection instance associated with string connectionType + /// + /// Thrown when connectionType is null or empty + public void RemoveConnection(string connectionType) + { + Validate.IsNotNullOrEmptyString("Connection Type", connectionType); + ReliableDataSourceConnection connection; + ConnectionTypeToConnectionMap.TryRemove(connectionType, out connection); + } + + /// + /// Removes all DbConnection instances held by this object + /// + public void RemoveAllConnections() + { + foreach (var type in AllConnectionTypes) + { + ReliableDataSourceConnection connection; + ConnectionTypeToConnectionMap.TryRemove(type, out connection); + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionProviderOptionsHelper.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionProviderOptionsHelper.cs new file mode 100644 index 0000000000..ede01b0b7e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionProviderOptionsHelper.cs @@ -0,0 +1,302 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Helper class for providing metadata about connection options + /// + internal class ConnectionProviderOptionsHelper + { + internal static ConnectionProviderOptions BuildConnectionProviderOptions() + { + return new ConnectionProviderOptions + { + Options = new ConnectionOption[] + { + new ConnectionOption + { + Name = "server", + DisplayName = "Server name", + Description = "Name of the SQL Server instance", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueServerName, + IsIdentity = true, + IsRequired = true, + GroupName = "Source" + }, + new ConnectionOption + { + Name = "database", + DisplayName = "Database name", + Description = "The name of the initial catalog or database int the data source", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueDatabaseName, + IsIdentity = true, + IsRequired = false, + GroupName = "Source" + }, + new ConnectionOption + { + Name = "authenticationType", + DisplayName = "Authentication type", + Description = "Specifies the method of authenticating with SQL Server", + ValueType = ConnectionOption.ValueTypeCategory, + SpecialValueType = ConnectionOption.SpecialValueAuthType, + CategoryValues = new CategoryValue[] + { new CategoryValue { DisplayName = "SQL Login", Name = "SqlLogin" }, + new CategoryValue { DisplayName = "Windows Authentication", Name = "Integrated" }, + new CategoryValue { DisplayName = "Azure Active Directory - Universal with MFA support", Name = "AzureMFA" } + }, + IsIdentity = true, + IsRequired = true, + GroupName = "Security" + }, + new ConnectionOption + { + Name = "user", + DisplayName = "User name", + Description = "Indicates the user ID to be used when connecting to the data source", + ValueType = ConnectionOption.ValueTypeString, + SpecialValueType = ConnectionOption.SpecialValueUserName, + IsIdentity = true, + IsRequired = true, + GroupName = "Security" + }, + new ConnectionOption + { + Name = "password", + DisplayName = "Password", + Description = "Indicates the password to be used when connecting to the data source", + ValueType = ConnectionOption.ValueTypePassword, + SpecialValueType = ConnectionOption.SpecialValuePasswordName, + IsIdentity = true, + IsRequired = true, + GroupName = "Security" + }, + new ConnectionOption + { + Name = "applicationIntent", + DisplayName = "Application intent", + Description = "Declares the application workload type when connecting to a server", + ValueType = ConnectionOption.ValueTypeCategory, + CategoryValues = new CategoryValue[] { + new CategoryValue { Name = "ReadWrite", DisplayName = "ReadWrite" }, + new CategoryValue {Name = "ReadOnly", DisplayName = "ReadOnly" } + }, + GroupName = "Initialization" + }, + new ConnectionOption + { + Name = "asynchronousProcessing", + DisplayName = "Asynchronous processing enabled", + Description = "When true, enables usage of the Asynchronous functionality in the .Net Framework Data Provider", + ValueType = ConnectionOption.ValueTypeBoolean, + GroupName = "Initialization" + }, + new ConnectionOption + { + Name = "connectTimeout", + DisplayName = "Connect timeout", + Description = + "The length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error", + ValueType = ConnectionOption.ValueTypeNumber, + DefaultValue = "15", + GroupName = "Initialization" + }, + new ConnectionOption + { + Name = "currentLanguage", + DisplayName = "Current language", + Description = "The SQL Server language record name", + ValueType = ConnectionOption.ValueTypeString, + GroupName = "Initialization" + }, + new ConnectionOption + { + Name = "columnEncryptionSetting", + DisplayName = "Column encryption setting", + Description = "Default column encryption setting for all the commands on the connection", + ValueType = ConnectionOption.ValueTypeCategory, + GroupName = "Security", + CategoryValues = new CategoryValue[] { + new CategoryValue { Name = "Disabled" }, + new CategoryValue {Name = "Enabled" } + } + }, + new ConnectionOption + { + Name = "encrypt", + DisplayName = "Encrypt", + Description = + "When true, SQL Server uses SSL encryption for all data sent between the client and server if the servers has a certificate installed", + GroupName = "Security", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "persistSecurityInfo", + DisplayName = "Persist security info", + Description = "When false, security-sensitive information, such as the password, is not returned as part of the connection", + GroupName = "Security", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "trustServerCertificate", + DisplayName = "Trust server certificate", + Description = "When true (and encrypt=true), SQL Server uses SSL encryption for all data sent between the client and server without validating the server certificate", + GroupName = "Security", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "attachedDBFileName", + DisplayName = "Attached DB file name", + Description = "The name of the primary file, including the full path name, of an attachable database", + ValueType = ConnectionOption.ValueTypeString, + GroupName = "Source" + }, + new ConnectionOption + { + Name = "contextConnection", + DisplayName = "Context connection", + Description = "When true, indicates the connection should be from the SQL server context. Available only when running in the SQL Server process", + ValueType = ConnectionOption.ValueTypeBoolean, + GroupName = "Source" + }, + new ConnectionOption + { + Name = "port", + DisplayName = "Port", + ValueType = ConnectionOption.ValueTypeNumber + }, + new ConnectionOption + { + Name = "connectRetryCount", + DisplayName = "Connect retry count", + Description = "Number of attempts to restore connection", + ValueType = ConnectionOption.ValueTypeNumber, + DefaultValue = "1", + GroupName = "Connection Resiliency" + }, + new ConnectionOption + { + Name = "connectRetryInterval", + DisplayName = "Connect retry interval", + Description = "Delay between attempts to restore connection", + ValueType = ConnectionOption.ValueTypeNumber, + DefaultValue = "10", + GroupName = "Connection Resiliency" + + }, + new ConnectionOption + { + Name = "applicationName", + DisplayName = "Application name", + Description = "The name of the application", + ValueType = ConnectionOption.ValueTypeString, + GroupName = "Context", + SpecialValueType = ConnectionOption.SpecialValueAppName + }, + new ConnectionOption + { + Name = "workstationId", + DisplayName = "Workstation Id", + Description = "The name of the workstation connecting to SQL Server", + ValueType = ConnectionOption.ValueTypeString, + GroupName = "Context" + }, + new ConnectionOption + { + Name = "pooling", + DisplayName = "Pooling", + Description = "When true, the connection object is drawn from the appropriate pool, or if necessary, is created and added to the appropriate pool", + ValueType = ConnectionOption.ValueTypeBoolean, + GroupName = "Pooling" + }, + new ConnectionOption + { + Name = "maxPoolSize", + DisplayName = "Max pool size", + Description = "The maximum number of connections allowed in the pool", + ValueType = ConnectionOption.ValueTypeNumber, + GroupName = "Pooling" + }, + new ConnectionOption + { + Name = "minPoolSize", + DisplayName = "Min pool size", + Description = "The minimum number of connections allowed in the pool", + ValueType = ConnectionOption.ValueTypeNumber, + GroupName = "Pooling" + }, + new ConnectionOption + { + Name = "loadBalanceTimeout", + DisplayName = "Load balance timeout", + Description = "The minimum amount of time (in seconds) for this connection to live in the pool before being destroyed", + ValueType = ConnectionOption.ValueTypeNumber, + GroupName = "Pooling" + }, + new ConnectionOption + { + Name = "replication", + DisplayName = "Replication", + Description = "Used by SQL Server in Replication", + ValueType = ConnectionOption.ValueTypeBoolean, + GroupName = "Replication" + }, + new ConnectionOption + { + Name = "attachDbFilename", + DisplayName = "Attach DB filename", + ValueType = ConnectionOption.ValueTypeString + }, + new ConnectionOption + { + Name = "failoverPartner", + DisplayName = "Failover partner", + Description = "the name or network address of the instance of SQL Server that acts as a failover partner", + ValueType = ConnectionOption.ValueTypeString, + GroupName = " Source" + }, + new ConnectionOption + { + Name = "multiSubnetFailover", + DisplayName = "Multi subnet failover", + ValueType = ConnectionOption.ValueTypeBoolean + }, + new ConnectionOption + { + Name = "multipleActiveResultSets", + DisplayName = "Multiple active result sets", + Description = "When true, multiple result sets can be returned and read from one connection", + ValueType = ConnectionOption.ValueTypeBoolean, + GroupName = "Advanced" + }, + new ConnectionOption + { + Name = "packetSize", + DisplayName = "Packet size", + Description = "Size in bytes of the network packets used to communicate with an instance of SQL Server", + ValueType = ConnectionOption.ValueTypeNumber, + GroupName = "Advanced" + }, + new ConnectionOption + { + Name = "typeSystemVersion", + DisplayName = "Type system version", + Description = "Indicates which server type system then provider will expose through the DataReader", + ValueType = ConnectionOption.ValueTypeString, + GroupName = "Advanced" + } + } + }; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs new file mode 100644 index 0000000000..da287c1d6c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionService.cs @@ -0,0 +1,1513 @@ +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Data.SqlClient; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.SqlServer.Management.Common; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.Admin.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; +using System.Diagnostics; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Main class for the Connection Management services + /// + public class ConnectionService + { + public const string AdminConnectionPrefix = "ADMIN:"; + internal const string PasswordPlaceholder = "******"; + private const string SqlAzureEdition = "SQL Azure"; + + /// + /// Singleton service instance + /// + private static readonly Lazy instance + = new Lazy(() => new ConnectionService()); + + /// + /// Gets the singleton service instance + /// + public static ConnectionService Instance => instance.Value; + + /// + /// The SQL connection factory object + /// + private IDataSourceConnectionFactory connectionFactory; + + private DatabaseLocksManager lockedDatabaseManager; + + /// + /// A map containing all CancellationTokenSource objects that are associated with a given URI/ConnectionType pair. + /// Entries in this map correspond to ReliableDataSourceClient instances that are in the process of connecting. + /// + private readonly ConcurrentDictionary cancelTupleToCancellationTokenSourceMap = + new ConcurrentDictionary(); + + private readonly object cancellationTokenSourceLock = new object(); + + private ConcurrentDictionary connectedQueues = new ConcurrentDictionary(); + + /// + /// Map from script URIs to ConnectionInfo objects + /// This is internal for testing access only + /// + internal Dictionary OwnerToConnectionMap { get; } = new Dictionary(); + + /// + /// Database Lock manager instance + /// + internal DatabaseLocksManager LockedDatabaseManager + { + get + { + if (lockedDatabaseManager == null) + { + lockedDatabaseManager = DatabaseLocksManager.Instance; + } + return lockedDatabaseManager; + } + set + { + this.lockedDatabaseManager = value; + } + } + + /// + /// Service host object for sending/receiving requests/events. + /// Internal for testing purposes. + /// + internal IProtocolEndpoint ServiceHost { get; set; } + + /// + /// Gets the connection queue + /// + internal IConnectedBindingQueue ConnectionQueue + { + get + { + return this.GetConnectedQueue("Default"); + } + } + + + /// + /// Default constructor should be private since it's a singleton class, but we need a constructor + /// for use in unit test mocking. + /// + public ConnectionService() + { + var defaultQueue = new ConnectedBindingQueue(needsMetadata: false); + connectedQueues.AddOrUpdate("Default", defaultQueue, (key, old) => defaultQueue); + this.LockedDatabaseManager.ConnectionService = this; + } + + /// + /// Returns a connection queue for given type + /// + /// + /// + public IConnectedBindingQueue GetConnectedQueue(string type) + { + IConnectedBindingQueue connectedBindingQueue; + if (connectedQueues.TryGetValue(type, out connectedBindingQueue)) + { + return connectedBindingQueue; + } + return null; + } + + /// + /// Returns all the connection queues + /// + public IEnumerable ConnectedQueues + { + get + { + return this.connectedQueues.Values; + } + } + + /// + /// Register a new connection queue if not already registered + /// + /// + /// + public virtual void RegisterConnectedQueue(string type, IConnectedBindingQueue connectedQueue) + { + if (!connectedQueues.ContainsKey(type)) + { + connectedQueues.AddOrUpdate(type, connectedQueue, (key, old) => connectedQueue); + } + } + + /// + /// Callback for onconnection handler + /// + /// + public delegate Task OnConnectionHandler(ConnectionInfo info); + + /// + /// Callback for ondisconnect handler + /// + public delegate Task OnDisconnectHandler(IConnectionSummary summary, string ownerUri); + + /// + /// List of onconnection handlers + /// + private readonly List onConnectionActivities = new List(); + + /// + /// List of ondisconnect handlers + /// + private readonly List onDisconnectActivities = new List(); + + /// + /// Gets the SQL connection factory instance + /// + public IDataSourceConnectionFactory ConnectionFactory + { + get + { + if (this.connectionFactory == null) + { + this.connectionFactory = new DataSourceConnectionFactory(); + } + return this.connectionFactory; + } + + internal set { this.connectionFactory = value; } + } + + /// + /// Test constructor that injects dependency interfaces + /// + /// + public ConnectionService(IDataSourceConnectionFactory testFactory) => this.connectionFactory = testFactory; + + // Attempts to link a URI to an actively used connection for this URI + public virtual bool TryFindConnection(string ownerUri, out ConnectionInfo connectionInfo) => this.OwnerToConnectionMap.TryGetValue(ownerUri, out connectionInfo); + + /// + /// Validates the given ConnectParams object. + /// + /// The params to validate + /// A ConnectionCompleteParams object upon validation error, + /// null upon validation success + public ConnectionCompleteParams ValidateConnectParams(ConnectParams connectionParams) + { + string paramValidationErrorMessage; + if (connectionParams == null) + { + return new ConnectionCompleteParams + { + Messages = SR.ConnectionServiceConnectErrorNullParams + }; + } + if (!connectionParams.IsValid(out paramValidationErrorMessage)) + { + return new ConnectionCompleteParams + { + OwnerUri = connectionParams.OwnerUri, + Messages = paramValidationErrorMessage + }; + } + + // return null upon success + return null; + } + + /// + /// Open a connection with the specified ConnectParams + /// + public virtual async Task Connect(ConnectParams connectionParams) + { + // Validate parameters + ConnectionCompleteParams validationResults = ValidateConnectParams(connectionParams); + if (validationResults != null) + { + return validationResults; + } + + TrySetConnectionType(connectionParams); + + connectionParams.Connection.ApplicationName = GetApplicationNameWithFeature(connectionParams.Connection.ApplicationName, connectionParams.Purpose); + // If there is no ConnectionInfo in the map, create a new ConnectionInfo, + // but wait until later when we are connected to add it to the map. + ConnectionInfo connectionInfo; + bool connectionChanged = false; + if (!OwnerToConnectionMap.TryGetValue(connectionParams.OwnerUri, out connectionInfo)) + { + connectionInfo = new ConnectionInfo(ConnectionFactory, connectionParams.OwnerUri, connectionParams.Connection); + } + else if (IsConnectionChanged(connectionParams, connectionInfo)) + { + // We are actively changing the connection information for this connection. We must disconnect + // all active connections, since it represents a full context change + connectionChanged = true; + } + + DisconnectExistingConnectionIfNeeded(connectionParams, connectionInfo, disconnectAll: connectionChanged); + + if (connectionChanged) + { + connectionInfo = new ConnectionInfo(ConnectionFactory, connectionParams.OwnerUri, connectionParams.Connection); + } + + // Try to open a connection with the given ConnectParams + ConnectionCompleteParams response = await TryOpenConnection(connectionInfo, connectionParams); + if (response != null) + { + return response; + } + + // If this is the first connection for this URI, add the ConnectionInfo to the map + bool addToMap = connectionChanged || !OwnerToConnectionMap.ContainsKey(connectionParams.OwnerUri); + if (addToMap) + { + OwnerToConnectionMap[connectionParams.OwnerUri] = connectionInfo; + } + + // Return information about the connected SQL Server instance + ConnectionCompleteParams completeParams = GetConnectionCompleteParams(connectionParams.Type, connectionInfo); + // Invoke callback notifications + InvokeOnConnectionActivities(connectionInfo, connectionParams); + + TryCloseConnectionTemporaryConnection(connectionParams, connectionInfo); + + return completeParams; + } + + private void TryCloseConnectionTemporaryConnection(ConnectParams connectionParams, ConnectionInfo connectionInfo) + { + try + { + if (connectionParams.Purpose == ConnectionType.ObjectExplorer || connectionParams.Purpose == ConnectionType.Dashboard || connectionParams.Purpose == ConnectionType.GeneralConnection) + { + ReliableDataSourceConnection connection; + string type = connectionParams.Type; + if (connectionInfo.TryGetConnection(type, out connection)) + { + // OE doesn't need to keep the connection open + connection.Close(); + } + } + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Information, "Failed to close temporary connections. error: " + ex.Message); + } + } + + private static string GetApplicationNameWithFeature(string applicationName, string featureName) + { + string appNameWithFeature = applicationName; + + if (!string.IsNullOrWhiteSpace(applicationName) && !string.IsNullOrWhiteSpace(featureName)) + { + int index = applicationName.IndexOf('-'); + string appName = applicationName; + if (index > 0) + { + appName = applicationName.Substring(0, index); + } + appNameWithFeature = $"{appName}-{featureName}"; + } + + return appNameWithFeature; + } + + private void TrySetConnectionType(ConnectParams connectionParams) + { + if (connectionParams != null && connectionParams.Type == ConnectionType.Default && !string.IsNullOrWhiteSpace(connectionParams.OwnerUri)) + { + if (connectionParams.OwnerUri.ToLowerInvariant().StartsWith("dashboard://")) + { + connectionParams.Purpose = ConnectionType.Dashboard; + } + else if (connectionParams.OwnerUri.ToLowerInvariant().StartsWith("connection://")) + { + connectionParams.Purpose = ConnectionType.GeneralConnection; + } + } + else if (connectionParams != null) + { + connectionParams.Purpose = connectionParams.Type; + } + } + + private bool IsConnectionChanged(ConnectParams connectionParams, ConnectionInfo connectionInfo) + { + if (connectionInfo.HasConnectionType(connectionParams.Type) + && !connectionInfo.ConnectionDetails.IsComparableTo(connectionParams.Connection)) + { + return true; + } + return false; + } + + private bool IsDefaultConnectionType(string connectionType) + { + return string.IsNullOrEmpty(connectionType) || ConnectionType.Default.Equals(connectionType, StringComparison.CurrentCultureIgnoreCase); + } + + private void DisconnectExistingConnectionIfNeeded(ConnectParams connectionParams, ConnectionInfo connectionInfo, bool disconnectAll) + { + // Resolve if it is an existing connection + // Disconnect active connection if the URI is already connected for this connection type + ReliableDataSourceConnection existingConnection; + if (connectionInfo.TryGetConnection(connectionParams.Type, out existingConnection)) + { + var disconnectParams = new DisconnectParams() + { + OwnerUri = connectionParams.OwnerUri, + Type = disconnectAll ? null : connectionParams.Type + }; + Disconnect(disconnectParams); + } + } + + /// + /// Creates a ConnectionCompleteParams as a response to a successful connection. + /// Also sets the DatabaseName and IsAzure properties of ConnectionInfo. + /// + /// A ConnectionCompleteParams in response to the successful connection + private ConnectionCompleteParams GetConnectionCompleteParams(string connectionType, ConnectionInfo connectionInfo) + { + ConnectionCompleteParams response = new ConnectionCompleteParams { OwnerUri = connectionInfo.OwnerUri, Type = connectionType }; + + try + { + ReliableDataSourceConnection connection; + connectionInfo.TryGetConnection(connectionType, out connection); + + // Update with the actual database name in connectionInfo and result + // Doing this here as we know the connection is open - expect to do this only on connecting + connectionInfo.ConnectionDetails.DatabaseName = connection.Database; + if (!string.IsNullOrEmpty(connectionInfo.ConnectionDetails.ConnectionString)) + { + // If the connection was set up with a connection string, use the connection string to get the details + var connectionString = new SqlConnectionStringBuilder(connection.ConnectionString); + response.ConnectionSummary = new ConnectionSummary + { + ServerName = connectionString.DataSource, + DatabaseName = connectionString.InitialCatalog, + UserName = connectionString.UserID + }; + } + else + { + response.ConnectionSummary = new ConnectionSummary + { + ServerName = connectionInfo.ConnectionDetails.ServerName, + DatabaseName = connectionInfo.ConnectionDetails.DatabaseName, + UserName = connectionInfo.ConnectionDetails.UserName + }; + } + + response.ConnectionId = connectionInfo.ConnectionId.ToString(); + + var reliableConnection = connection as ReliableDataSourceConnection; + IDataSource dataSource = reliableConnection.GetUnderlyingConnection(); + DataSourceObjectMetadata clusterMetadata = DataSourceFactory.CreateClusterMetadata(connectionInfo.ConnectionDetails.ServerName); + + DiagnosticsInfo clusterDiagnostics = dataSource.GetDiagnostics(clusterMetadata); + ReliableConnectionHelper.ServerInfo serverInfo = DataSourceFactory.ConvertToServerinfoFormat(DataSourceType.Kusto, clusterDiagnostics); + + response.ServerInfo = new ServerInfo + { + Options = serverInfo.Options // Server properties are shown on "manage" dashboard. + }; + connectionInfo.IsCloud = response.ServerInfo.IsCloud; + connectionInfo.MajorVersion = response.ServerInfo.ServerMajorVersion; + } + catch (Exception ex) + { + response.Messages = ex.ToString(); + } + + return response; + } + + /// + /// Tries to create and open a connection with the given ConnectParams. + /// + /// null upon success, a ConnectionCompleteParams detailing the error upon failure + private async Task TryOpenConnection(ConnectionInfo connectionInfo, ConnectParams connectionParams) + { + CancellationTokenSource source = null; + ReliableDataSourceConnection connection = null; + CancelTokenKey cancelKey = new CancelTokenKey { OwnerUri = connectionParams.OwnerUri, Type = connectionParams.Type }; + ConnectionCompleteParams response = new ConnectionCompleteParams { OwnerUri = connectionInfo.OwnerUri, Type = connectionParams.Type }; + bool? currentPooling = connectionInfo.ConnectionDetails.Pooling; + + try + { + connectionInfo.ConnectionDetails.Pooling = false; + // build the connection string from the input parameters + string connectionString = BuildConnectionString(connectionInfo.ConnectionDetails); + + // create a sql connection instance + connection = connectionInfo.Factory.CreateDataSourceConnection(connectionString, connectionInfo.ConnectionDetails.AzureAccountToken); + connectionInfo.AddConnection(connectionParams.Type, connection); + + // Add a cancellation token source so that the connection OpenAsync() can be cancelled + source = new CancellationTokenSource(); + // Locking here to perform two operations as one atomic operation + lock (cancellationTokenSourceLock) + { + // If the URI is currently connecting from a different request, cancel it before we try to connect + CancellationTokenSource currentSource; + if (cancelTupleToCancellationTokenSourceMap.TryGetValue(cancelKey, out currentSource)) + { + currentSource.Cancel(); + } + cancelTupleToCancellationTokenSourceMap[cancelKey] = source; + } + + // Open the connection + await connection.OpenAsync(source.Token); + } + catch (SqlException ex) + { + response.ErrorNumber = ex.Number; + response.ErrorMessage = ex.Message; + response.Messages = ex.ToString(); + return response; + } + catch (OperationCanceledException) + { + // OpenAsync was cancelled + response.Messages = SR.ConnectionServiceConnectionCanceled; + return response; + } + catch (Exception ex) + { + response.ErrorMessage = ex.Message; + response.Messages = ex.ToString(); + return response; + } + finally + { + // Remove our cancellation token from the map since we're no longer connecting + // Using a lock here to perform two operations as one atomic operation + lock (cancellationTokenSourceLock) + { + // Only remove the token from the map if it is the same one created by this request + CancellationTokenSource sourceValue; + if (cancelTupleToCancellationTokenSourceMap.TryGetValue(cancelKey, out sourceValue) && sourceValue == source) + { + cancelTupleToCancellationTokenSourceMap.TryRemove(cancelKey, out sourceValue); + } + source?.Dispose(); + } + if (connectionInfo != null && connectionInfo.ConnectionDetails != null) + { + connectionInfo.ConnectionDetails.Pooling = currentPooling; + } + } + + // Return null upon success + return null; + } + + /// + /// Gets the existing connection with the given URI and connection type string. If none exists, + /// creates a new connection. This cannot be used to create a default connection or to create a + /// connection if a default connection does not exist. + /// + /// URI identifying the resource mapped to this connection + /// + /// What the purpose for this connection is. A single resource + /// such as a SQL file may have multiple connections - one for Intellisense, another for query execution + /// + /// + /// Workaround for .Net Core clone connection issues: should persist security be used so that + /// when SMO clones connections it can do so without breaking on SQL Password connections. + /// This should be removed once the core issue is resolved and clone works as expected + /// + /// A DB connection for the connection type requested + public virtual async Task GetOrOpenConnection(string ownerUri, string connectionType, bool alwaysPersistSecurity = false) + { + Validate.IsNotNullOrEmptyString(nameof(ownerUri), ownerUri); + Validate.IsNotNullOrEmptyString(nameof(connectionType), connectionType); + + // Try to get the ConnectionInfo, if it exists + ConnectionInfo connectionInfo; + if (!OwnerToConnectionMap.TryGetValue(ownerUri, out connectionInfo)) + { + throw new ArgumentOutOfRangeException(SR.ConnectionServiceListDbErrorNotConnected(ownerUri)); + } + + // Make sure a default connection exists + ReliableDataSourceConnection connection; + ReliableDataSourceConnection defaultConnection; + if (!connectionInfo.TryGetConnection(ConnectionType.Default, out defaultConnection)) + { + throw new InvalidOperationException(SR.ConnectionServiceDbErrorDefaultNotConnected(ownerUri)); + } + + if (IsDedicatedAdminConnection(connectionInfo.ConnectionDetails)) + { + // Since this is a dedicated connection only 1 is allowed at any time. Return the default connection for use in the requested action + connection = defaultConnection; + } + else + { + // Try to get the ReliableDataSourceClient and create if it doesn't already exist + if (!connectionInfo.TryGetConnection(connectionType, out connection) && ConnectionType.Default != connectionType) + { + connection = await TryOpenConnectionForConnectionType(ownerUri, connectionType, alwaysPersistSecurity, connectionInfo); + } + } + + return connection; + } + + private async Task TryOpenConnectionForConnectionType(string ownerUri, string connectionType, + bool alwaysPersistSecurity, ConnectionInfo connectionInfo) + { + // If the ReliableDataSourceClient does not exist and is not the default connection, create one. + // We can't create the default (initial) connection here because we won't have a ConnectionDetails + // if Connect() has not yet been called. + bool? originalPersistSecurityInfo = connectionInfo.ConnectionDetails.PersistSecurityInfo; + if (alwaysPersistSecurity) + { + connectionInfo.ConnectionDetails.PersistSecurityInfo = true; + } + ConnectParams connectParams = new ConnectParams + { + OwnerUri = ownerUri, + Connection = connectionInfo.ConnectionDetails, + Type = connectionType + }; + try + { + await Connect(connectParams); + } + finally + { + connectionInfo.ConnectionDetails.PersistSecurityInfo = originalPersistSecurityInfo; + } + + ReliableDataSourceConnection connection; + connectionInfo.TryGetConnection(connectionType, out connection); + return connection; + } + + /// + /// Cancel a connection that is in the process of opening. + /// + public bool CancelConnect(CancelConnectParams cancelParams) + { + // Validate parameters + if (cancelParams == null || string.IsNullOrEmpty(cancelParams.OwnerUri)) + { + return false; + } + + CancelTokenKey cancelKey = new CancelTokenKey + { + OwnerUri = cancelParams.OwnerUri, + Type = cancelParams.Type + }; + + // Cancel any current connection attempts for this URI + CancellationTokenSource source; + if (cancelTupleToCancellationTokenSourceMap.TryGetValue(cancelKey, out source)) + { + try + { + source.Cancel(); + return true; + } + catch + { + return false; + } + } + + return false; + } + + /// + /// Close a connection with the specified connection details. + /// + public virtual bool Disconnect(DisconnectParams disconnectParams) + { + // Validate parameters + if (disconnectParams == null || string.IsNullOrEmpty(disconnectParams.OwnerUri)) + { + return false; + } + + // Cancel if we are in the middle of connecting + if (CancelConnections(disconnectParams.OwnerUri, disconnectParams.Type)) + { + return false; + } + + // Lookup the ConnectionInfo owned by the URI + ConnectionInfo info; + if (!OwnerToConnectionMap.TryGetValue(disconnectParams.OwnerUri, out info)) + { + return false; + } + + // Call Close() on the connections we want to disconnect + // If no connections were located, return false + if (!CloseConnections(info, disconnectParams.Type)) + { + return false; + } + + // Remove the disconnected connections from the ConnectionInfo map + if (disconnectParams.Type == null) + { + info.RemoveAllConnections(); + } + else + { + info.RemoveConnection(disconnectParams.Type); + } + + // If the ConnectionInfo has no more connections, remove the ConnectionInfo + if (info.CountConnections == 0) + { + OwnerToConnectionMap.Remove(disconnectParams.OwnerUri); + } + + // Handle Telemetry disconnect events if we are disconnecting the default connection + if (disconnectParams.Type == null || disconnectParams.Type == ConnectionType.Default) + { + HandleDisconnectTelemetry(info); + InvokeOnDisconnectionActivities(info); + } + + // Return true upon success + return true; + } + + /// + /// Cancel connections associated with the given ownerUri. + /// If connectionType is not null, cancel the connection with the given connectionType + /// If connectionType is null, cancel all pending connections associated with ownerUri. + /// + /// true if a single pending connection associated with the non-null connectionType was + /// found and cancelled, false otherwise + private bool CancelConnections(string ownerUri, string connectionType) + { + // Cancel the connection of the given type + if (connectionType != null) + { + // If we are trying to disconnect a specific connection and it was just cancelled, + // this will return true + return CancelConnect(new CancelConnectParams() { OwnerUri = ownerUri, Type = connectionType }); + } + + // Cancel all pending connections + foreach (var entry in cancelTupleToCancellationTokenSourceMap) + { + string entryConnectionUri = entry.Key.OwnerUri; + string entryConnectionType = entry.Key.Type; + if (ownerUri.Equals(entryConnectionUri)) + { + CancelConnect(new CancelConnectParams() { OwnerUri = ownerUri, Type = entryConnectionType }); + } + } + + return false; + } + + /// + /// Closes DbConnections associated with the given ConnectionInfo. + /// If connectionType is not null, closes the ReliableDataSourceClient with the type given by connectionType. + /// If connectionType is null, closes all DbConnections. + /// + /// true if connections were found and attempted to be closed, + /// false if no connections were found + private bool CloseConnections(ConnectionInfo connectionInfo, string connectionType) + { + ICollection connectionsToDisconnect = new List(); + if (connectionType == null) + { + connectionsToDisconnect = connectionInfo.AllConnections; + } + else + { + // Make sure there is an existing connection of this type + ReliableDataSourceConnection connection; + if (!connectionInfo.TryGetConnection(connectionType, out connection)) + { + return false; + } + connectionsToDisconnect.Add(connection); + } + + if (connectionsToDisconnect.Count == 0) + { + return false; + } + + foreach (ReliableDataSourceConnection connection in connectionsToDisconnect) + { + try + { + connection.Close(); + } + catch (Exception) + { + // Ignore + } + } + + return true; + } + + /// + /// List all databases on the server specified + /// + public ListDatabasesResponse ListDatabases(ListDatabasesParams listDatabasesParams) + { + // Verify parameters + var owner = listDatabasesParams.OwnerUri; + if (string.IsNullOrEmpty(owner)) + { + throw new ArgumentException(SR.ConnectionServiceListDbErrorNullOwnerUri); + } + + // Use the existing connection as a base for the search + ConnectionInfo info; + if (!TryFindConnection(owner, out info)) + { + throw new Exception(SR.ConnectionServiceListDbErrorNotConnected(owner)); + } + ConnectionDetails connectionDetails = info.ConnectionDetails.Clone(); + + IDataSource dataSource = OpenDataSourceConnection(info); + DataSourceObjectMetadata objectMetadata = DataSourceFactory.CreateClusterMetadata(info.ConnectionDetails.ServerName); + + ListDatabasesResponse response = new ListDatabasesResponse(); + + // Mainly used by "manage" dashboard + if(listDatabasesParams.IncludeDetails.HasTrue()){ + IEnumerable databaseMetadataInfo = dataSource.GetChildObjects(objectMetadata, true); + List metadata = DataSourceFactory.ConvertToDatabaseInfo(databaseMetadataInfo); + response.Databases = metadata.ToArray(); + + return response; + } + + IEnumerable databaseMetadata = dataSource.GetChildObjects(objectMetadata); + if(databaseMetadata != null) response.DatabaseNames = databaseMetadata.Select(objMeta => objMeta.PrettyName).ToArray(); + return response; + } + + public void InitializeService(IProtocolEndpoint serviceHost) + { + this.ServiceHost = serviceHost; + + // Register request and event handlers with the Service Host + serviceHost.SetRequestHandler(ConnectionRequest.Type, HandleConnectRequest); + serviceHost.SetRequestHandler(CancelConnectRequest.Type, HandleCancelConnectRequest); + serviceHost.SetRequestHandler(DisconnectRequest.Type, HandleDisconnectRequest); + serviceHost.SetRequestHandler(ListDatabasesRequest.Type, HandleListDatabasesRequest); + serviceHost.SetRequestHandler(ChangeDatabaseRequest.Type, HandleChangeDatabaseRequest); + serviceHost.SetRequestHandler(GetConnectionStringRequest.Type, HandleGetConnectionStringRequest); + serviceHost.SetRequestHandler(BuildConnectionInfoRequest.Type, HandleBuildConnectionInfoRequest); + } + + /// + /// Add a new method to be called when the onconnection request is submitted + /// + /// + public void RegisterOnConnectionTask(OnConnectionHandler activity) + { + onConnectionActivities.Add(activity); + } + + /// + /// Add a new method to be called when the ondisconnect request is submitted + /// + public void RegisterOnDisconnectTask(OnDisconnectHandler activity) + { + onDisconnectActivities.Add(activity); + } + + /// + /// Handle new connection requests + /// + /// + /// + /// + protected async Task HandleConnectRequest( + ConnectParams connectParams, + RequestContext requestContext) + { + Logger.Write(TraceEventType.Verbose, "HandleConnectRequest"); + + try + { + RunConnectRequestHandlerTask(connectParams); + await requestContext.SendResult(true); + } + catch + { + await requestContext.SendResult(false); + } + } + + private void RunConnectRequestHandlerTask(ConnectParams connectParams) + { + // create a task to connect asynchronously so that other requests are not blocked in the meantime + Task.Run(async () => + { + try + { + // result is null if the ConnectParams was successfully validated + ConnectionCompleteParams result = ValidateConnectParams(connectParams); + if (result != null) + { + await ServiceHost.SendEvent(ConnectionCompleteNotification.Type, result); + return; + } + + // open connection based on request details + result = await Connect(connectParams); + await ServiceHost.SendEvent(ConnectionCompleteNotification.Type, result); + } + catch (Exception ex) + { + ConnectionCompleteParams result = new ConnectionCompleteParams() + { + Messages = ex.ToString() + }; + await ServiceHost.SendEvent(ConnectionCompleteNotification.Type, result); + } + }).ContinueWithOnFaulted(null); + } + + /// + /// Handle cancel connect requests + /// + protected async Task HandleCancelConnectRequest( + CancelConnectParams cancelParams, + RequestContext requestContext) + { + Logger.Write(TraceEventType.Verbose, "HandleCancelConnectRequest"); + + try + { + bool result = CancelConnect(cancelParams); + await requestContext.SendResult(result); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Handle disconnect requests + /// + protected async Task HandleDisconnectRequest( + DisconnectParams disconnectParams, + RequestContext requestContext) + { + Logger.Write(TraceEventType.Verbose, "HandleDisconnectRequest"); + + try + { + bool result = Instance.Disconnect(disconnectParams); + await requestContext.SendResult(result); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + + } + + /// + /// Handle requests to list databases on the current server + /// + protected async Task HandleListDatabasesRequest( + ListDatabasesParams listDatabasesParams, + RequestContext requestContext) + { + Logger.Write(TraceEventType.Verbose, "ListDatabasesRequest"); + + try + { + ListDatabasesResponse result = ListDatabases(listDatabasesParams); + await requestContext.SendResult(result); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Checks if a ConnectionDetails object represents a DAC connection + /// + /// + public static bool IsDedicatedAdminConnection(ConnectionDetails connectionDetails) + { + Validate.IsNotNull(nameof(connectionDetails), connectionDetails); + SqlConnectionStringBuilder builder = CreateConnectionStringBuilder(connectionDetails); + string serverName = builder.DataSource; + return serverName != null && serverName.StartsWith(AdminConnectionPrefix, StringComparison.OrdinalIgnoreCase); + } + + /// + /// Build a connection string from a connection details instance + /// + /// + public static string BuildConnectionString(ConnectionDetails connectionDetails) + { + return CreateConnectionStringBuilder(connectionDetails).ToString(); + } + + /// + /// Build a connection string builder a connection details instance + /// + /// + public static SqlConnectionStringBuilder CreateConnectionStringBuilder(ConnectionDetails connectionDetails) + { + SqlConnectionStringBuilder connectionBuilder; + + // If connectionDetails has a connection string already, use it to initialize the connection builder, then override any provided options. + // Otherwise use the server name, username, and password from the connection details. + if (!string.IsNullOrEmpty(connectionDetails.ConnectionString)) + { + connectionBuilder = new SqlConnectionStringBuilder(connectionDetails.ConnectionString); + } + else + { + // add alternate port to data source property if provided + string dataSource = !connectionDetails.Port.HasValue + ? connectionDetails.ServerName + : string.Format("{0},{1}", connectionDetails.ServerName, connectionDetails.Port.Value); + + connectionBuilder = new SqlConnectionStringBuilder + { + ["Data Source"] = dataSource, + ["User Id"] = connectionDetails.UserName, + ["Password"] = connectionDetails.Password + }; + } + + // Check for any optional parameters + if (!string.IsNullOrEmpty(connectionDetails.DatabaseName)) + { + connectionBuilder["Initial Catalog"] = connectionDetails.DatabaseName; + } + if (!string.IsNullOrEmpty(connectionDetails.AuthenticationType)) + { + switch (connectionDetails.AuthenticationType) + { + case "Integrated": + connectionBuilder.IntegratedSecurity = true; + break; + case "SqlLogin": + break; + case "AzureMFA": + connectionBuilder.UserID = ""; + connectionBuilder.Password = ""; + break; + default: + throw new ArgumentException(SR.ConnectionServiceConnStringInvalidAuthType(connectionDetails.AuthenticationType)); + } + } + if (connectionDetails.Encrypt.HasValue) + { + connectionBuilder.Encrypt = connectionDetails.Encrypt.Value; + } + if (connectionDetails.TrustServerCertificate.HasValue) + { + connectionBuilder.TrustServerCertificate = connectionDetails.TrustServerCertificate.Value; + } + if (connectionDetails.PersistSecurityInfo.HasValue) + { + connectionBuilder.PersistSecurityInfo = connectionDetails.PersistSecurityInfo.Value; + } + if (connectionDetails.ConnectTimeout.HasValue) + { + connectionBuilder.ConnectTimeout = connectionDetails.ConnectTimeout.Value; + } + if (connectionDetails.ConnectRetryCount.HasValue) + { + connectionBuilder.ConnectRetryCount = connectionDetails.ConnectRetryCount.Value; + } + if (connectionDetails.ConnectRetryInterval.HasValue) + { + connectionBuilder.ConnectRetryInterval = connectionDetails.ConnectRetryInterval.Value; + } + if (!string.IsNullOrEmpty(connectionDetails.ApplicationName)) + { + connectionBuilder.ApplicationName = connectionDetails.ApplicationName; + } + if (!string.IsNullOrEmpty(connectionDetails.WorkstationId)) + { + connectionBuilder.WorkstationID = connectionDetails.WorkstationId; + } + if (!string.IsNullOrEmpty(connectionDetails.ApplicationIntent)) + { + ApplicationIntent intent; + switch (connectionDetails.ApplicationIntent) + { + case "ReadOnly": + intent = ApplicationIntent.ReadOnly; + break; + case "ReadWrite": + intent = ApplicationIntent.ReadWrite; + break; + default: + throw new ArgumentException(SR.ConnectionServiceConnStringInvalidIntent(connectionDetails.ApplicationIntent)); + } + connectionBuilder.ApplicationIntent = intent; + } + if (!string.IsNullOrEmpty(connectionDetails.CurrentLanguage)) + { + connectionBuilder.CurrentLanguage = connectionDetails.CurrentLanguage; + } + if (connectionDetails.Pooling.HasValue) + { + connectionBuilder.Pooling = connectionDetails.Pooling.Value; + } + if (connectionDetails.MaxPoolSize.HasValue) + { + connectionBuilder.MaxPoolSize = connectionDetails.MaxPoolSize.Value; + } + if (connectionDetails.MinPoolSize.HasValue) + { + connectionBuilder.MinPoolSize = connectionDetails.MinPoolSize.Value; + } + if (connectionDetails.LoadBalanceTimeout.HasValue) + { + connectionBuilder.LoadBalanceTimeout = connectionDetails.LoadBalanceTimeout.Value; + } + if (connectionDetails.Replication.HasValue) + { + connectionBuilder.Replication = connectionDetails.Replication.Value; + } + if (!string.IsNullOrEmpty(connectionDetails.AttachDbFilename)) + { + connectionBuilder.AttachDBFilename = connectionDetails.AttachDbFilename; + } + if (!string.IsNullOrEmpty(connectionDetails.FailoverPartner)) + { + connectionBuilder.FailoverPartner = connectionDetails.FailoverPartner; + } + if (connectionDetails.MultiSubnetFailover.HasValue) + { + connectionBuilder.MultiSubnetFailover = connectionDetails.MultiSubnetFailover.Value; + } + if (connectionDetails.MultipleActiveResultSets.HasValue) + { + connectionBuilder.MultipleActiveResultSets = connectionDetails.MultipleActiveResultSets.Value; + } + if (connectionDetails.PacketSize.HasValue) + { + connectionBuilder.PacketSize = connectionDetails.PacketSize.Value; + } + if (!string.IsNullOrEmpty(connectionDetails.TypeSystemVersion)) + { + connectionBuilder.TypeSystemVersion = connectionDetails.TypeSystemVersion; + } + connectionBuilder.Pooling = false; + + return connectionBuilder; + } + + /// + /// Handles a request to get a connection string for the provided connection + /// + public async Task HandleGetConnectionStringRequest( + GetConnectionStringParams connStringParams, + RequestContext requestContext) + { + await Task.Run(async () => + { + string connectionString = string.Empty; + ConnectionInfo info; + if (TryFindConnection(connStringParams.OwnerUri, out info)) + { + try + { + if (!connStringParams.IncludePassword) + { + info.ConnectionDetails.Password = ConnectionService.PasswordPlaceholder; + } + + info.ConnectionDetails.ApplicationName = "sqlops-connection-string"; + + connectionString = BuildConnectionString(info.ConnectionDetails); + } + catch (Exception e) + { + await requestContext.SendError(e.ToString()); + } + } + + await requestContext.SendResult(connectionString); + }); + } + + /// + /// Handles a request to serialize a connection string + /// + public async Task HandleBuildConnectionInfoRequest( + string connectionString, + RequestContext requestContext) + { + await Task.Run(async () => + { + try + { + await requestContext.SendResult(ParseConnectionString(connectionString)); + } + catch (Exception) + { + // If theres an error in the parse, it means we just can't parse, so we return undefined + // rather than an error. + await requestContext.SendResult(null); + } + }); + } + + public ConnectionDetails ParseConnectionString(string connectionString) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(connectionString); + ConnectionDetails details = new ConnectionDetails() + { + ApplicationIntent = builder.ApplicationIntent.ToString(), + ApplicationName = builder.ApplicationName, + AttachDbFilename = builder.AttachDBFilename, + AuthenticationType = builder.IntegratedSecurity ? "Integrated" : "SqlLogin", + ConnectRetryCount = builder.ConnectRetryCount, + ConnectRetryInterval = builder.ConnectRetryInterval, + ConnectTimeout = builder.ConnectTimeout, + CurrentLanguage = builder.CurrentLanguage, + DatabaseName = builder.InitialCatalog, + Encrypt = builder.Encrypt, + FailoverPartner = builder.FailoverPartner, + LoadBalanceTimeout = builder.LoadBalanceTimeout, + MaxPoolSize = builder.MaxPoolSize, + MinPoolSize = builder.MinPoolSize, + MultipleActiveResultSets = builder.MultipleActiveResultSets, + MultiSubnetFailover = builder.MultiSubnetFailover, + PacketSize = builder.PacketSize, + Password = !builder.IntegratedSecurity ? builder.Password : string.Empty, + PersistSecurityInfo = builder.PersistSecurityInfo, + Pooling = builder.Pooling, + Replication = builder.Replication, + ServerName = builder.DataSource, + TrustServerCertificate = builder.TrustServerCertificate, + TypeSystemVersion = builder.TypeSystemVersion, + UserName = builder.UserID, + WorkstationId = builder.WorkstationID, + }; + + return details; + } + + /// + /// Handles a request to change the database for a connection + /// + public async Task HandleChangeDatabaseRequest( + ChangeDatabaseParams changeDatabaseParams, + RequestContext requestContext) + { + await requestContext.SendResult(ChangeConnectionDatabaseContext(changeDatabaseParams.OwnerUri, changeDatabaseParams.NewDatabase, true)); + } + + /// + /// Change the database context of a connection. + /// + /// URI of the owner of the connection + /// Name of the database to change the connection to + public bool ChangeConnectionDatabaseContext(string ownerUri, string newDatabaseName, bool force = false) + { + ConnectionInfo info; + if (TryFindConnection(ownerUri, out info)) + { + try + { + info.ConnectionDetails.DatabaseName = newDatabaseName; + + foreach (string key in info.AllConnectionTypes) + { + ReliableDataSourceConnection conn; + info.TryGetConnection(key, out conn); + if (conn != null && conn.Database != newDatabaseName) + { + if (info.IsCloud && force) + { + conn.Close(); + conn.Dispose(); + info.RemoveConnection(key); + + string connectionString = BuildConnectionString(info.ConnectionDetails); + + // create a sql connection instance + ReliableDataSourceConnection connection = info.Factory.CreateDataSourceConnection(connectionString, info.ConnectionDetails.AzureAccountToken); + connection.Open(); + info.AddConnection(key, connection); + } + else + { + conn.ChangeDatabase(newDatabaseName); + } + } + + } + + // Fire a connection changed event + ConnectionChangedParams parameters = new ConnectionChangedParams(); + IConnectionSummary summary = info.ConnectionDetails; + parameters.Connection = summary.Clone(); + parameters.OwnerUri = ownerUri; + ServiceHost.SendEvent(ConnectionChangedNotification.Type, parameters); + return true; + } + catch (Exception e) + { + Logger.Write( + TraceEventType.Error, + string.Format( + "Exception caught while trying to change database context to [{0}] for OwnerUri [{1}]. Exception:{2}", + newDatabaseName, + ownerUri, + e.ToString()) + ); + } + } + return false; + } + + /// + /// Invokes the initial on-connect activities if the provided ConnectParams represents the default + /// connection. + /// + private void InvokeOnConnectionActivities(ConnectionInfo connectionInfo, ConnectParams connectParams) + { + if (connectParams.Type != ConnectionType.Default && connectParams.Type != ConnectionType.GeneralConnection) + { + return; + } + + foreach (var activity in this.onConnectionActivities) + { + // not awaiting here to allow handlers to run in the background + activity(connectionInfo); + } + } + + /// + /// Invokes the final on-disconnect activities if the provided DisconnectParams represents the default + /// connection or is null - representing that all connections are being disconnected. + /// + private void InvokeOnDisconnectionActivities(ConnectionInfo connectionInfo) + { + foreach (var activity in this.onDisconnectActivities) + { + activity(connectionInfo.ConnectionDetails, connectionInfo.OwnerUri); + } + } + + /// + /// Handles the Telemetry events that occur upon disconnect. + /// + /// + private void HandleDisconnectTelemetry(ConnectionInfo connectionInfo) + { + if (ServiceHost != null) + { + try + { + // Send a telemetry notification for intellisense performance metrics + ServiceHost.SendEvent(TelemetryNotification.Type, new TelemetryParams() + { + Params = new TelemetryProperties + { + Properties = new Dictionary + { + { TelemetryPropertyNames.IsAzure, connectionInfo.IsCloud.ToOneOrZeroString() } + }, + EventName = TelemetryEventNames.IntellisenseQuantile, + Measures = connectionInfo.IntellisenseMetrics.Quantile + } + }); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Verbose, "Could not send Connection telemetry event " + ex.ToString()); + } + } + } + + /// + /// Create and open a new SqlConnection from a ConnectionInfo object + /// Note: we need to audit all uses of this method to determine why we're + /// bypassing normal ConnectionService connection management + /// + /// The connection info to connect with + /// A plaintext string that will be included in the application name for the connection + /// A SqlConnection created with the given connection info + internal static SqlConnection OpenSqlConnection(ConnectionInfo connInfo, string featureName = null) + { + try + { + // capture original values + int? originalTimeout = connInfo.ConnectionDetails.ConnectTimeout; + bool? originalPersistSecurityInfo = connInfo.ConnectionDetails.PersistSecurityInfo; + bool? originalPooling = connInfo.ConnectionDetails.Pooling; + + // increase the connection timeout to at least 30 seconds and and build connection string + connInfo.ConnectionDetails.ConnectTimeout = Math.Max(30, originalTimeout ?? 0); + // enable PersistSecurityInfo to handle issues in SMO where the connection context is lost in reconnections + connInfo.ConnectionDetails.PersistSecurityInfo = true; + // turn off connection pool to avoid hold locks on server resources after calling SqlConnection Close method + connInfo.ConnectionDetails.Pooling = false; + connInfo.ConnectionDetails.ApplicationName = GetApplicationNameWithFeature(connInfo.ConnectionDetails.ApplicationName, featureName); + + // generate connection string + string connectionString = BuildConnectionString(connInfo.ConnectionDetails); + + // restore original values + connInfo.ConnectionDetails.ConnectTimeout = originalTimeout; + connInfo.ConnectionDetails.PersistSecurityInfo = originalPersistSecurityInfo; + connInfo.ConnectionDetails.Pooling = originalPooling; + + // open a dedicated binding server connection + using (SqlConnection sqlConn = new SqlConnection(connectionString)) + { + // Fill in Azure authentication token if needed + if (connInfo.ConnectionDetails.AzureAccountToken != null) + { + sqlConn.AccessToken = connInfo.ConnectionDetails.AzureAccountToken; + } + + sqlConn.Open(); + return sqlConn; + } + } + catch (Exception ex) + { + string error = string.Format(CultureInfo.InvariantCulture, + "Failed opening a SqlConnection: error:{0} inner:{1} stacktrace:{2}", + ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty, ex.StackTrace); + Logger.Write(TraceEventType.Error, error); + } + + return null; + } + + /// + /// Create and open a new SqlConnection from a ConnectionInfo object + /// Note: we need to audit all uses of this method to determine why we're + /// bypassing normal ConnectionService connection management + /// + /// The connection info to connect with + /// A plaintext string that will be included in the application name for the connection + /// A SqlConnection created with the given connection info + internal static IDataSource OpenDataSourceConnection(ConnectionInfo connInfo, string featureName = null) + { + try + { + // generate connection string + string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails); + + // TODOKusto: Pass in type of DataSource needed to make this generic. Hard coded to Kusto right now. + return DataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken); + } + catch (Exception ex) + { + string error = string.Format(CultureInfo.InvariantCulture, + "Failed opening a DataSource of type {0}: error:{1} inner:{2} stacktrace:{3}", + DataSourceType.Kusto, ex.Message, ex.InnerException != null ? ex.InnerException.Message : string.Empty, ex.StackTrace); + Logger.Write(TraceEventType.Error, error); + } + + return null; + } + + /// + /// Create and open a new ServerConnection from a ConnectionInfo object. + /// This calls ConnectionService.OpenSqlConnection and then creates a + /// ServerConnection from it. + /// + /// The connection info to connect with + /// A plaintext string that will be included in the application name for the connection + /// A ServerConnection (wrapping a SqlConnection) created with the given connection info + internal static ServerConnection OpenServerConnection(ConnectionInfo connInfo, string featureName = null) + { + SqlConnection sqlConnection = OpenSqlConnection(connInfo, featureName); + + return connInfo.ConnectionDetails.AzureAccountToken != null + ? new ServerConnection(sqlConnection, new AzureAccessToken(connInfo.ConnectionDetails.AzureAccountToken)) + : new ServerConnection(sqlConnection); + } + + public static void EnsureConnectionIsOpen(ReliableDataSourceConnection conn, bool forceReopen = false) + { + // verify that the connection is open + if (forceReopen) + { + try + { + // close it in case it's in some non-Closed state + conn.Close(); + } + catch + { + // ignore any exceptions thrown from .Close + // if the connection is really broken the .Open call will throw + } + finally + { + // try to reopen the connection + conn.Open(); + } + } + } + } + + public class AzureAccessToken : IRenewableToken + { + public DateTimeOffset TokenExpiry { get; set; } + public string Resource { get; set; } + public string Tenant { get; set; } + public string UserId { get; set; } + + private string accessToken; + + public AzureAccessToken(string accessToken) + { + this.accessToken = accessToken; + } + + public string GetAccessToken() + { + return this.accessToken; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionType.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionType.cs new file mode 100644 index 0000000000..902aac3dce --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ConnectionType.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// String constants that represent connection types. + /// + /// Default: Connection used by the editor. Opened by the editor upon the initial connection. + /// Query: Connection used for executing queries. Opened when the first query is executed. + /// + public static class ConnectionType + { + public const string Default = "Default"; + public const string Query = "Query"; + public const string Edit = "Edit"; + public const string ObjectExplorer = "ObjectExplorer"; + public const string Dashboard = "Dashboard"; + public const string GeneralConnection = "GeneralConnection"; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/BuildConnectionInfoRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/BuildConnectionInfoRequest.cs new file mode 100644 index 0000000000..3190f26b32 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/BuildConnectionInfoRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Serialize Connection String request + /// + public class BuildConnectionInfoRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/buildconnectioninfo"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectParams.cs new file mode 100644 index 0000000000..a697be103a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectParams.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the Cancel Connect Request. + /// + public class CancelConnectParams + { + /// + /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace + /// or a virtual file representing an object in a database. + /// + public string OwnerUri { get; set; } + + /// + /// The type of connection we are trying to cancel + /// + public string Type { get; set; } = ConnectionType.Default; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectRequest.cs new file mode 100644 index 0000000000..716a72a096 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/CancelConnectRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Cancel connect request mapping entry + /// + public class CancelConnectRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/cancelconnect"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseParams.cs new file mode 100644 index 0000000000..287c1bcf0a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseParams.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the List Databases Request. + /// + public class ChangeDatabaseParams + { + /// + /// URI of the owner of the connection requesting the list of databases. + /// + public string OwnerUri { get; set; } + + /// + /// The database to change to + /// + public string NewDatabase { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseRequest.cs new file mode 100644 index 0000000000..946f9337d1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ChangeDatabaseRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// List databases request mapping entry + /// + public class ChangeDatabaseRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/changedatabase"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParams.cs new file mode 100644 index 0000000000..93f0ef3cb0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParams.cs @@ -0,0 +1,37 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the Connect Request. + /// + public class ConnectParams + { + /// + /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace + /// or a virtual file representing an object in a database. + /// + public string OwnerUri { get; set; } + + /// + /// Contains the required parameters to initialize a connection to a database. + /// A connection will identified by its server name, database name and user name. + /// This may be changed in the future to support multiple connections with different + /// connection properties to the same database. + /// + public ConnectionDetails Connection { get; set; } + + /// + /// The type of this connection. By default, this is set to ConnectionType.Default. + /// + public string Type { get; set; } = ConnectionType.Default; + + /// + /// The porpose of the connection to keep track of open connections + /// + public string Purpose { get; set; } = ConnectionType.GeneralConnection; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParamsExtensions.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParamsExtensions.cs new file mode 100644 index 0000000000..5612828f81 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectParamsExtensions.cs @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Extension methods to ConnectParams + /// + public static class ConnectParamsExtensions + { + /// + /// Check that the fields in ConnectParams are all valid + /// + public static bool IsValid(this ConnectParams parameters, out string errorMessage) + { + errorMessage = string.Empty; + if (string.IsNullOrEmpty(parameters.OwnerUri)) + { + errorMessage = SR.ConnectionParamsValidateNullOwnerUri; + } + else if (parameters.Connection == null) + { + errorMessage = SR.ConnectionParamsValidateNullConnection; + } + else if (!string.IsNullOrEmpty(parameters.Connection.ConnectionString)) + { + // Do not check other connection parameters if a connection string is present + return string.IsNullOrEmpty(errorMessage); + } + else if (string.IsNullOrEmpty(parameters.Connection.ServerName)) + { + errorMessage = SR.ConnectionParamsValidateNullServerName; + } + else if (string.IsNullOrEmpty(parameters.Connection.AuthenticationType) || parameters.Connection.AuthenticationType == "SqlLogin") + { + // For SqlLogin, username cannot be empty + if (string.IsNullOrEmpty(parameters.Connection.UserName)) + { + errorMessage = SR.ConnectionParamsValidateNullSqlAuth("UserName"); + } + } + + return string.IsNullOrEmpty(errorMessage); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedNotification.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedNotification.cs new file mode 100644 index 0000000000..8b7ba758c2 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedNotification.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// ConnectionChanged notification mapping entry + /// + public class ConnectionChangedNotification + { + public static readonly + EventType Type = + EventType.Create("connection/connectionchanged"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedParams.cs new file mode 100644 index 0000000000..3874d8b0a0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionChangedParams.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the ConnectionChanged Notification. + /// + public class ConnectionChangedParams + { + /// + /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace + /// or a virtual file representing an object in a database. + /// + public string OwnerUri { get; set; } + /// + /// Contains the high-level properties about the connection, for display to the user. + /// + public ConnectionSummary Connection { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionCompleteNotification.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionCompleteNotification.cs new file mode 100644 index 0000000000..6974ac0929 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionCompleteNotification.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters to be sent back with a connection complete event + /// + public class ConnectionCompleteParams + { + /// + /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace + /// or a virtual file representing an object in a database. + /// + public string OwnerUri { get; set; } + + /// + /// A GUID representing a unique connection ID + /// + public string ConnectionId { get; set; } + + /// + /// Gets or sets any detailed connection error messages. + /// + public string Messages { get; set; } + + /// + /// Error message returned from the engine for a connection failure reason, if any. + /// + public string ErrorMessage { get; set; } + + /// + /// Error number returned from the engine for connection failure reason, if any. + /// + public int ErrorNumber { get; set; } + + /// + /// Information about the connected server. + /// + public ServerInfo ServerInfo { get; set; } + + /// + /// Gets or sets the actual Connection established, including Database Name + /// + public ConnectionSummary ConnectionSummary { get; set; } + + /// + /// The type of connection that this notification is for + /// + public string Type { get; set; } = ConnectionType.Default; + } + + /// + /// ConnectionComplete notification mapping entry + /// + public class ConnectionCompleteNotification + { + public static readonly + EventType Type = + EventType.Create("connection/complete"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetails.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetails.cs new file mode 100644 index 0000000000..b722f12f8e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetails.cs @@ -0,0 +1,540 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Message format for the initial connection request + /// + /// + /// If this contract is ever changed, be sure to update ConnectionDetailsExtensions methods. + /// + public class ConnectionDetails : GeneralRequestDetails, IConnectionSummary + { + public ConnectionDetails() : base() + { + } + + /// + /// Gets or sets the connection password + /// + public string Password + { + get + { + return GetOptionValue("password"); + } + set + { + SetOptionValue("password", value); + } + } + + /// + /// Gets or sets the connection server name + /// + public string ServerName + { + get + { + return GetOptionValue("server"); + } + + set + { + SetOptionValue("server", value); + } + } + + /// + /// Gets or sets the connection database name + /// + public string DatabaseName + { + get + { + return GetOptionValue("database"); + } + + set + { + SetOptionValue("database", value); + } + } + + /// + /// Gets or sets the connection user name + /// + public string UserName + { + get + { + return GetOptionValue("user"); + } + + set + { + SetOptionValue("user", value); + } + } + + /// + /// Gets or sets the authentication to use. + /// + public string AuthenticationType + { + get + { + return GetOptionValue("authenticationType"); + } + + set + { + SetOptionValue("authenticationType", value); + } + } + + /// + /// Gets or sets a Boolean value that indicates whether SQL Server uses SSL encryption for all data sent between the client and server if the server has a certificate installed. + /// + public bool? Encrypt + { + get + { + return GetOptionValue("encrypt"); + } + + set + { + SetOptionValue("encrypt", value); + } + } + + /// + /// Gets or sets a value that indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust. + /// + public bool? TrustServerCertificate + { + get + { + return GetOptionValue("trustServerCertificate"); + } + + set + { + SetOptionValue("trustServerCertificate", value); + } + } + + /// + /// Gets or sets a Boolean value that indicates if security-sensitive information, such as the password, is not returned as part of the connection if the connection is open or has ever been in an open state. + /// + public bool? PersistSecurityInfo + { + get + { + return GetOptionValue("persistSecurityInfo"); + } + + set + { + SetOptionValue("persistSecurityInfo", value); + } + } + + /// + /// Gets or sets the length of time (in seconds) to wait for a connection to the server before terminating the attempt and generating an error. + /// + public int? ConnectTimeout + { + get + { + return GetOptionValue("connectTimeout"); + } + + set + { + SetOptionValue("connectTimeout", value); + } + } + + /// + /// The number of reconnections attempted after identifying that there was an idle connection failure. + /// + public int? ConnectRetryCount + { + get + { + return GetOptionValue("connectRetryCount"); + } + + set + { + SetOptionValue("connectRetryCount", value); + } + } + + /// + /// Amount of time (in seconds) between each reconnection attempt after identifying that there was an idle connection failure. + /// + public int? ConnectRetryInterval + { + get + { + return GetOptionValue("connectRetryInterval"); + } + + set + { + SetOptionValue("connectRetryInterval", value); + } + } + + /// + /// Gets or sets the name of the application associated with the connection string. + /// + public string ApplicationName + { + get + { + return GetOptionValue("applicationName"); + } + + set + { + SetOptionValue("applicationName", value); + } + } + + /// + /// Gets or sets the name of the workstation connecting to SQL Server. + /// + public string WorkstationId + { + get + { + return GetOptionValue("workstationId"); + } + + set + { + SetOptionValue("workstationId", value); + } + } + + /// + /// Declares the application workload type when connecting to a database in an SQL Server Availability Group. + /// + public string ApplicationIntent + { + get + { + return GetOptionValue("applicationIntent"); + } + + set + { + SetOptionValue("applicationIntent", value); + } + } + + /// + /// Gets or sets the SQL Server Language record name. + /// + public string CurrentLanguage + { + get + { + return GetOptionValue("currentLanguage"); + } + + set + { + SetOptionValue("currentLanguage", value); + } + } + + /// + /// Gets or sets a Boolean value that indicates whether the connection will be pooled or explicitly opened every time that the connection is requested. + /// + public bool? Pooling + { + get + { + return GetOptionValue("pooling"); + } + + set + { + SetOptionValue("pooling", value); + } + } + + /// + /// Gets or sets the maximum number of connections allowed in the connection pool for this specific connection string. + /// + public int? MaxPoolSize + { + get + { + return GetOptionValue("maxPoolSize"); + } + + set + { + SetOptionValue("maxPoolSize", value); + } + } + + /// + /// Gets or sets the minimum number of connections allowed in the connection pool for this specific connection string. + /// + public int? MinPoolSize + { + get + { + return GetOptionValue("minPoolSize"); + } + + set + { + SetOptionValue("minPoolSize", value); + } + } + + /// + /// Gets or sets the minimum time, in seconds, for the connection to live in the connection pool before being destroyed. + /// + public int? LoadBalanceTimeout + { + get + { + return GetOptionValue("loadBalanceTimeout"); + } + + set + { + SetOptionValue("loadBalanceTimeout", value); + } + } + + /// + /// Gets or sets a Boolean value that indicates whether replication is supported using the connection. + /// + public bool? Replication + { + get + { + return GetOptionValue("replication"); + } + + set + { + SetOptionValue("replication", value); + } + } + + /// + /// Gets or sets a string that contains the name of the primary data file. This includes the full path name of an attachable database. + /// + public string AttachDbFilename + { + get + { + return GetOptionValue("attachDbFilename"); + } + + set + { + SetOptionValue("attachDbFilename", value); + } + } + + /// + /// Gets or sets the name or address of the partner server to connect to if the primary server is down. + /// + public string FailoverPartner + { + get + { + return GetOptionValue("failoverPartner"); + } + + set + { + SetOptionValue("failoverPartner", value); + } + } + + /// + /// If your application is connecting to an AlwaysOn availability group (AG) on different subnets, setting MultiSubnetFailover=true provides faster detection of and connection to the (currently) active server. + /// + public bool? MultiSubnetFailover + { + get + { + return GetOptionValue("multiSubnetFailover"); + } + + set + { + SetOptionValue("multiSubnetFailover", value); + } + } + + /// + /// When true, an application can maintain multiple active result sets (MARS). + /// + public bool? MultipleActiveResultSets + { + get + { + return GetOptionValue("multipleActiveResultSets"); + } + + set + { + SetOptionValue("multipleActiveResultSets", value); + } + } + + /// + /// Gets or sets the size in bytes of the network packets used to communicate with an instance of SQL Server. + /// + public int? PacketSize + { + get + { + return GetOptionValue("packetSize"); + } + + set + { + SetOptionValue("packetSize", value); + } + } + + /// + /// Gets or sets the port to use for the TCP/IP connection + /// + public int? Port + { + get + { + return GetOptionValue("port"); + } + + set + { + SetOptionValue("port", value); + } + } + + /// + /// Gets or sets a string value that indicates the type system the application expects. + /// + public string TypeSystemVersion + { + get + { + return GetOptionValue("typeSystemVersion"); + } + + set + { + SetOptionValue("typeSystemVersion", value); + } + } + + /// + /// Gets or sets a string value to be used as the connection string. If given, all other options will be ignored. + /// + public string ConnectionString + { + get + { + return GetOptionValue("connectionString"); + } + + set + { + SetOptionValue("connectionString", value); + } + } + + /// + /// Gets or sets the group ID + /// + public string GroupId + { + get + { + return GetOptionValue("groupId"); + } + set + { + SetOptionValue("groupId", value); + } + } + + /// + /// Gets or sets the database display name + /// + public string DatabaseDisplayName + { + get + { + return GetOptionValue("databaseDisplayName"); + } + set + { + SetOptionValue("databaseDisplayName", value); + } + } + + public string AzureAccountToken + { + get + { + return GetOptionValue("azureAccountToken"); + } + set + { + SetOptionValue("azureAccountToken", value); + } + } + + public bool IsComparableTo(ConnectionDetails other) + { + if (other == null) + { + return false; + } + + if (ServerName != other.ServerName + || AuthenticationType != other.AuthenticationType + || UserName != other.UserName + || AzureAccountToken != other.AzureAccountToken) + { + return false; + } + + // For database name, only compare if neither is empty. This is important + // Since it allows for handling of connections to the default database, but is + // not a 100% accurate heuristic. + if (!string.IsNullOrEmpty(DatabaseName) + && !string.IsNullOrEmpty(other.DatabaseName) + && DatabaseName != other.DatabaseName) + { + return false; + } + + return true; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs new file mode 100644 index 0000000000..edfbf651c0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionDetailsExtensions.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Extension methods for the ConnectionDetails contract class + /// + public static class ConnectionDetailsExtensions + { + /// + /// Create a copy of a connection details object. + /// + public static ConnectionDetails Clone(this ConnectionDetails details) + { + return new ConnectionDetails() + { + ServerName = details.ServerName, + DatabaseName = details.DatabaseName, + UserName = details.UserName, + Password = details.Password, + AuthenticationType = details.AuthenticationType, + Encrypt = details.Encrypt, + TrustServerCertificate = details.TrustServerCertificate, + PersistSecurityInfo = details.PersistSecurityInfo, + ConnectTimeout = details.ConnectTimeout, + ConnectRetryCount = details.ConnectRetryCount, + ConnectRetryInterval = details.ConnectRetryInterval, + ApplicationName = details.ApplicationName, + WorkstationId = details.WorkstationId, + ApplicationIntent = details.ApplicationIntent, + CurrentLanguage = details.CurrentLanguage, + Pooling = details.Pooling, + MaxPoolSize = details.MaxPoolSize, + MinPoolSize = details.MinPoolSize, + LoadBalanceTimeout = details.LoadBalanceTimeout, + Replication = details.Replication, + AttachDbFilename = details.AttachDbFilename, + FailoverPartner = details.FailoverPartner, + MultiSubnetFailover = details.MultiSubnetFailover, + MultipleActiveResultSets = details.MultipleActiveResultSets, + PacketSize = details.PacketSize, + TypeSystemVersion = details.TypeSystemVersion, + ConnectionString = details.ConnectionString, + Port = details.Port, + AzureAccountToken = details.AzureAccountToken + }; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionRequest.cs new file mode 100644 index 0000000000..8a63e28a43 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Connect request mapping entry + /// + public class ConnectionRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/connect"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummary.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummary.cs new file mode 100644 index 0000000000..b4f26536bf --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummary.cs @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + + public interface IConnectionSummary + { + /// + /// Gets or sets the connection server name + /// + string ServerName { get; set; } + + /// + /// Gets or sets the connection database name + /// + string DatabaseName { get; set; } + + /// + /// Gets or sets the connection user name + /// + string UserName { get; set; } + } + + /// + /// Provides high level information about a connection. + /// + public class ConnectionSummary : IConnectionSummary + { + /// + /// Gets or sets the connection server name + /// + public virtual string ServerName { get; set; } + + /// + /// Gets or sets the connection database name + /// + public virtual string DatabaseName { get; set; } + + /// + /// Gets or sets the connection user name + /// + public virtual string UserName { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryComparer.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryComparer.cs new file mode 100644 index 0000000000..2c69be19d0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryComparer.cs @@ -0,0 +1,53 @@ +// +// 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; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + + /// + /// Treats connections as the same if their server, db and usernames all match + /// + public class ConnectionSummaryComparer : IEqualityComparer + { + public bool Equals(ConnectionSummary x, ConnectionSummary y) + { + if(x == y) { return true; } + else if(x != null) + { + if(y == null) { return false; } + + // Compare server, db, username. Note: server is case-insensitive in the driver + return string.Compare(x.ServerName, y.ServerName, StringComparison.OrdinalIgnoreCase) == 0 + && string.Compare(x.DatabaseName, y.DatabaseName, StringComparison.Ordinal) == 0 + && string.Compare(x.UserName, y.UserName, StringComparison.Ordinal) == 0; + } + return false; + } + + public int GetHashCode(ConnectionSummary obj) + { + int hashcode = 31; + if(obj != null) + { + if(obj.ServerName != null) + { + hashcode ^= obj.ServerName.GetHashCode(); + } + if (obj.DatabaseName != null) + { + hashcode ^= obj.DatabaseName.GetHashCode(); + } + if (obj.UserName != null) + { + hashcode ^= obj.UserName.GetHashCode(); + } + } + return hashcode; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs new file mode 100644 index 0000000000..476ded3a18 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ConnectionSummaryExtensions.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Extension methods to ConnectionSummary + /// + public static class ConnectionSummaryExtensions + { + /// + /// Create a copy of a ConnectionSummary object + /// + public static ConnectionSummary Clone(this IConnectionSummary summary) + { + return new ConnectionSummary() + { + ServerName = summary.ServerName, + DatabaseName = summary.DatabaseName, + UserName = summary.UserName + }; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectParams.cs new file mode 100644 index 0000000000..f25979a358 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectParams.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the Disconnect Request. + /// + public class DisconnectParams + { + /// + /// A URI identifying the owner of the connection. This will most commonly be a file in the workspace + /// or a virtual file representing an object in a database. + /// + public string OwnerUri { get; set; } + + /// + /// The type of connection we are disconnecting. If null, we will disconnect all connections. + /// connections. + /// + public string Type { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectRequest.cs new file mode 100644 index 0000000000..eef7fb8d56 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/DisconnectRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Disconnect request mapping entry + /// + public class DisconnectRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/disconnect"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringParams.cs new file mode 100644 index 0000000000..75c6a1f1d3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringParams.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the Get Connection String Request. + /// + public class GetConnectionStringParams + { + /// + /// URI of the owner of the connection + /// + public string OwnerUri { get; set; } + + /// + /// Indicates whether the password should be return in the connection string + /// + public bool IncludePassword { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringRequest.cs new file mode 100644 index 0000000000..fa855b3528 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/GetConnectionStringRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Get Connection String request + /// + public class GetConnectionStringRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/getconnectionstring"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/LanguageFlavorChange.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/LanguageFlavorChange.cs new file mode 100644 index 0000000000..db97c23b24 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/LanguageFlavorChange.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + + /// + /// Parameters for the Language Flavor Change notification. + /// + public class LanguageFlavorChangeParams + { + /// + /// A URI identifying the affected resource + /// + public string Uri { get; set; } + + /// + /// The primary language + /// + public string Language { get; set; } + + /// + /// The specific language flavor that is being set + /// + public string Flavor { get; set; } + } + + /// + /// Defines an event that is sent from the client to notify that + /// the client is exiting and the server should as well. + /// + public class LanguageFlavorChangeNotification + { + public static readonly + EventType Type = + EventType.Create("connection/languageflavorchanged"); + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesParams.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesParams.cs new file mode 100644 index 0000000000..039a93e8e7 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesParams.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Parameters for the List Databases Request. + /// + public class ListDatabasesParams + { + /// + /// URI of the owner of the connection requesting the list of databases. + /// + public string OwnerUri { get; set; } + + /// + /// whether to include the details of the databases. Called by manage dashboard + /// + public bool? IncludeDetails { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesRequest.cs new file mode 100644 index 0000000000..45f21c1744 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesRequest.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// List databases request mapping entry + /// + public class ListDatabasesRequest + { + public static readonly + RequestType Type = + RequestType.Create("connection/listdatabases"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesResponse.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesResponse.cs new file mode 100644 index 0000000000..cf6e86a18b --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ListDatabasesResponse.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +using Microsoft.Kusto.ServiceLayer.Admin.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Message format for the list databases response + /// + public class ListDatabasesResponse + { + /// + /// Gets or sets the list of database names. + /// + public string[] DatabaseNames { get; set; } + + /// + /// Gets or sets the databases details. + /// + public DatabaseInfo[] Databases { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ServerInfo.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ServerInfo.cs new file mode 100644 index 0000000000..4cb6032cee --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/Contracts/ServerInfo.cs @@ -0,0 +1,75 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; + +namespace Microsoft.Kusto.ServiceLayer.Connection.Contracts +{ + /// + /// Contract for information on the connected SQL Server instance. + /// + public class ServerInfo + { + /// + /// The major version of the SQL Server instance. + /// + public int ServerMajorVersion { get; set; } + + /// + /// The minor version of the SQL Server instance. + /// + public int ServerMinorVersion { get; set; } + + /// + /// The build of the SQL Server instance. + /// + public int ServerReleaseVersion { get; set; } + + /// + /// The ID of the engine edition of the SQL Server instance. + /// + public int EngineEditionId { get; set; } + + /// + /// String containing the full server version text. + /// + public string ServerVersion { get; set; } + + /// + /// String describing the product level of the server. + /// + public string ServerLevel { get; set; } + + /// + /// The edition of the SQL Server instance. + /// + public string ServerEdition { get; set; } + + /// + /// Whether the SQL Server instance is running in the cloud (Azure) or not. + /// + public bool IsCloud { get; set; } + + /// + /// The version of Azure that the SQL Server instance is running on, if applicable. + /// + public int AzureVersion { get; set; } + + /// + /// The Operating System version string of the machine running the SQL Server instance. + /// + public string OsVersion { get; set; } + + /// + /// The Operating System version string of the machine running the SQL Server instance. + /// + public string MachineName { get; set; } + + /// + /// Server options + /// + public Dictionary Options { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs new file mode 100644 index 0000000000..c676decd47 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/DataSourceConnectionFactory.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Data.Common; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Factory class to create SqlClientConnections + /// The purpose of the factory is to make it easier to mock out the database + /// in 'offline' unit test scenarios. + /// + public class DataSourceConnectionFactory : IDataSourceConnectionFactory + { + /// + /// Creates a new SqlConnection object + /// + public ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken) + { + RetryPolicy connectionRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); + RetryPolicy commandRetryPolicy = RetryPolicyFactory.CreateDefaultConnectionRetryPolicy(); + return new ReliableDataSourceConnection(connectionString, connectionRetryPolicy, commandRetryPolicy, azureAccountToken); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseFullAccessException.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseFullAccessException.cs new file mode 100644 index 0000000000..f1a2d11cfc --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseFullAccessException.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + public class DatabaseFullAccessException: Exception + { + public DatabaseFullAccessException() + : base() + { + } + + public DatabaseFullAccessException(string message, Exception exception) + : base(message, exception) + { + } + + + public DatabaseFullAccessException(string message) + : base(message) + { + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseLocksManager.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseLocksManager.cs new file mode 100644 index 0000000000..c1aeb0df8c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/DatabaseLocksManager.cs @@ -0,0 +1,114 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using System; +using System.Collections.Generic; +using System.Threading; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + public class DatabaseLocksManager: IDisposable + { + internal DatabaseLocksManager(int waitToGetFullAccess) + { + this.waitToGetFullAccess = waitToGetFullAccess; + } + + private static DatabaseLocksManager instance = new DatabaseLocksManager(DefaultWaitToGetFullAccess); + + public static DatabaseLocksManager Instance + { + get + { + return instance; + } + } + + public ConnectionService ConnectionService { get; set; } + + private Dictionary databaseAccessEvents = new Dictionary(); + private object databaseAccessLock = new object(); + public const int DefaultWaitToGetFullAccess = 10000; + public int waitToGetFullAccess = DefaultWaitToGetFullAccess; + + private ManualResetEvent GetResetEvent(string serverName, string databaseName) + { + string key = GenerateKey(serverName, databaseName); + ManualResetEvent resetEvent = null; + lock (databaseAccessLock) + { + if (!databaseAccessEvents.TryGetValue(key, out resetEvent)) + { + resetEvent = new ManualResetEvent(true); + databaseAccessEvents.Add(key, resetEvent); + } + } + + return resetEvent; + } + + public bool GainFullAccessToDatabase(string serverName, string databaseName) + { + /* + * TODO: add the lock so not two process can get full access at the same time + ManualResetEvent resetEvent = GetResetEvent(serverName, databaseName); + if (resetEvent.WaitOne(this.waitToGetFullAccess)) + { + resetEvent.Reset(); + + foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues) + { + item.CloseConnections(serverName, databaseName); + } + return true; + } + else + { + throw new DatabaseFullAccessException($"Waited more than {waitToGetFullAccess} milli seconds for others to release the lock"); + } + */ + foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues) + { + item.CloseConnections(serverName, databaseName, DefaultWaitToGetFullAccess); + } + return true; + + } + + public bool ReleaseAccess(string serverName, string databaseName) + { + /* + ManualResetEvent resetEvent = GetResetEvent(serverName, databaseName); + + foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues) + { + item.OpenConnections(serverName, databaseName); + } + + resetEvent.Set(); + */ + foreach (IConnectedBindingQueue item in ConnectionService.ConnectedQueues) + { + item.OpenConnections(serverName, databaseName, DefaultWaitToGetFullAccess); + } + return true; + + } + + private string GenerateKey(string serverName, string databaseName) + { + return $"{serverName.ToLowerInvariant()}-{databaseName.ToLowerInvariant()}"; + } + + public void Dispose() + { + foreach (var resetEvent in databaseAccessEvents) + { + resetEvent.Value.Dispose(); + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/FeatureWithFullDbAccess.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/FeatureWithFullDbAccess.cs new file mode 100644 index 0000000000..9be034c7b0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/FeatureWithFullDbAccess.cs @@ -0,0 +1,40 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Any operation that needs full access to databas should implement this interface. + /// Make sure to call GainAccessToDatabase before the operation and ReleaseAccessToDatabase after + /// + public interface IFeatureWithFullDbAccess + { + /// + /// Database Lock Manager + /// + DatabaseLocksManager LockedDatabaseManager { get; set; } + + /// + /// Makes sure the feature has fill access to the database + /// + bool GainAccessToDatabase(); + + /// + /// Release the access to db + /// + bool ReleaseAccessToDatabase(); + + /// + /// Server name + /// + string ServerName { get; } + + /// + /// Database name + /// + string DatabaseName { get; } + } + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs new file mode 100644 index 0000000000..fbfd45b160 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/IDataSourceConnectionFactory.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Data.Common; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Interface for the SQL Connection factory + /// + public interface IDataSourceConnectionFactory + { + /// + /// Create a new SQL Connection object + /// + ReliableDataSourceConnection CreateDataSourceConnection(string connectionString, string azureAccountToken); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Connection/ReliableConnection/RetryCallbackEventArgs.cs b/src/Microsoft.Kusto.ServiceLayer/Connection/ReliableConnection/RetryCallbackEventArgs.cs new file mode 100644 index 0000000000..b6a11bbf20 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Connection/ReliableConnection/RetryCallbackEventArgs.cs @@ -0,0 +1,58 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// This code is copied from the source described in the comment below. + +// ======================================================================================= +// Microsoft Windows Server AppFabric Customer Advisory Team (CAT) Best Practices Series +// +// This sample is supplemental to the technical guidance published on the community +// blog at http://blogs.msdn.com/appfabriccat/ and copied from +// sqlmain ./sql/manageability/mfx/common/ +// +// ======================================================================================= +// Copyright © 2012 Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT. +// ======================================================================================= + +using System; + +namespace Microsoft.Kusto.ServiceLayer.Connection.ReliableConnection +{ + /// + /// Defines a arguments for event handler which will be invoked whenever a retry condition is encountered. + /// + internal sealed class RetryCallbackEventArgs : EventArgs + { + private readonly int _retryCount; + private readonly Exception _exception; + private readonly TimeSpan _delay; + + public RetryCallbackEventArgs(int retryCount, Exception exception, TimeSpan delay) + { + _retryCount = retryCount; + _exception = exception; + _delay = delay; + } + + public TimeSpan Delay + { + get { return _delay; } + } + + public Exception Exception + { + get { return _exception; } + } + + public int RetryCount + { + get { return _retryCount; } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataReaderWrapper.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataReaderWrapper.cs new file mode 100644 index 0000000000..89ee36164d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataReaderWrapper.cs @@ -0,0 +1,59 @@ +// +// Copyright (c) Microsoft. All Rights Reserved. +// +using System; +using System.Text.RegularExpressions; +using System.Linq; +using System.Data; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + class DataReaderWrapper:IDataReader + { + private readonly IDataReader _inner ; + public DataReaderWrapper(IDataReader inner) + { + _inner = inner; + } + + public object this[int i] => _inner[i]; + + public object this[string name] => _inner[name]; + + public int Depth => _inner.Depth; + + public bool IsClosed => _inner.IsClosed; + + public int RecordsAffected => _inner.RecordsAffected; + + public int FieldCount => _inner.FieldCount; + + public void Close() => _inner.Close(); + public void Dispose() => _inner.Dispose(); + public bool GetBoolean(int i) => _inner.GetBoolean(i); + public byte GetByte(int i) => _inner.GetByte(i); + public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) => _inner.GetBytes(i, fieldOffset, buffer, bufferoffset, length); + public char GetChar(int i) => _inner.GetChar(i); + public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) => _inner.GetChars(i, fieldoffset, buffer, bufferoffset, length); + public IDataReader GetData(int i) => _inner.GetData(i); + public string GetDataTypeName(int i) => _inner.GetDataTypeName(i); + public DateTime GetDateTime(int i) => _inner.GetDateTime(i); + public decimal GetDecimal(int i) => _inner.GetDecimal(i); + public double GetDouble(int i) => _inner.GetDouble(i); + public Type GetFieldType(int i) => _inner.GetFieldType(i); + public float GetFloat(int i) => _inner.GetFloat(i); + public Guid GetGuid(int i) => _inner.GetGuid(i); + public short GetInt16(int i) => _inner.GetInt16(i); + public int GetInt32(int i) => _inner.GetInt32(i); + public long GetInt64(int i) => _inner.GetInt64(i); + public string GetName(int i) => _inner.GetName(i); + public int GetOrdinal(string name) => _inner.GetOrdinal(name); + public DataTable GetSchemaTable() => _inner.GetSchemaTable(); + public string GetString(int i) => _inner.GetString(i); + public object GetValue(int i) => _inner.GetValue(i); + public int GetValues(object[] values) => _inner.GetValues(values); + public bool IsDBNull(int i) => _inner.IsDBNull(i); + public virtual bool NextResult() => _inner.NextResult(); + public bool Read() => _inner.Read(); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs new file mode 100644 index 0000000000..1cd3269750 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceBase.cs @@ -0,0 +1,132 @@ +// +// Copyright (c) Microsoft. All Rights Reserved. +// + +using System; +using System.Collections.Generic; +using System.Threading; +using System.Data; +using System.Threading.Tasks; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + /// + public abstract class DataSourceBase : IDataSource + { + protected Object dataSourceLock = new Object(); + + private string _database; + + #region IDisposable + + /// + /// Finalizes an instance of the class. + /// + ~DataSourceBase() + { + Dispose(false); + } + + /// + /// Disposes resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Disposes resources. + /// + /// true if disposing; false if finalizing. + protected virtual void Dispose(bool disposing) + { + } + + #endregion + + #region IDataSource + + /// + public abstract Task ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null); + + /// + public async Task ExecuteScalarQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(query, nameof(query)); + + using (var records = await ExecuteQueryAsync(query, cancellationToken, databaseName)) + { + return records.ToScalar(); + } + } + + public abstract Task> ExecuteControlCommandAsync(string command, bool throwOnError, CancellationToken cancellationToken); + + /// + public abstract DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata parentMetadata); + + /// + public abstract IEnumerable GetChildObjects(DataSourceObjectMetadata parentMetadata, bool includeSizeDetails = false); + + /// + public abstract void Refresh(); + + /// + public abstract void Refresh(DataSourceObjectMetadata objectMetadata); + + /// + public abstract void UpdateDatabase(string databaseName); + + /// + public abstract CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo queryText, Position index, bool throwOnError = false); + /// + public abstract Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false); + + /// + public abstract DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false); + + /// + public abstract ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText); + + /// + public abstract Task Exists(); + + /// + public abstract bool Exists(DataSourceObjectMetadata objectMetadata); + + public abstract string GenerateAlterFunctionScript(string functionName); + + /// + public DataSourceType DataSourceType { get; protected set; } + + /// + public string ClusterName { get; protected set; } + + /// + public string DatabaseName { + get + { + return _database; + } + + set + { + lock(dataSourceLock) + { + _database = value; + } + } + } + + #endregion + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs new file mode 100644 index 0000000000..3e78d5007b --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceFactory.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.Admin.Contracts; +using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; +using Microsoft.Kusto.ServiceLayer.Metadata.Contracts; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + /// + /// Data source factory. + /// + public static class DataSourceFactory + { + public static IDataSource Create(DataSourceType dataSourceType, string connectionString, string azureAccountToken) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(connectionString, nameof(connectionString)); + ValidationUtils.IsArgumentNotNullOrWhiteSpace(azureAccountToken, nameof(azureAccountToken)); + + switch (dataSourceType) + { + case DataSourceType.Kusto: + { + return new KustoDataSource(connectionString, azureAccountToken); + } + + default: + throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType)); + } + } + + public static DataSourceObjectMetadata CreateClusterMetadata(string clusterName) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(clusterName, nameof(clusterName)); + + return new DataSourceObjectMetadata{ + MetadataType = DataSourceMetadataType.Cluster, + MetadataTypeName = DataSourceMetadataType.Cluster.ToString(), + Name = clusterName, + PrettyName = clusterName, + Urn = $"{clusterName}" + }; + } + + public static DataSourceObjectMetadata CreateDatabaseMetadata(DataSourceObjectMetadata clusterMetadata, string databaseName) + { + ValidationUtils.IsTrue(clusterMetadata.MetadataType == DataSourceMetadataType.Cluster, nameof(clusterMetadata)); + ValidationUtils.IsArgumentNotNullOrWhiteSpace(databaseName, nameof(databaseName)); + + return new DatabaseMetadata{ + ClusterName = clusterMetadata.Name, + MetadataType = DataSourceMetadataType.Database, + MetadataTypeName = DataSourceMetadataType.Database.ToString(), + Name = databaseName, + PrettyName = databaseName, + Urn = $"{clusterMetadata.Urn}.{databaseName}" + }; + } + + public static FolderMetadata CreateFolderMetadata(DataSourceObjectMetadata parentMetadata, string path, string name) + { + ValidationUtils.IsNotNull(parentMetadata, nameof(parentMetadata)); + + return new FolderMetadata{ + MetadataType = DataSourceMetadataType.Folder, + MetadataTypeName = DataSourceMetadataType.Folder.ToString(), + Name = name, + PrettyName = name, + ParentMetadata = parentMetadata, + Urn = $"{path}.{name}" + }; + } + + // Gets default keywords for intellisense when there is no connection. + public static CompletionItem[] GetDefaultAutoComplete(DataSourceType dataSourceType, ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition){ + switch (dataSourceType) + { + case DataSourceType.Kusto: + { + return KustoIntellisenseHelper.GetDefaultKeywords(scriptDocumentInfo, textDocumentPosition); + } + + default: + throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType)); + } + } + + // Gets default keywords errors related to intellisense when there is no connection. + public static ScriptFileMarker[] GetDefaultSemanticMarkers(DataSourceType dataSourceType, ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText){ + switch (dataSourceType) + { + case DataSourceType.Kusto: + { + return KustoIntellisenseHelper.GetDefaultDiagnostics(parseInfo, scriptFile, queryText); + } + + default: + throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType)); + } + } + + // Converts database details shown on cluster manage dashboard to DatabaseInfo type. Add DataSourceType as param if required to show different properties + public static List ConvertToDatabaseInfo(IEnumerable clusterDBDetails) + { + var databaseDetails = new List(); + + if(typeof(DatabaseMetadata) == clusterDBDetails.FirstOrDefault().GetType()){ + foreach(var dbDetail in clusterDBDetails) + { + DatabaseInfo databaseInfo = new DatabaseInfo(); + Int64.TryParse(dbDetail.SizeInMB.ToString(), out long sum_OriginalSize); + databaseInfo.Options["name"] = dbDetail.Name; + databaseInfo.Options["sizeInMB"] = (sum_OriginalSize /(1024 * 1024)).ToString(); + databaseDetails.Add(databaseInfo); + } + } + + return databaseDetails; + } + + // Converts tables details shown on database manage dashboard to ObjectMetadata type. Add DataSourceType as param if required to show different properties + public static List ConvertToObjectMetadata(IEnumerable dbChildDetails) + { + var databaseChildDetails = new List(); + + foreach(var childDetail in dbChildDetails) + { + ObjectMetadata dbChildInfo = new ObjectMetadata(); + dbChildInfo.Name = childDetail.PrettyName; + dbChildInfo.MetadataTypeName = childDetail.MetadataTypeName; + dbChildInfo.MetadataType = MetadataType.Table; // Add mapping here. + databaseChildDetails.Add(dbChildInfo); + } + return databaseChildDetails; + } + + public static ReliableConnectionHelper.ServerInfo ConvertToServerinfoFormat(DataSourceType dataSourceType, DiagnosticsInfo clusterDiagnostics) + { + switch (dataSourceType) + { + case DataSourceType.Kusto: + { + ReliableConnectionHelper.ServerInfo serverInfo = new ReliableConnectionHelper.ServerInfo(); + serverInfo.Options = new Dictionary(clusterDiagnostics.Options); + return serverInfo; + } + + default: + throw new ArgumentException($"Unsupported data source type \"{dataSourceType}\"", nameof(dataSourceType)); + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs new file mode 100644 index 0000000000..fa423e3c61 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/KustoIntellisenseHelper.cs @@ -0,0 +1,329 @@ +// +// 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.Threading; +using System.Threading.Tasks; +using System.Linq; +using Kusto.Language; +using Kusto.Language.Editor; +using Kusto.Language.Syntax; +using Kusto.Language.Symbols; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense +{ + /// + /// Kusto specific class for intellisense helper functions. + /// + public static class KustoIntellisenseHelper + { + + public class ShowDatabasesResult + { + public string DatabaseName; + public string PersistentStorage; + public string Version; + public bool IsCurrent; + public string DatabaseAccessMode; + public string PrettyName; + public bool CurrentUserIsUnrestrictedViewer; + public string DatabaseId; + } + + public class ShowDatabaseSchemaResult + { + public string DatabaseName; + public string TableName; + public string ColumnName; + public string ColumnType; + public bool IsDefaultTable; + public bool IsDefaultColumn; + public string PrettyName; + public string Version; + public string Folder; + public string DocName; + } + + public class ShowFunctionsResult + { + public string Name; + public string Parameters; + public string Body; + public string Folder; + public string DocString; + } + + /// + /// Convert CLR type name into a Kusto scalar type. + /// + private static ScalarSymbol GetKustoType(string clrTypeName) + { + switch (clrTypeName) + { + case "System.Byte": + case "Byte": + case "byte": + case "System.SByte": + case "SByte": + case "sbyte": + case "System.Int16": + case "Int16": + case "short": + case "System.UInt16": + case "UInt16": + case "ushort": + case "System.Int32": + case "System.Single": + case "Int32": + case "int": + return ScalarTypes.Int; + case "System.UInt32": // unsigned ints don't fit into int, use long + case "UInt32": + case "uint": + case "System.Int64": + case "Int64": + case "long": + return ScalarTypes.Long; + case "System.Double": + case "Double": + case "double": + case "float": + return ScalarTypes.Real; + case "System.UInt64": // unsigned longs do not fit into long, use decimal + case "UInt64": + case "ulong": + case "System.Decimal": + case "Decimal": + case "decimal": + case "System.Data.SqlTypes.SqlDecimal": + case "SqlDecimal": + return ScalarTypes.Decimal; + case "System.Guid": + case "Guid": + return ScalarTypes.Guid; + case "System.DateTime": + case "DateTime": + return ScalarTypes.DateTime; + case "System.TimeSpan": + case "TimeSpan": + return ScalarTypes.TimeSpan; + case "System.String": + case "String": + case "string": + return ScalarTypes.String; + case "System.Boolean": + case "Boolean": + case "bool": + return ScalarTypes.Bool; + case "System.Object": + case "Object": + case "object": + return ScalarTypes.Dynamic; + case "System.Type": + case "Type": + return ScalarTypes.Type; + default: + throw new InvalidOperationException($"Unhandled clr type: {clrTypeName}"); + } + } + + private static IReadOnlyList NoParameters = new Parameter[0]; + + /// + /// Translate Kusto parameter list declaration into into list of instances. + /// + private static IReadOnlyList TranslateParameters(string parameters) + { + parameters = parameters.Trim(); + + if (string.IsNullOrEmpty(parameters) || parameters == "()") + return NoParameters; + + if (parameters[0] != '(') + parameters = "(" + parameters; + if (parameters[parameters.Length - 1] != ')') + parameters = parameters + ")"; + + var query = "let fn = " + parameters + " { };"; + var code = KustoCode.ParseAndAnalyze(query); + var let = code.Syntax.GetFirstDescendant(); + var variable = let.Name.ReferencedSymbol as VariableSymbol; + var function = variable.Type as FunctionSymbol; + return function.Signatures[0].Parameters; + } + + /// + /// Loads the schema for the specified databasea into a a . + /// + public static async Task LoadDatabaseAsync(IDataSource dataSource, string databaseName, bool throwOnError = false) + { + var members = new List(); + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken cancellationToken = source.Token; + + var tableSchemas = await dataSource.ExecuteControlCommandAsync($".show database {databaseName} schema", throwOnError, cancellationToken).ConfigureAwait(false); + if (tableSchemas == null) + return null; + + tableSchemas = tableSchemas + .Where(r => !string.IsNullOrEmpty(r.TableName) && !string.IsNullOrEmpty(r.ColumnName)) + .ToArray(); + + foreach (var table in tableSchemas.GroupBy(s => s.TableName)) + { + var columns = table.Select(s => new ColumnSymbol(s.ColumnName, GetKustoType(s.ColumnType))).ToList(); + var tableSymbol = new TableSymbol(table.Key, columns); + members.Add(tableSymbol); + } + + var functionSchemas = await dataSource.ExecuteControlCommandAsync(".show functions", throwOnError, cancellationToken).ConfigureAwait(false); + if (functionSchemas == null) + return null; + + foreach (var fun in functionSchemas) + { + var parameters = TranslateParameters(fun.Parameters); + var functionSymbol = new FunctionSymbol(fun.Name, fun.Body, parameters); + members.Add(functionSymbol); + } + + var databaseSymbol = new DatabaseSymbol(databaseName, members); + return databaseSymbol; + } + + public static CompletionItemKind CreateCompletionItemKind(CompletionKind kustoKind) + { + CompletionItemKind kind = CompletionItemKind.Variable; + switch (kustoKind) + { + case CompletionKind.Syntax: + kind = CompletionItemKind.Module; + break; + case CompletionKind.Column: + kind = CompletionItemKind.Field; + break; + case CompletionKind.Variable: + kind = CompletionItemKind.Variable; + break; + case CompletionKind.Table: + kind = CompletionItemKind.File; + break; + case CompletionKind.Database: + kind = CompletionItemKind.Method; + break; + case CompletionKind.LocalFunction: + case CompletionKind.DatabaseFunction: + case CompletionKind.BuiltInFunction: + case CompletionKind.AggregateFunction: + kind = CompletionItemKind.Function; + break; + default: + kind = CompletionItemKind.Keyword; + break; + } + + return kind; + } + + /// + /// Gets default keyword when user if not connected to any Kusto cluster. + /// + public static LanguageServices.Contracts.CompletionItem[] GetDefaultKeywords(ScriptDocumentInfo scriptDocumentInfo, Position textDocumentPosition){ + var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, GlobalState.Default); + var script = CodeScript.From(scriptDocumentInfo.Contents, GlobalState.Default); + script.TryGetTextPosition(textDocumentPosition.Line + 1, textDocumentPosition.Character, out int position); // Gets the actual offset based on line and local offset + var completion = kustoCodeService.GetCompletionItems(position); + + List completions = new List(); + foreach (var autoCompleteItem in completion.Items) + { + var label = autoCompleteItem.DisplayText; + // convert the completion item candidates into vscode format CompletionItems + completions.Add(AutoCompleteHelper.CreateCompletionItem(label, label + " keyword", label, CompletionItemKind.Keyword, scriptDocumentInfo.StartLine, scriptDocumentInfo.StartColumn, textDocumentPosition.Character)); + } + + return completions.ToArray(); + } + + /// + /// Gets default diagnostics when user if not connected to any Kusto cluster. + /// + public static ScriptFileMarker[] GetDefaultDiagnostics(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText){ + var kustoCodeService = new KustoCodeService(queryText, GlobalState.Default); + var script = CodeScript.From(queryText, GlobalState.Default); + var parseResult = kustoCodeService.GetDiagnostics(); + + parseInfo.ParseResult = parseResult; + + // build a list of Kusto script file markers from the errors. + List markers = new List(); + if (parseResult != null && parseResult.Count() > 0) + { + foreach (var error in parseResult) + { + script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset); + script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset); + + // vscode specific format for error markers. + markers.Add(new ScriptFileMarker() + { + Message = error.Message, + Level = ScriptFileMarkerLevel.Error, + ScriptRegion = new ScriptRegion() + { + File = scriptFile.FilePath, + StartLineNumber = startLine, + StartColumnNumber = startOffset, + StartOffset = 0, + EndLineNumber = endLine, + EndColumnNumber = endOffset, + EndOffset = 0 + } + }); + } + } + + return markers.ToArray(); + } + + /// + /// Loads the schema for the specified database and returns a new with the database added or updated. + /// + public static async Task AddOrUpdateDatabaseAsync(IDataSource dataSource, GlobalState globals, string databaseName, string clusterName, bool throwOnError) + { // try and show error from here. + DatabaseSymbol databaseSymbol = null; + + if(databaseName != null){ + databaseSymbol = await LoadDatabaseAsync(dataSource, databaseName, throwOnError).ConfigureAwait(false); + } + + if(databaseSymbol == null){ + return globals; + } + + var cluster = globals.GetCluster(clusterName); + if (cluster == null) + { + cluster = new ClusterSymbol(clusterName, new[] { databaseSymbol }, isOpen: true); + globals = globals.AddOrUpdateCluster(cluster); + } + else + { + cluster = cluster.AddOrUpdateDatabase(databaseSymbol); + globals = globals.AddOrUpdateCluster(cluster); + } + + globals = globals.WithCluster(cluster).WithDatabase(databaseSymbol); + + return globals; + } + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs new file mode 100644 index 0000000000..d92433a32b --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceIntellisense/ScriptParseInfo.cs @@ -0,0 +1,48 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Kusto.Language; +using Kusto.Language.Editor; + +namespace Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense +{ + /// + /// Data Source specific class for storing cached metadata regarding a parsed KQL file. + /// + public class ScriptParseInfo + { + private object buildingMetadataLock = new object(); + + /// + /// Event which tells if MetadataProvider is built fully or not + /// + public object BuildingMetadataLock + { + get { return this.buildingMetadataLock; } + } + + /// + /// Gets or sets a flag determining is the LanguageService is connected + /// + public bool IsConnected { get; set; } + + /// + /// Gets or sets the binding queue connection context key + /// + public string ConnectionKey { get; set; } + + /// + /// Gets or sets the previous Kusto diagnostics result. TODOKusto: Check exact usage. + /// + public IReadOnlyList ParseResult { get; set; } + + /// + /// Gets or sets the current autocomplete suggestion list retrieved from the Kusto language library. + /// So that other details like documentation can be later retrieved in ResolveCompletionItem. + /// + public IEnumerable CurrentSuggestions { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceType.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceType.cs new file mode 100644 index 0000000000..911a911615 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DataSourceType.cs @@ -0,0 +1,28 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + /// + /// Represents the type of a data source. + /// + public enum DataSourceType + { + /// + /// Unknown. + /// + None, + + /// + /// A Kusto cluster. + /// + Kusto, + + /// + /// An Application Insights subscription. + /// + ApplicationInsights, + + /// + /// An Operations Management Suite (OMS) Log Analytics workspace. + /// + OmsLogAnalytics + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/DiagnosticsInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/DiagnosticsInfo.cs new file mode 100644 index 0000000000..2a567a20f7 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/DiagnosticsInfo.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + public class DiagnosticsInfo + { + /// + /// Gets or sets the options + /// + public Dictionary Options { get; set; } + + public DiagnosticsInfo() + { + Options = new Dictionary(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs new file mode 100644 index 0000000000..03eeab2550 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/IDataSource.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + /// + /// Represents data source utilities. + /// + public interface IDataSource : IDisposable + { + /// + /// The data source type. + /// + DataSourceType DataSourceType { get; } + + /// + /// The cluster/server name. + /// + string ClusterName { get; } + + /// + /// The current database name, if there is one. + /// + string DatabaseName { get; set; } + + /// + /// Executes a query. + /// + /// The query. + /// The results. + Task ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null); + + /// + /// Executes a Kusto query that returns a scalar value. + /// + /// The type of the result. + /// The query. + /// The result. + Task ExecuteScalarQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null); + + /// + /// Executes a Kusto query that returns a scalar value. + /// + /// The type of the result. + /// The query. + /// The result. + Task> ExecuteControlCommandAsync(string command, bool throwOnError, CancellationToken cancellationToken); + + /// + /// Get children of the given parent + /// + /// Parent object metadata. + /// Metadata for all children. + DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata parentMetadata); + + /// + /// Get children of the given parent + /// + /// Parent object metadata. + /// + /// Metadata for all children. + IEnumerable GetChildObjects(DataSourceObjectMetadata parentMetadata, bool includeSizeDetails = false); + + /// + /// Refresh object list for entire cluster. + /// + void Refresh(); + + /// + /// Refresh object list for given object. + /// + /// Object metadata. + void Refresh(DataSourceObjectMetadata objectMetadata); + + /// + /// Updates database and affected variables like GlobalState for given object. + /// + /// Object metadata. + void UpdateDatabase(string databaseName); + + /// + /// Gets autocomplete suggestions at given position. + /// + /// Object metadata. + CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo queryText, Position index, bool throwOnError = false); + /// + /// Gets quick info hover tooltips for the current position. + /// + /// Object metadata. + Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false); + + /// + /// Gets definition for a selected query text. + /// + /// Object metadata. + DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false); + + /// + /// Gets a list of semantic diagnostic marks for the provided script file + /// + /// Object metadata. + ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText); + + /// + /// Tells whether the data source exists. + /// + /// true if it exists; false otherwise. + Task Exists(); + + /// + /// Tells whether the object exists. + /// + /// true if it exists; false otherwise. + bool Exists(DataSourceObjectMetadata objectMetadata); + + /// + /// Gets FunctionInfo object for a function + /// + /// + /// + string GenerateAlterFunctionScript(string functionName); + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs new file mode 100644 index 0000000000..f54ffb8691 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoDataSource.cs @@ -0,0 +1,1045 @@ +// +// Copyright (c) Microsoft. All Rights Reserved. +// +using System; +using System.Collections.Generic; +using System.Threading; +using System.Collections.Concurrent; +using System.Data; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using System.Text; +using Newtonsoft.Json; +using System.Threading.Tasks; +using Kusto.Cloud.Platform.Data; +using Kusto.Data; +using Kusto.Data.Common; +using Kusto.Data.Data; +using Kusto.Data.Net.Client; +using Kusto.Language; +using Kusto.Language.Editor; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.DataSource.Models; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + /// + /// Represents Kusto utilities. + /// + public class KustoDataSource : DataSourceBase + { + private ICslQueryProvider _kustoQueryProvider; + + private ICslAdminProvider _kustoAdminProvider; + + /// + /// List of databases. + /// + private IEnumerable _databaseMetadata; + + /// + /// List of tables per database. Key - Parent Folder or Database Urn + /// + private ConcurrentDictionary> _tableMetadata = new ConcurrentDictionary>(); + + /// + /// List of columns per table. Key - DatabaseName.TableName + /// + private ConcurrentDictionary> _columnMetadata = new ConcurrentDictionary>(); + + /// + /// List of tables per database. Key - Parent Folder or Database Urn + /// + private ConcurrentDictionary> _folderMetadata = new ConcurrentDictionary>(); + + /// + /// List of functions per database. Key - Parent Folder or Database Urn + /// + private ConcurrentDictionary> _functionMetadata = new ConcurrentDictionary>(); + + // Some clusters have this signature. Queries might slightly differ for Aria + private const string AriaProxyURL = "kusto.aria.microsoft.com"; + + /// + /// The database schema query. Performance: ".show database schema" is more efficient than ".show schema", + /// especially for large clusters with many databases or tables. + /// + private const string ShowDatabaseSchema = ".show database [{0}] schema"; + + /// + /// The dashboard needs a list of all tables regardless of the folder structure of the table. The + /// tables are stored with the key in the following format: OnlyTables.ClusterName.DatabaseName + /// + private const string DatabaseKeyPrefix = "OnlyTables"; + + /// + /// Prevents a default instance of the class from being created. + /// + public KustoDataSource(string connectionString, string azureAccountToken) + { + ClusterName = GetClusterName(connectionString); + DatabaseName = GetDatabaseName(connectionString); + UserToken = azureAccountToken; + SchemaState = Task.Run(() => KustoIntellisenseHelper.AddOrUpdateDatabaseAsync(this, GlobalState.Default, DatabaseName, ClusterName, throwOnError: false)).Result; + // Check if a connection can be made + ValidationUtils.IsTrue(Exists().Result, $"Unable to connect. ClusterName = {ClusterName}, DatabaseName = {DatabaseName}"); + } + + /// + /// Extracts the cluster name from the connectionstring. The string looks like the following: + /// "Data Source=clustername.kusto.windows.net;User ID=;Password=;Pooling=False;Application Name=azdata-GeneralConnection" + /// + /// A connection string coming over the Data management protocol + private static string GetClusterName(string connectionString) + { + var csb = new SqlConnectionStringBuilder(connectionString); + + // If there is no https:// prefix, add it + Uri uri; + if ((Uri.TryCreate(csb.DataSource, UriKind.Absolute, out uri) || Uri.TryCreate("https://" + csb.DataSource, UriKind.Absolute, out uri)) && + (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)) + { + return uri.AbsoluteUri; + } + + throw new ArgumentException("Expected a URL of the form clustername.kusto.windows.net"); + } + + /// + /// Extracts the database name from the connectionstring, if it exists + /// + /// A connection string coming over the Data management protocol + private static string GetDatabaseName(string connectionString) + { + var csb = new SqlConnectionStringBuilder(connectionString); + + return csb.InitialCatalog; + } + + /// + /// SchemaState used for getting intellisense info. + /// + public GlobalState SchemaState { get; private set; } + + /// + /// The AAD user token. + /// + public string UserToken { get; private set; } + + /// + /// The AAD application client id. + /// + public string ApplicationClientId { get; private set; } + + /// + /// The AAD application client key. + /// + public string ApplicationKey { get; private set; } + + // The Kusto query provider. + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ICslQueryProvider KustoQueryProvider + { + get + { + if (_kustoQueryProvider == null) + { + var kcsb = GetKustoConnectionStringBuilder(); + _kustoQueryProvider = KustoClientFactory.CreateCslQueryProvider(kcsb); + } + + return _kustoQueryProvider; + } + } + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ICslAdminProvider KustoAdminProvider + { + get + { + if (_kustoAdminProvider == null) + { + var kcsb = GetKustoConnectionStringBuilder(); + _kustoAdminProvider = KustoClientFactory.CreateCslAdminProvider(kcsb); + if (!string.IsNullOrWhiteSpace(DatabaseName)) + { + _kustoAdminProvider.DefaultDatabaseName = DatabaseName; + } + } + + return _kustoAdminProvider; + } + } + + /// + /// Disposes resources. + /// + /// True if disposing. False otherwise. + protected override void Dispose(bool disposing) + { + // Dispose managed resources. + if (disposing) + { + _kustoQueryProvider?.Dispose(); + _kustoQueryProvider = null; + + _kustoAdminProvider?.Dispose(); + _kustoAdminProvider = null; + } + + base.Dispose(disposing); + } + + #region DataSourceUtils + + /// + /// Executes a query. + /// + /// The query. + /// The results. + public override Task ExecuteQueryAsync(string query, CancellationToken cancellationToken, string databaseName = null) + { + var reader = ExecuteQuery(query, cancellationToken, databaseName); + return Task.FromResult(reader); + } + + private IDataReader ExecuteQuery(string query, CancellationToken cancellationToken, string databaseName = null) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(query, nameof(query)); + + var clientRequestProperties = new ClientRequestProperties + { + ClientRequestId = Guid.NewGuid().ToString() + }; + clientRequestProperties.SetOption(ClientRequestProperties.OptionNoTruncation, true); + + if(cancellationToken != null) + { + cancellationToken.Register(() => CancelQuery(clientRequestProperties.ClientRequestId)); + } + + IDataReader origReader = KustoQueryProvider.ExecuteQuery( + KustoQueryUtils.IsClusterLevelQuery(query) ? "" : databaseName, + query, + clientRequestProperties); + + return new KustoResultsReader(origReader); + } + + private void CancelQuery(string clientRequestId) + { + var query = ".cancel query " + clientRequestId; + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + using (var reader = ExecuteQuery(query, token)) + { + // No-op + } + } + + /// + public override async Task Exists() + { + try + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + var count = await ExecuteScalarQueryAsync(".show databases | count", token); + return count >= 0; + } + catch + { + return false; + } + } + + #endregion + + /// + /// Executes a Kusto control command. + /// + /// The command. + public void ExecuteControlCommand(string command) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(command, nameof(command)); + + using (var adminOutput = KustoAdminProvider.ExecuteControlCommand(command, null)) + { + } + } + + private KustoConnectionStringBuilder GetKustoConnectionStringBuilder() + { + ValidationUtils.IsNotNull(ClusterName, nameof(ClusterName)); + ValidationUtils.IsTrue( + !string.IsNullOrWhiteSpace(UserToken) + || (!string.IsNullOrWhiteSpace(ApplicationClientId) && !string.IsNullOrWhiteSpace(ApplicationKey)), + $"the Kusto authentication is not specified - either set {nameof(UserToken)}, or set {nameof(ApplicationClientId)} and {nameof(ApplicationKey)}"); + + var kcsb = new KustoConnectionStringBuilder + { + DataSource = ClusterName, + + // Perform federated auth based on the AAD user token, or based on the AAD application client id and key. + FederatedSecurity = true + }; + + if (!string.IsNullOrWhiteSpace(DatabaseName)) + { + kcsb.InitialCatalog = DatabaseName; + } + + if (!string.IsNullOrWhiteSpace(UserToken)) + { + kcsb.UserToken = UserToken; + } + + if (!string.IsNullOrWhiteSpace(ApplicationClientId)) + { + kcsb.ApplicationClientId = ApplicationClientId; + } + + if (!string.IsNullOrWhiteSpace(ApplicationKey)) + { + kcsb.ApplicationKey = ApplicationKey; + } + + return kcsb; + } + + #region IDataSource + + protected DiagnosticsInfo GetClusterDiagnostics(){ + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + DiagnosticsInfo clusterDiagnostics = new DiagnosticsInfo(); + + var query = ".show diagnostics | extend Passed= (IsHealthy) and not(IsScaleOutRequired) | extend Summary = strcat('Cluster is ', iif(Passed, '', 'NOT'), 'healthy.'),Details=pack('MachinesTotal', MachinesTotal, 'DiskCacheCapacity', round(ClusterDataCapacityFactor,1)) | project Action = 'Cluster Diagnostics', Category='Info', Summary, Details;"; + using (var reader = ExecuteQuery(query, token)) + { + while(reader.Read()) + { + var details = JsonConvert.DeserializeObject>(reader["Details"].ToString()); + clusterDiagnostics.Options["summary"] = reader["Summary"].ToString(); + clusterDiagnostics.Options["machinesTotal"] = details["MachinesTotal"].ToString(); + clusterDiagnostics.Options["diskCacheCapacity"] = details["DiskCacheCapacity"].ToString() + "%"; + } + } + + return clusterDiagnostics; + } + + /// + private IEnumerable GetDatabaseMetadata(bool includeSizeDetails) + { + if (_databaseMetadata == null) + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + // Getting database names when we are connected to a specific database should not happen. + ValidationUtils.IsNotNull(DatabaseName, nameof(DatabaseName)); + + var query = ".show databases" + (this.ClusterName.IndexOf(AriaProxyURL, StringComparison.CurrentCultureIgnoreCase) == -1 ? " | project DatabaseName, PrettyName" : ""); + + if (includeSizeDetails == true){ + query = ".show cluster extents | summarize sum(OriginalSize) by tostring(DatabaseName)"; + } + + using (var reader = ExecuteQuery(query, token)) + { + _databaseMetadata = reader.ToEnumerable() + .Where(row => !string.IsNullOrWhiteSpace(row["DatabaseName"].ToString())) + .Select(row => new DatabaseMetadata + { + ClusterName = this.ClusterName, + MetadataType = DataSourceMetadataType.Database, + MetadataTypeName = DataSourceMetadataType.Database.ToString(), + SizeInMB = includeSizeDetails == true ? row["sum_OriginalSize"].ToString() : null, + Name = row["DatabaseName"].ToString(), + PrettyName = includeSizeDetails == true ? row["DatabaseName"].ToString(): (String.IsNullOrEmpty(row["PrettyName"]?.ToString()) ? row["DatabaseName"].ToString() : row["PrettyName"].ToString()), + Urn = $"{this.ClusterName}.{row["DatabaseName"].ToString()}" + }) + .Materialize() + .OrderBy(row => row.Name, StringComparer.Ordinal); // case-sensitive + } + } + + return _databaseMetadata; + } + + /// + public override bool Exists(DataSourceObjectMetadata objectMetadata) + { + ValidationUtils.IsNotNull(objectMetadata, "Need a datasource object"); + + switch(objectMetadata.MetadataType) + { + case DataSourceMetadataType.Database: return DatabaseExists(objectMetadata.Name).Result; + default: throw new ArgumentException($"Unexpected type {objectMetadata.MetadataType}."); + } + } + + /// + /// Executes a query or command against a kusto cluster and returns a sequence of result row instances. + /// + public override async Task> ExecuteControlCommandAsync(string command, bool throwOnError, CancellationToken cancellationToken) + { + try + { + var resultReader = await ExecuteQueryAsync(command, cancellationToken, DatabaseName); + var results = KustoDataReaderParser.ParseV1(resultReader, null); + var tableReader = results[WellKnownDataSet.PrimaryResult].Single().TableData.CreateDataReader(); + return new ObjectReader(tableReader); + } + catch (Exception) when (!throwOnError) + { + return null; + } + } + + /// + public override void UpdateDatabase(string databaseName){ + DatabaseName = databaseName; + SchemaState = Task.Run(() => KustoIntellisenseHelper.AddOrUpdateDatabaseAsync(this, GlobalState.Default, DatabaseName, ClusterName, throwOnError: false)).Result; + } + + /// + public override LanguageServices.Contracts.CompletionItem[] GetAutoCompleteSuggestions(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false){ + var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, SchemaState); + var script = CodeScript.From(scriptDocumentInfo.Contents, SchemaState); + script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character, out int position); // Gets the actual offset based on line and local offset + + var completion = kustoCodeService.GetCompletionItems(position); + scriptDocumentInfo.ScriptParseInfo.CurrentSuggestions = completion.Items; // this is declaration item so removed for now, but keep the info when api gets updated + + List completions = new List(); + foreach (var autoCompleteItem in completion.Items) + { + var label = autoCompleteItem.DisplayText; + completions.Add(AutoCompleteHelper.CreateCompletionItem(label, label + " keyword", label, KustoIntellisenseHelper.CreateCompletionItemKind(autoCompleteItem.Kind), scriptDocumentInfo.StartLine, scriptDocumentInfo.StartColumn, textPosition.Character)); + } + + return completions.ToArray(); + } + + /// + public override Hover GetHoverHelp(ScriptDocumentInfo scriptDocumentInfo, Position textPosition, bool throwOnError = false){ + var kustoCodeService = new KustoCodeService(scriptDocumentInfo.Contents, SchemaState); + var script = CodeScript.From(scriptDocumentInfo.Contents, SchemaState); + script.TryGetTextPosition(textPosition.Line + 1, textPosition.Character, out int position); + + var quickInfo = kustoCodeService.GetQuickInfo(position); + + return AutoCompleteHelper.ConvertQuickInfoToHover( + quickInfo.Text, + "kusto", + scriptDocumentInfo.StartLine, + scriptDocumentInfo.StartColumn, + textPosition.Character); + + } + + /// + public override DefinitionResult GetDefinition(string queryText, int index, int startLine, int startColumn, bool throwOnError = false){ + var abc = KustoCode.ParseAndAnalyze(queryText, SchemaState); //TODOKusto: API wasnt working properly, need to check that part. + var kustoCodeService = new KustoCodeService(abc); + //var kustoCodeService = new KustoCodeService(queryText, globals); + var relatedInfo = kustoCodeService.GetRelatedElements(index); + + if (relatedInfo != null && relatedInfo.Elements.Count > 1) + { + + } + + return null; + } + + /// + public override ScriptFileMarker[] GetSemanticMarkers(ScriptParseInfo parseInfo, ScriptFile scriptFile, string queryText) + { + var kustoCodeService = new KustoCodeService(queryText, SchemaState); + var script = CodeScript.From(queryText, SchemaState); + var parseResult = kustoCodeService.GetDiagnostics(); + + + parseInfo.ParseResult = parseResult; + + // build a list of Kusto script file markers from the errors. + List markers = new List(); + if (parseResult != null && parseResult.Count() > 0) + { + foreach (var error in parseResult) + { + script.TryGetLineAndOffset(error.Start, out var startLine, out var startOffset); + script.TryGetLineAndOffset(error.End, out var endLine, out var endOffset); + + // vscode specific format for error markers. + markers.Add(new ScriptFileMarker() + { + Message = error.Message, + Level = ScriptFileMarkerLevel.Error, + ScriptRegion = new ScriptRegion() + { + File = scriptFile.FilePath, + StartLineNumber = startLine, + StartColumnNumber = startOffset, + StartOffset = 0, + EndLineNumber = endLine, + EndColumnNumber = endOffset, + EndOffset = 0 + } + }); + } + } + + return markers.ToArray(); + } + + /// + public override void Refresh() + { + // This class caches objects. Throw them away so that the next call will re-query the data source for the objects. + _databaseMetadata = null; + _tableMetadata = new ConcurrentDictionary>(); + _columnMetadata = new ConcurrentDictionary>(); + _folderMetadata = new ConcurrentDictionary>(); + _functionMetadata = new ConcurrentDictionary>(); + } + + /// + public override void Refresh(DataSourceObjectMetadata objectMetadata) + { + ValidationUtils.IsNotNull(objectMetadata, nameof(objectMetadata)); + + switch(objectMetadata.MetadataType) + { + case DataSourceMetadataType.Cluster: + Refresh(); + break; + + case DataSourceMetadataType.Database: + _tableMetadata.TryRemove(objectMetadata.Name, out _); + break; + + case DataSourceMetadataType.Table: + var tm = objectMetadata as TableMetadata; + _columnMetadata.TryRemove(GenerateMetadataKey(tm.DatabaseName, tm.Name), out _); + break; + + case DataSourceMetadataType.Column: + // Remove column metadata for the whole table + var cm = objectMetadata as ColumnMetadata; + _columnMetadata.TryRemove(GenerateMetadataKey(cm.DatabaseName, cm.TableName), out _); + break; + + case DataSourceMetadataType.Function: + var fm = objectMetadata as FunctionMetadata; + _functionMetadata.TryRemove(GenerateMetadataKey(fm.DatabaseName, fm.Name), out _); + break; + + case DataSourceMetadataType.Folder: + var folder = objectMetadata as FolderMetadata; + _folderMetadata.TryRemove(GenerateMetadataKey(folder.ParentMetadata.Name, folder.Name), out _); + break; + + default: + throw new ArgumentException($"Unexpected type {objectMetadata.MetadataType}."); + } + } + + /// + public override IEnumerable GetChildObjects(DataSourceObjectMetadata objectMetadata, bool includeSizeDetails) + { + ValidationUtils.IsNotNull(objectMetadata, nameof(objectMetadata)); + + switch(objectMetadata.MetadataType) + { + case DataSourceMetadataType.Cluster: // show databases + return GetDatabaseMetadata(includeSizeDetails); + + case DataSourceMetadataType.Database: // show folders, tables, and functions + return GetDatabaseSchema(objectMetadata, includeSizeDetails); + + case DataSourceMetadataType.Table: // show columns + var table = objectMetadata as TableMetadata; + return GetTableSchema(table); + + case DataSourceMetadataType.Folder: // show subfolders, functions, and tables + var folder = objectMetadata as FolderMetadata; + return GetAllMetadata(folder.Urn); + + default: + throw new ArgumentException($"Unexpected type {objectMetadata.MetadataType}."); + } + } + + public override DiagnosticsInfo GetDiagnostics(DataSourceObjectMetadata objectMetadata) + { + ValidationUtils.IsNotNull(objectMetadata, nameof(objectMetadata)); + + // Add more cases when required. + switch(objectMetadata.MetadataType) + { + case DataSourceMetadataType.Cluster: + return GetClusterDiagnostics(); + + default: + throw new ArgumentException($"Unexpected type {objectMetadata.MetadataType}."); + } + } + + internal async Task DatabaseExists(string databaseName) + { + ValidationUtils.IsArgumentNotNullOrWhiteSpace(databaseName, nameof(databaseName)); + + try + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + var count = await ExecuteScalarQueryAsync(".show tables | count", token, databaseName); + return count >= 0; + } + catch + { + return false; + } + } + + /// + private IEnumerable GetDatabaseSchema(DataSourceObjectMetadata objectMetadata, bool includeSizeDetails) + { + // Check if the database exists + ValidationUtils.IsTrue(DatabaseExists(objectMetadata.Name).Result, $"Database '{objectMetadata}' does not exist."); + + var allMetadata = GetAllMetadata(objectMetadata.Urn); + + // if the records have already been loaded them return them + if (allMetadata.Any()) + { + return allMetadata; + } + + LoadTableSchema(objectMetadata); + LoadFunctionSchema(objectMetadata); + + if (!includeSizeDetails) + { + return GetAllMetadata(objectMetadata.Urn); + } + + string newKey = $"{DatabaseKeyPrefix}.{objectMetadata.Urn}"; + return _tableMetadata[newKey].OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase); + } + + private IEnumerable GetAllMetadata(string key) + { + var returnList = new List(); + + if (_folderMetadata.ContainsKey(key)) + { + returnList.AddRange(_folderMetadata[key] + .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + } + + if (_tableMetadata.ContainsKey(key)) + { + returnList.AddRange(_tableMetadata[key] + .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + } + + if (_functionMetadata.ContainsKey(key)) + { + returnList.AddRange(_functionMetadata[key] + .OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase)); + } + + return returnList; + } + + /// + /// Gets column data which includes tables and table folders. + /// + /// + /// + /// + private IEnumerable GetColumnInfos(string databaseName, string tableName) + { + ValidationUtils.IsNotNullOrWhitespace(databaseName, nameof(databaseName)); + + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + const string systemPrefix = "System."; + var query = new StringBuilder(string.Format(CultureInfo.InvariantCulture, ShowDatabaseSchema, + databaseName)); + query.Append($" | where TableName == '{tableName}' "); + query.Append(" | project TableName, ColumnName, ColumnType, Folder"); + + using (var reader = ExecuteQuery(query.ToString(), token, databaseName)) + { + var columns = reader.ToEnumerable() + .Select(row => new ColumnInfo + { + Table = row["TableName"]?.ToString(), + Name = row["ColumnName"]?.ToString(), + DataType = row["ColumnType"]?.ToString().TrimPrefix(systemPrefix), + Folder = row["Folder"]?.ToString() + }) + .Materialize() + .OrderBy(row => row.Name, StringComparer.Ordinal); // case-sensitive + + return columns; + } + } + + private IEnumerable GetTableInfos(string databaseName) + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + string query = $".show database {databaseName} cslschema"; + + using (var reader = ExecuteQuery(query, token, databaseName)) + { + return reader.ToEnumerable() + .Select(row => new TableInfo + { + TableName = row["TableName"]?.ToString(), + Folder = row["Folder"]?.ToString() + }) + .Materialize(); + } + } + + private void LoadTableSchema(DataSourceObjectMetadata databaseMetadata) + { + var tableInfos = GetTableInfos(databaseMetadata.Name); + + if (!tableInfos.Any()) + { + return; + } + + var rootTableFolderKey = new StringBuilder($"{databaseMetadata.Urn}"); + if (tableInfos.Any(x => !string.IsNullOrWhiteSpace(x.Folder))) + { + // create Table folder to hold functions tables + var tableFolder = DataSourceFactory.CreateFolderMetadata(databaseMetadata, rootTableFolderKey.ToString(), "Tables"); + _folderMetadata.AddRange(rootTableFolderKey.ToString(), new List {tableFolder}); + rootTableFolderKey.Append($".{tableFolder.Name}"); + + SetFolderMetadataForTables(databaseMetadata, tableInfos, rootTableFolderKey.ToString()); + } + + SetTableMetadata(databaseMetadata, tableInfos, rootTableFolderKey.ToString()); + } + + private IEnumerable GetTableSchema(TableMetadata tableMetadata) + { + var key = GenerateMetadataKey(tableMetadata.DatabaseName, tableMetadata.Name); + if (_columnMetadata.ContainsKey(key)) + { + return _columnMetadata[key]; + } + + IEnumerable columnInfos = GetColumnInfos(tableMetadata.DatabaseName, tableMetadata.Name); + + if (!columnInfos.Any()) + { + return Enumerable.Empty(); + } + + SetColumnMetadata(tableMetadata.DatabaseName, tableMetadata.Name, columnInfos); + + return _columnMetadata[key]; + } + + private void SetFolderMetadataForTables(DataSourceObjectMetadata objectMetadata, IEnumerable tableInfos, string rootTableFolderKey) + { + var tablesByFolder = tableInfos + .GroupBy(x => x.Folder, StringComparer.OrdinalIgnoreCase) + .ToList(); + + var tableFolders = new List(); + + foreach (var columnGroup in tablesByFolder) + { + // skip tables without folders + if (string.IsNullOrWhiteSpace(columnGroup.Key)) + { + continue; + } + + var folder = DataSourceFactory.CreateFolderMetadata(objectMetadata, rootTableFolderKey, columnGroup.Key); + tableFolders.Add(folder); + } + + _folderMetadata.AddRange(rootTableFolderKey, tableFolders); + } + + private void LoadFunctionSchema(DataSourceObjectMetadata databaseMetadata) + { + IEnumerable functionInfos = GetFunctionInfos(databaseMetadata.Name); + + if (!functionInfos.Any()) + { + return; + } + + // create Functions folder to hold functions folders + var rootFunctionFolderKey = $"{databaseMetadata.Urn}"; + var rootFunctionFolder = DataSourceFactory.CreateFolderMetadata(databaseMetadata, rootFunctionFolderKey, "Functions"); + _folderMetadata.AddRange(rootFunctionFolderKey, new List {rootFunctionFolder}); + + // create each folder to hold functions + var functionsGroupByFolder = functionInfos + .GroupBy(x => x.Folder, StringComparer.OrdinalIgnoreCase) + .ToList(); + + if (functionsGroupByFolder.Any()) + { + SetFolderMetadataForFunctions(databaseMetadata, functionsGroupByFolder, rootFunctionFolder); + } + + SetFunctionMetadata(databaseMetadata.Name, rootFunctionFolder.Name, functionsGroupByFolder); + } + + private void SetFolderMetadataForFunctions(DataSourceObjectMetadata databaseMetadata, List> functionsGroupByFolder, + FolderMetadata functionFolder) + { + var functionFolders = new Dictionary>(); + + foreach (var functionGroup in functionsGroupByFolder) + { + // skip functions with no folder + if (string.IsNullOrWhiteSpace(functionGroup.Key)) + { + continue; + } + + // folders are in the following format: folder1/folder2/folder3/folder4 + var subFolders = functionGroup.Key.Replace(@"\", @"/").Split(@"/"); + var topFolder = subFolders.First(); + + var folderKey = functionFolder.Urn; + var folder = DataSourceFactory.CreateFolderMetadata(databaseMetadata, folderKey, topFolder); + functionFolders.SafeAdd(folderKey, folder); + + for (int i = 1; i < subFolders.Length; i++) + { + folderKey = $"{folderKey}.{subFolders[i - 1]}"; + var subFolder = DataSourceFactory.CreateFolderMetadata(databaseMetadata, folderKey, subFolders[i]); + functionFolders.SafeAdd(folderKey, subFolder); + } + } + + foreach (var folder in functionFolders) + { + _folderMetadata.AddRange(folder.Key, folder.Value.Values.ToList()); + } + } + + private void SetColumnMetadata(string databaseName, string tableName, IEnumerable columnInfos) + { + var columns = columnInfos + .Where(row => + !string.IsNullOrWhiteSpace(row.Table) + && !string.IsNullOrWhiteSpace(row.Name) + && !string.IsNullOrWhiteSpace(row.DataType)); + + var columnMetadatas = new SortedList(); + + foreach (ColumnInfo columnInfo in columns) + { + var column = new ColumnMetadata + { + ClusterName = ClusterName, + DatabaseName = databaseName, + TableName = tableName, + MetadataType = DataSourceMetadataType.Column, + MetadataTypeName = DataSourceMetadataType.Column.ToString(), + Name = columnInfo.Name, + PrettyName = columnInfo.Name, + Urn = $"{ClusterName}.{databaseName}.{tableName}.{columnInfo.Name}", + DataType = columnInfo.DataType + }; + + columnMetadatas.Add(column.PrettyName, column); + } + + _columnMetadata[GenerateMetadataKey(databaseName, tableName)] = columnMetadatas.Values; + } + + private void SetTableMetadata(DataSourceObjectMetadata databaseName, IEnumerable tableInfos, string rootTableFolderKey) + { + var tableFolders = new Dictionary> + { + {$"{DatabaseKeyPrefix}.{databaseName.Urn}", new List()} + }; + + foreach (var table in tableInfos) + { + var tableKey = new StringBuilder(rootTableFolderKey); + + if (!string.IsNullOrWhiteSpace(table.Folder)) + { + tableKey.Append($".{table.Folder}"); + } + + var tableMetadata = new TableMetadata + { + ClusterName = ClusterName, + DatabaseName = databaseName.Name, + MetadataType = DataSourceMetadataType.Table, + MetadataTypeName = DataSourceMetadataType.Table.ToString(), + Name = table.TableName, + PrettyName = table.TableName, + Folder = table.Folder, + Urn = $"{tableKey}.{table.TableName}" + }; + + if (tableFolders.ContainsKey(tableKey.ToString())) + { + tableFolders[tableKey.ToString()].Add(tableMetadata); + } + else + { + tableFolders[tableKey.ToString()] = new List{tableMetadata}; + } + + // keep a list of all tables for the database + // this is used for the dashboard + tableFolders[$"{DatabaseKeyPrefix}.{databaseName.Urn}"].Add(tableMetadata); + } + + foreach (var table in tableFolders) + { + _tableMetadata.AddRange(table.Key, table.Value); + } + } + + private void SetFunctionMetadata(string databaseName, string rootFunctionFolderKey, + List> functionGroupByFolder) + { + foreach (var functionGroup in functionGroupByFolder) + { + var stringBuilder = new StringBuilder(rootFunctionFolderKey); + + if (!string.IsNullOrWhiteSpace(functionGroup.Key)) + { + stringBuilder.Append("."); + + // folders are in the following format: folder1/folder2/folder3/folder4 + var folderKey = functionGroup.Key + .Replace(@"\", ".") + .Replace(@"/", "."); + + stringBuilder.Append(folderKey); + } + + var functionKey = $"{ClusterName}.{databaseName}.{stringBuilder}"; + var functions = new List(); + + foreach (FunctionInfo functionInfo in functionGroup) + { + var function = new FunctionMetadata + { + DatabaseName = databaseName, + Parameters = functionInfo.Parameters, + Body = functionInfo.Body, + MetadataType = DataSourceMetadataType.Function, + MetadataTypeName = DataSourceMetadataType.Function.ToString(), + Name = $"{functionInfo.Name}{functionInfo.Parameters}", + PrettyName = functionInfo.Name, + Urn = $"{functionKey}.{functionInfo.Name}" + }; + + functions.Add(function); + } + + _functionMetadata.AddRange(functionKey, functions); + } + } + + private IEnumerable GetFunctionInfos(string databaseName) + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + string query = ".show functions"; + + using (var reader = ExecuteQuery(query, token, databaseName)) + { + return reader.ToEnumerable() + .Select(row => new FunctionInfo + { + Name = row["Name"]?.ToString(), + Body = row["Body"]?.ToString(), + DocString = row["DocString"]?.ToString(), + Folder = row["Folder"]?.ToString(), + Parameters = row["Parameters"]?.ToString() + }) + .Materialize(); + } + } + + private FunctionInfo GetFunctionInfo(string functionName) + { + CancellationTokenSource source = new CancellationTokenSource(); + CancellationToken token = source.Token; + + string query = $".show function {functionName}"; + + using (var reader = ExecuteQuery(query, token, DatabaseName)) + { + return reader.ToEnumerable() + .Select(row => new FunctionInfo + { + Name = row["Name"]?.ToString(), + Body = row["Body"]?.ToString(), + DocString = row["DocString"]?.ToString(), + Folder = row["Folder"]?.ToString(), + Parameters = row["Parameters"]?.ToString() + }) + .FirstOrDefault(); + } + } + + public override string GenerateAlterFunctionScript(string functionName) + { + var functionInfo = GetFunctionInfo(functionName); + + if (functionInfo == null) + { + return string.Empty; + } + + var alterCommand = new StringBuilder(); + + alterCommand.Append(".alter function with "); + alterCommand.Append($"(folder = \"{functionInfo.Folder}\", docstring = \"{functionInfo.DocString}\", skipvalidation = \"false\" ) "); + alterCommand.Append($"{functionInfo.Name}{functionInfo.Parameters} "); + alterCommand.Append($"{functionInfo.Body}"); + + return alterCommand.ToString(); + } + + private string GenerateMetadataKey(string databaseName, string objectName) + { + return string.IsNullOrWhiteSpace(objectName) ? databaseName : $"{databaseName}.{objectName}"; + } + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs new file mode 100644 index 0000000000..bfc2a201f6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoQueryUtils.cs @@ -0,0 +1,115 @@ +// +// Copyright (c) Microsoft. All Rights Reserved. +// +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Linq; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + public static class KustoQueryUtils + { + public const string StatementSeparator = "\n | "; // Start each statement on a new line. Not required by Kusto, but doing this for readability of scripts generated from here. + + /// + /// Escape table/column/database names for a Kusto query. + /// + /// The name to be escaped + /// Always escape if this flag is set + /// The escaped string + public static string EscapeName(string name, bool alwaysEscape = false) + { + if (name.StartsWith("[@") || name == "*") // Field already escaped. No escaping required for '*' operand + { + return name; + } + + string result = name; + Regex rx = new Regex("[^_a-zA-Z0-9]"); + string [] kustoKeywordList = {"and", "anomalychart", "areachart", "asc", "barchart", "between", "bool", "boolean", "by", + "columnchart", "consume", "contains", "containscs", "count", "date", "datetime", "default", "desc", "distinct", + "double", "dynamic", "endswith", "evaluate", "extend", "false", "filter", "find", "first", "flags", "float", + "getschema", "has", "hasprefix", "hassuffix", "in", "int", "join", "journal", "kind", "ladderchart", "last", + "like", "limit", "linechart", "long", "materialize", "mvexpand", "notcontains", "notlike", "of", "or", "order", + "parse", "piechart", "pivotchart", "print", "project", "queries", "real", "regex", "sample", "scatterchart", + "search", "set", "sort", "stacked", "stacked100", "stackedareachart", "startswith", "string", "summarize", + "take", "time", "timechart", "timeline", "timepivot", "timespan", "to", "top", "toscalar", "true", "union", + "unstacked", "viewers", "where", "withsource"}; // add more keywords here + + var escapeName = rx.IsMatch(name) || kustoKeywordList.Any(name.Contains) || alwaysEscape; + if (escapeName) + { + if (name.IndexOf('"') > -1) + { + result = "[@'" + name + "']"; + } + else + { + result = "[@\"" + name + "\"]"; + } + } + + return result; + } + + + public static bool IsClusterLevelQuery(string query) + { + string [] clusterLevelQueryPrefixes = { + ".show databases", + ".show schema" + }; + + return clusterLevelQueryPrefixes.Any(query.StartsWith); + } + + /// + /// Adds an object of type DataSourceObjectMetadata to a dictionary>. If the key exists then the item is added + /// to the list. If not then the key is created and then added. + /// + /// The dictionary of the dictionary that the list should be added to. + /// The key to be added. + /// The metadata to be added to the list. + /// + public static void SafeAdd(this Dictionary> dictionary, string key, + T metadata) where T : DataSourceObjectMetadata + { + if (dictionary.ContainsKey(key)) + { + if (dictionary[key].ContainsKey(metadata.Name)) + { + return; + } + + dictionary[key].Add(metadata.Name, metadata); + } + else + { + dictionary[key] = new Dictionary {{metadata.Name, metadata}}; + } + } + + /// + /// Add a range to a dictionary of ConcurrentDictionary. Adds range to existing IEnumerable within dictionary + /// at the same key. + /// + /// + /// + /// + /// + public static void AddRange(this ConcurrentDictionary> dictionary, string key, + List metadatas) where T : DataSourceObjectMetadata + { + if (dictionary.ContainsKey(key)) + { + metadatas.AddRange(dictionary[key]); + } + + dictionary[key] = metadatas.OrderBy(x => x.PrettyName, StringComparer.OrdinalIgnoreCase).ToList(); + } + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoResultsReader.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoResultsReader.cs new file mode 100644 index 0000000000..c5bea819fb --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/KustoResultsReader.cs @@ -0,0 +1,22 @@ +using System.Data; + +namespace Microsoft.Kusto.ServiceLayer.DataSource +{ + internal class KustoResultsReader : DataReaderWrapper + { + public KustoResultsReader(IDataReader reader) + : base(reader) + { + } + + /// + /// Kusto returns 3 results tables - QueryResults, QueryProperties, QueryStatus. When returning query results + /// we want the caller to only read the first table. We override the NextResult function here to only return one table + /// from the IDataReader. + /// + /*public override bool NextResult() + { + return false; + }*/ + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/ColumnMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/ColumnMetadata.cs new file mode 100644 index 0000000000..183e9d1ff5 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/ColumnMetadata.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Column metadata information + /// + public class ColumnMetadata : TableMetadata + { + public string TableName { get; set; } + public string DataType { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceMetadataType.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceMetadataType.cs new file mode 100644 index 0000000000..097b097426 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceMetadataType.cs @@ -0,0 +1,15 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Metadata type enumeration + /// + public enum DataSourceMetadataType + { + Cluster = 0, + Database = 1, + Table = 2, + Column = 3, + Function = 4, + Folder = 5 + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceObjectMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceObjectMetadata.cs new file mode 100644 index 0000000000..97d98c5a04 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DataSourceObjectMetadata.cs @@ -0,0 +1,20 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Object metadata information + /// + public class DataSourceObjectMetadata + { + public DataSourceMetadataType MetadataType { get; set; } + + public string MetadataTypeName { get; set; } + + public string Name { get; set; } + + public string PrettyName { get; set; } + + public string Urn { get; set; } + + public string SizeInMB { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DatabaseMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DatabaseMetadata.cs new file mode 100644 index 0000000000..1b6e072a42 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/DatabaseMetadata.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Database metadata information + /// + public class DatabaseMetadata : DataSourceObjectMetadata + { + public string ClusterName { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FolderMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FolderMetadata.cs new file mode 100644 index 0000000000..eabde5845f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FolderMetadata.cs @@ -0,0 +1,10 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Folder metadata information + /// + public class FolderMetadata : DataSourceObjectMetadata + { + public DataSourceObjectMetadata ParentMetadata { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FunctionMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FunctionMetadata.cs new file mode 100644 index 0000000000..f0134cf4fe --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/FunctionMetadata.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + public class FunctionMetadata : DatabaseMetadata + { + public string DatabaseName { get; set; } + + public string Parameters { get; set; } + + public string Body { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/TableMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/TableMetadata.cs new file mode 100644 index 0000000000..578e35cb5c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Metadata/TableMetadata.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Metadata +{ + /// + /// Database metadata information + /// + public class TableMetadata : DatabaseMetadata + { + public string DatabaseName { get; set; } + public string Folder { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/ColumnInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/ColumnInfo.cs new file mode 100644 index 0000000000..01514f42b6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/ColumnInfo.cs @@ -0,0 +1,26 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Models +{ + public class ColumnInfo + { + /// + /// The table name. + /// + public string Table { get; set; } + + /// + /// The column name. + /// + public string Name { get; set; } + + /// + /// The data type. + /// + public string DataType { get; set; } + + + /// + /// The folder name. + /// + public string Folder { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/FunctionInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/FunctionInfo.cs new file mode 100644 index 0000000000..9db9096aa9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/FunctionInfo.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Models +{ + public class FunctionInfo + { + public string Name { get; set; } + public string Parameters { get; set; } + public string Body { get; set; } + public string Folder { get; set; } + public string DocString { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/TableInfo.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/TableInfo.cs new file mode 100644 index 0000000000..ad1c51f222 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/Models/TableInfo.cs @@ -0,0 +1,8 @@ +namespace Microsoft.Kusto.ServiceLayer.DataSource.Models +{ + public class TableInfo + { + public string TableName { get; set; } + public string Folder { get; set; } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs b/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs new file mode 100644 index 0000000000..dd1e0bb56e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/DataSource/ReliableDataSourceConnection.cs @@ -0,0 +1,258 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +// This code is copied from the source described in the comment below. + +// ======================================================================================= +// Microsoft Windows Server AppFabric Customer Advisory Team (CAT) Best Practices Series +// +// This sample is supplemental to the technical guidance published on the community +// blog at http://blogs.msdn.com/appfabriccat/ and copied from +// sqlmain ./sql/manageability/mfx/common/ +// +// ======================================================================================= +// Copyright © 2012 Microsoft Corporation. All rights reserved. +// +// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER +// EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. YOU BEAR THE RISK OF USING IT. +// ======================================================================================= + +using System; +using System.Collections.Generic; +using System.Data; +using System.Collections; +using System.Data.Common; +using System.Data.SqlClient; +using System.Diagnostics; +using System.Globalization; +using System.Text; +using System.Threading; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Microsoft.SqlTools.Utility; +using Microsoft.SqlTools.ServiceLayer.Connection.ReliableConnection; +using Microsoft.Kusto.ServiceLayer.DataSource; + +namespace Microsoft.Kusto.ServiceLayer.Connection +{ + /// + /// Provides a reliable way of opening connections to and executing commands + /// taking into account potential network unreliability and a requirement for connection retry. + /// + public sealed partial class ReliableDataSourceConnection : IDisposable + { + private IDataSource _dataSource; + private readonly RetryPolicy _connectionRetryPolicy; + private RetryPolicy _commandRetryPolicy; + private Guid _azureSessionId = Guid.NewGuid(); + + private string _connectionString; + private string _azureAccountToken; + + /// + /// Initializes a new instance of the ReliableKustoClient class with a given connection string + /// and a policy defining whether to retry a request if the connection fails to be opened or a command + /// fails to be successfully executed. + /// + /// The connection string used to open the SQL Azure database. + /// The retry policy defining whether to retry a request if a connection fails to be established. + /// The retry policy defining whether to retry a request if a command fails to be executed. + public ReliableDataSourceConnection(string connectionString, RetryPolicy connectionRetryPolicy, RetryPolicy commandRetryPolicy, string azureAccountToken) + { + _connectionString = connectionString; + _azureAccountToken = azureAccountToken; + _dataSource = DataSourceFactory.Create(DataSourceType.Kusto, connectionString, azureAccountToken); + + _connectionRetryPolicy = connectionRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy(); + _commandRetryPolicy = commandRetryPolicy ?? RetryPolicyFactory.CreateNoRetryPolicy(); + + _connectionRetryPolicy.RetryOccurred += RetryConnectionCallback; + _commandRetryPolicy.RetryOccurred += RetryCommandCallback; + } + + private void RetryCommandCallback(RetryState retryState) + { + RetryPolicyUtils.RaiseSchemaAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.CommandRetry, _azureSessionId); + } + + private void RetryConnectionCallback(RetryState retryState) + { + RetryPolicyUtils.RaiseSchemaAmbientRetryMessage(retryState, SqlSchemaModelErrorCodes.ServiceActions.ConnectionRetry, _azureSessionId); + } + + /// + /// Disposes resources. + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Performs application-defined tasks associated with freeing, releasing, or + /// resetting managed and unmanaged resources. + /// + /// A flag indicating that managed resources must be released. + public void Dispose(bool disposing) + { + if (disposing) + { + if (_connectionRetryPolicy != null) + { + _connectionRetryPolicy.RetryOccurred -= RetryConnectionCallback; + } + + if (_commandRetryPolicy != null) + { + _commandRetryPolicy.RetryOccurred -= RetryCommandCallback; + } + + _dataSource.Dispose(); + } + } + + /// + /// Gets or sets the connection string for opening a connection to the SQL Azure database. + /// + public string ConnectionString { get; set; } + + /// + /// Gets the policy which decides whether to retry a connection request, based on how many + /// times the request has been made and the reason for the last failure. + /// + public RetryPolicy ConnectionRetryPolicy + { + get { return _connectionRetryPolicy; } + } + + /// + /// Gets the policy which decides whether to retry a command, based on how many + /// times the request has been made and the reason for the last failure. + /// + public RetryPolicy CommandRetryPolicy + { + get { return _commandRetryPolicy; } + set + { + Validate.IsNotNull(nameof(value), value); + + if (_commandRetryPolicy != null) + { + _commandRetryPolicy.RetryOccurred -= RetryCommandCallback; + } + + _commandRetryPolicy = value; + _commandRetryPolicy.RetryOccurred += RetryCommandCallback; + } + } + + /// + /// Gets the server name from the underlying connection. + /// + public string ClusterName + { + get { return _dataSource.ClusterName; } + } + + /// + /// If the underlying SqlConnection absolutely has to be accessed, for instance + /// to pass to external APIs that require this type of connection, then this + /// can be used. + /// + /// + public IDataSource GetUnderlyingConnection() + { + return _dataSource; + } + + /// + /// Changes the current database for an open Connection object. + /// + /// The name of the database to use in place of the current database. + public void ChangeDatabase(string databaseName) + { + _dataSource.UpdateDatabase(databaseName); + } + + /// + /// Opens a database connection with the settings specified by the ConnectionString + /// property of the provider-specific Connection object. + /// + public void Open() + { + // TODOKusto: Should we initialize in the constructor or here. Set a breapoint and check. + // Check if retry policy was specified, if not, disable retries by executing the Open method using RetryPolicy.NoRetry. + if(_dataSource == null) + { + _connectionRetryPolicy.ExecuteAction(() => + { + _dataSource = DataSourceFactory.Create(DataSourceType.Kusto, _connectionString, _azureAccountToken); + }); + } + } + + /// + /// Opens a database connection with the settings specified by the ConnectionString + /// property of the provider-specific Connection object. + /// + public Task OpenAsync(CancellationToken token) + { + // Make sure that the token isn't cancelled before we try + if (token.IsCancellationRequested) + { + return Task.FromCanceled(token); + } + + // Check if retry policy was specified, if not, disable retries by executing the Open method using RetryPolicy.NoRetry. + try + { + return _connectionRetryPolicy.ExecuteAction(async () => + { + await Task.Run(() => Open()); + }); + } + catch (Exception e) + { + return Task.FromException(e); + } + } + + /// + /// Closes the connection to the database. + /// + public void Close() + { + } + + /// + /// Gets the time to wait while trying to establish a connection before terminating + /// the attempt and generating an error. + /// + public int ConnectionTimeout + { + get { return 30; } + } + + /// + /// Gets the name of the current database or the database to be used after a + /// connection is opened. + /// + public string Database + { + get { return _dataSource.DatabaseName; } + } + + private void VerifyConnectionOpen(ReliableDataSourceConnection conn) + { + if(conn.GetUnderlyingConnection() == null) + { + conn.Open(); + } + } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs b/src/Microsoft.Kusto.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs new file mode 100644 index 0000000000..dc09a86d8d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Formatter/Contracts/DocumentFormatting.cs @@ -0,0 +1,113 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Formatter.Contracts +{ + /// + /// A formatting request to process an entire document + /// + public class DocumentFormattingRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/formatting"); + } + + /// + /// A formatting request to process a specific range inside a document + /// + public class DocumentRangeFormattingRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/rangeFormatting"); + } + + /// + /// A formatting request to handle a user typing, giving a chance to update the text based on this + /// + public class DocumentOnTypeFormattingRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/onTypeFormatting"); + } + + + /// + /// Params for the + /// + public class DocumentFormattingParams + { + + /// + /// The document to format. + /// + public TextDocumentIdentifier TextDocument { get; set; } + + /// + /// The formatting options + /// + public FormattingOptions Options { get; set; } + + } + + + /// + /// Params for the + /// + public class DocumentRangeFormattingParams : DocumentFormattingParams + { + + /// + /// The range to format + /// + public Range Range { get; set; } + + } + + /// + /// Params for the + /// + public class DocumentOnTypeFormattingParams : DocumentFormattingParams + { + /// + /// The position at which this request was sent. + + /// + Position Position { get; set; } + + /// + /// The character that has been typed. + + /// + string Ch { get; set; } + } + + /// + /// Value-object describing what options formatting should use. + /// + public class FormattingOptions + { + /// + /// Size of a tab in spaces + /// + public int TabSize { get; set; } + + /// + /// Prefer spaces over tabs. + /// + public bool InsertSpaces { get; set; } + + // TODO there may be other options passed by VSCode - format is + // [key: string]: boolean | number | string; + // Determine how these might be passed and add them here +} + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Formatter/Impl/FormatOptions.cs b/src/Microsoft.Kusto.ServiceLayer/Formatter/Impl/FormatOptions.cs new file mode 100644 index 0000000000..82ff23ecda --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Formatter/Impl/FormatOptions.cs @@ -0,0 +1,171 @@ +// +// 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.ComponentModel; + +namespace Microsoft.Kusto.ServiceLayer.Formatter +{ + + public enum CasingOptions { None, Uppercase, Lowercase }; + + /// + /// The supported options to use when formatting text + /// + public class FormatOptions : INotifyPropertyChanged + { + + private int spacesPerIndent; + private bool useTabs = false; + private bool encloseIdentifiersInSquareBrackets; + private bool placeCommasBeforeNextStatement; + private bool placeEachReferenceOnNewLineInQueryStatements; + private CasingOptions keywordCasing; + private CasingOptions datatypeCasing; + private bool alignColumnDefinitionsInColumns; + + internal FormatOptions() + { + SpacesPerIndent = 4; + UseTabs = false; + PlaceCommasBeforeNextStatement = false; + EncloseIdentifiersInSquareBrackets = false; + PlaceEachReferenceOnNewLineInQueryStatements = false; + } + + public int SpacesPerIndent + { + get { return spacesPerIndent; } + set { spacesPerIndent = value; + RaisePropertyChanged("SpacesPerIndent"); } + } + + public bool UseTabs + { + get { return useTabs; } + set + { + useTabs = value; + // raise UseTabs & UseSpaces property changed events + RaisePropertyChanged("UseTabs"); + RaisePropertyChanged("UseSpaces"); + } + } + + public bool UseSpaces + { + get { return !UseTabs; } + set { UseTabs = !value; } + } + + public bool EncloseIdentifiersInSquareBrackets + { + get { return encloseIdentifiersInSquareBrackets; } + set + { + encloseIdentifiersInSquareBrackets = value; + RaisePropertyChanged("EncloseIdentifiersInSquareBrackets"); + } + } + + public bool PlaceCommasBeforeNextStatement + { + get { return placeCommasBeforeNextStatement; } + set + { + placeCommasBeforeNextStatement = value; + RaisePropertyChanged("PlaceCommasBeforeNextStatement"); + } + } + + public bool PlaceEachReferenceOnNewLineInQueryStatements + { + get { return placeEachReferenceOnNewLineInQueryStatements; } + set + { + placeEachReferenceOnNewLineInQueryStatements = value; + RaisePropertyChanged("PlaceEachReferenceOnNewLineInQueryStatements"); + } + } + + public CasingOptions KeywordCasing + { + get { return keywordCasing; } + set + { + keywordCasing = value; + RaisePropertyChanged("KeywordCasing"); + } + } + + public bool UppercaseKeywords + { + get { return KeywordCasing == CasingOptions.Uppercase; } + } + public bool LowercaseKeywords + { + get { return KeywordCasing == CasingOptions.Lowercase; } + } + + public bool DoNotFormatKeywords + { + get { return KeywordCasing == CasingOptions.None; } + } + + public CasingOptions DatatypeCasing + { + get { return datatypeCasing; } + set + { + datatypeCasing = value; + RaisePropertyChanged("DatatypeCasing"); + } + } + + public bool UppercaseDataTypes + { + get { return DatatypeCasing == CasingOptions.Uppercase; } + } + public bool LowercaseDataTypes + { + get { return DatatypeCasing == CasingOptions.Lowercase; } + } + public bool DoNotFormatDataTypes + { + get { return DatatypeCasing == CasingOptions.None; } + } + + public bool AlignColumnDefinitionsInColumns + { + get { return alignColumnDefinitionsInColumns; } + set + { + alignColumnDefinitionsInColumns = value; + RaisePropertyChanged("AlignColumnDefinitionsInColumns"); + } + } + + private void RaisePropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + public event PropertyChangedEventHandler PropertyChanged; + + public static void Copy(FormatOptions target, FormatOptions source) + { + target.AlignColumnDefinitionsInColumns = source.AlignColumnDefinitionsInColumns; + target.DatatypeCasing = source.DatatypeCasing; + target.EncloseIdentifiersInSquareBrackets = source.EncloseIdentifiersInSquareBrackets; + target.KeywordCasing = source.KeywordCasing; + target.PlaceCommasBeforeNextStatement = source.PlaceCommasBeforeNextStatement; + target.PlaceEachReferenceOnNewLineInQueryStatements = source.PlaceEachReferenceOnNewLineInQueryStatements; + target.SpacesPerIndent = source.SpacesPerIndent; + target.UseSpaces = source.UseSpaces; + target.UseTabs = source.UseTabs; + } + } + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Formatter/TSqlFormatterService.cs b/src/Microsoft.Kusto.ServiceLayer/Formatter/TSqlFormatterService.cs new file mode 100644 index 0000000000..faeee98d6e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Formatter/TSqlFormatterService.cs @@ -0,0 +1,320 @@ +// +// 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.Composition; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +//using Kusto.Language; +//using Kusto.Language.Editor; +using Microsoft.SqlTools.Extensibility; +using Microsoft.SqlTools.Hosting; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Formatter.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Workspace; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.SqlTools.Utility; +using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range; + +namespace Microsoft.Kusto.ServiceLayer.Formatter +{ + + [Export(typeof(IHostedService))] + public class TSqlFormatterService : HostedService, IComposableService + { + private FormatterSettings settings; + /// + /// The default constructor is required for MEF-based composable services + /// + public TSqlFormatterService() + { + settings = new FormatterSettings(); + } + + + + public override void InitializeService(IProtocolEndpoint serviceHost) + { + Logger.Write(TraceEventType.Verbose, "TSqlFormatter initialized"); + serviceHost.SetRequestHandler(DocumentFormattingRequest.Type, HandleDocFormatRequest); + serviceHost.SetRequestHandler(DocumentRangeFormattingRequest.Type, HandleDocRangeFormatRequest); + WorkspaceService?.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification); + } + + /// + /// Gets the workspace service. Note: should handle case where this is null in cases where unit tests do not set this up + /// + private WorkspaceService WorkspaceService + { + get { return ServiceProvider.GetService>(); } + } + + /// + /// Gets the language service. Note: should handle case where this is null in cases where unit tests do not set this up + /// + private LanguageService LanguageService + { + get { return ServiceProvider.GetService(); } + } + + /// + /// Ensure formatter settings are always up to date + /// + public Task HandleDidChangeConfigurationNotification( + SqlToolsSettings newSettings, + SqlToolsSettings oldSettings, + EventContext eventContext) + { + // update the current settings to reflect any changes (assuming formatter settings exist) + settings = newSettings?.SqlTools?.Format ?? settings; + return Task.FromResult(true); + } + + public async Task HandleDocFormatRequest(DocumentFormattingParams docFormatParams, RequestContext requestContext) + { + Func> requestHandler = () => + { + return FormatAndReturnEdits(docFormatParams); + }; + await HandleRequest(requestHandler, requestContext, "HandleDocFormatRequest"); + + DocumentStatusHelper.SendTelemetryEvent(requestContext, CreateTelemetryProps(isDocFormat: true)); + } + + public async Task HandleDocRangeFormatRequest(DocumentRangeFormattingParams docRangeFormatParams, RequestContext requestContext) + { + Func> requestHandler = () => + { + return FormatRangeAndReturnEdits(docRangeFormatParams); + }; + await HandleRequest(requestHandler, requestContext, "HandleDocRangeFormatRequest"); + + DocumentStatusHelper.SendTelemetryEvent(requestContext, CreateTelemetryProps(isDocFormat: false)); + } + private static TelemetryProperties CreateTelemetryProps(bool isDocFormat) + { + return new TelemetryProperties + { + Properties = new Dictionary + { + { TelemetryPropertyNames.FormatType, + isDocFormat ? TelemetryPropertyNames.DocumentFormatType : TelemetryPropertyNames.RangeFormatType } + }, + EventName = TelemetryEventNames.FormatCode + }; + } + + private async Task FormatRangeAndReturnEdits(DocumentRangeFormattingParams docFormatParams) + { + return await Task.Factory.StartNew(() => + { + if (ShouldSkipFormatting(docFormatParams)) + { + return Array.Empty(); + } + + var range = docFormatParams.Range; + ScriptFile scriptFile = GetFile(docFormatParams); + if (scriptFile == null) + { + return new TextEdit[0]; + } + TextEdit textEdit = new TextEdit { Range = range }; + string text = scriptFile.GetTextInRange(range.ToBufferRange()); + return DoFormat(docFormatParams, textEdit, text); + }); + } + + private bool ShouldSkipFormatting(DocumentFormattingParams docFormatParams) + { + if (docFormatParams == null + || docFormatParams.TextDocument == null + || docFormatParams.TextDocument.Uri == null) + { + return true; + } + return (LanguageService != null && LanguageService.ShouldSkipNonMssqlFile(docFormatParams.TextDocument.Uri)); + } + + private async Task FormatAndReturnEdits(DocumentFormattingParams docFormatParams) + { + return await Task.Factory.StartNew(() => + { + if (ShouldSkipFormatting(docFormatParams)) + { + return Array.Empty(); + } + + var scriptFile = GetFile(docFormatParams); + if (scriptFile == null + || scriptFile.FileLines.Count == 0) + { + return new TextEdit[0]; + } + TextEdit textEdit = PrepareEdit(scriptFile); + string text = scriptFile.Contents; + return DoFormat(docFormatParams, textEdit, text); + }); + } + + private TextEdit[] DoFormat(DocumentFormattingParams docFormatParams, TextEdit edit, string text) + { + Validate.IsNotNull(nameof(docFormatParams), docFormatParams); + + FormatOptions options = GetOptions(docFormatParams); + List edits = new List(); + edit.NewText = Format(text, options, false); + // TODO do not add if no formatting needed? + edits.Add(edit); + return edits.ToArray(); + } + + private FormatOptions GetOptions(DocumentFormattingParams docFormatParams) + { + return MergeFormatOptions(docFormatParams.Options, settings); + } + + internal static FormatOptions MergeFormatOptions(FormattingOptions formatRequestOptions, FormatterSettings settings) + + { + FormatOptions options = new FormatOptions(); + if (formatRequestOptions != null) + { + options.UseSpaces = formatRequestOptions.InsertSpaces; + options.SpacesPerIndent = formatRequestOptions.TabSize; + } + UpdateFormatOptionsFromSettings(options, settings); + return options; + } + + internal static void UpdateFormatOptionsFromSettings(FormatOptions options, FormatterSettings settings) + { + Validate.IsNotNull(nameof(options), options); + if (settings != null) + { + if (settings.AlignColumnDefinitionsInColumns.HasValue) { options.AlignColumnDefinitionsInColumns = settings.AlignColumnDefinitionsInColumns.Value; } + + if (settings.PlaceCommasBeforeNextStatement.HasValue) { options.PlaceCommasBeforeNextStatement = settings.PlaceCommasBeforeNextStatement.Value; } + + if (settings.PlaceSelectStatementReferencesOnNewLine.HasValue) { options.PlaceEachReferenceOnNewLineInQueryStatements = settings.PlaceSelectStatementReferencesOnNewLine.Value; } + + if (settings.UseBracketForIdentifiers.HasValue) { options.EncloseIdentifiersInSquareBrackets = settings.UseBracketForIdentifiers.Value; } + + options.DatatypeCasing = settings.DatatypeCasing; + options.KeywordCasing = settings.KeywordCasing; + } + } + + private ScriptFile GetFile(DocumentFormattingParams docFormatParams) + { + return WorkspaceService.Workspace.GetFile(docFormatParams.TextDocument.Uri); + } + + private static TextEdit PrepareEdit(ScriptFile scriptFile) + { + int fileLines = scriptFile.FileLines.Count; + Position start = new Position { Line = 0, Character = 0 }; + int lastChar = scriptFile.FileLines[scriptFile.FileLines.Count - 1].Length; + Position end = new Position { Line = scriptFile.FileLines.Count - 1, Character = lastChar }; + + TextEdit edit = new TextEdit + { + Range = new Range { Start = start, End = end } + }; + return edit; + } + + private async Task HandleRequest(Func> handler, RequestContext requestContext, string requestType) + { + Logger.Write(TraceEventType.Verbose, requestType); + + try + { + T result = await handler(); + await requestContext.SendResult(result); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + + + public string Format(TextReader input) + { + string originalSql = input.ReadToEnd(); + return Format(originalSql, new FormatOptions()); + } + + public string Format(string input, FormatOptions options) + { + return Format(input, options, true); + } + + public string Format(string input, FormatOptions options, bool verifyOutput) + { + string result = null; + //TODOKusto: Implement formatting for Kusto generically here. + //var kustoCodeService = new KustoCodeService(input, GlobalState.Default); + //var formattedText = kustoCodeService.GetFormattedText(); + //DoFormat(input, options, verifyOutput, visitor => + //{ + //result = formattedText.Text; + //}); + + return result; + } + + /*public void Format(string input, FormatOptions options, bool verifyOutput, Replacement.OnReplace replace) + { + DoFormat(input, options, verifyOutput, visitor => + { + foreach (Replacement r in visitor.Context.Replacements) + { + r.Apply(replace); + } + }); + } + + private void DoFormat(string input, FormatOptions options, bool verifyOutput, Action postFormatAction) + { + Validate.IsNotNull(nameof(input), input); + Validate.IsNotNull(nameof(options), options); + + ParseResult result = Parser.Parse(input); + FormatContext context = new FormatContext(result.Script, options); + + FormatterVisitor visitor = new FormatterVisitor(context, ServiceProvider); + result.Script.Accept(visitor); + if (verifyOutput) + { + visitor.VerifyFormat(); + } + + postFormatAction?.Invoke(visitor); + }*/ + } + + internal static class RangeExtensions + { + public static BufferRange ToBufferRange(this Range range) + { + // It turns out that VSCode sends Range objects as 0-indexed lines, while + // our BufferPosition and BufferRange logic assumes 1-indexed. Therefore + // need to increment all ranges by 1 when copying internally and reduce + // when returning to the caller + return new BufferRange( + new BufferPosition(range.Start.Line + 1, range.Start.Character + 1), + new BufferPosition(range.End.Line + 1, range.End.Character + 1) + ); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs new file mode 100644 index 0000000000..c0c0e18790 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/HostLoader.cs @@ -0,0 +1,136 @@ +// +// 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.Threading.Tasks; +using Microsoft.SqlTools.Credentials; +using Microsoft.SqlTools.Extensibility; +using Microsoft.SqlTools.Hosting; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Admin; +using Microsoft.Kusto.ServiceLayer.Metadata; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.QueryExecution; +using Microsoft.Kusto.ServiceLayer.Scripting; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Workspace; +using SqlToolsContext = Microsoft.SqlTools.ServiceLayer.SqlContext.SqlToolsContext; + +namespace Microsoft.Kusto.ServiceLayer +{ + /// + /// Provides support for starting up a service host. This is a common responsibility + /// for both the main service program and test driver that interacts with it + /// + public static class HostLoader + { + private static object lockObject = new object(); + private static bool isLoaded; + + private static readonly string[] inclusionList = + { + "microsofsqltoolscredentials.dll", + "microsoft.sqltools.hosting.dll", + "microsoftkustoservicelayer.dll" + }; + + internal static ServiceHost CreateAndStartServiceHost(SqlToolsContext sqlToolsContext) + { + ServiceHost serviceHost = ServiceHost.Instance; + lock (lockObject) + { + if (!isLoaded) + { + // Grab the instance of the service host + serviceHost.Initialize(); + + InitializeRequestHandlersAndServices(serviceHost, sqlToolsContext); + + // Start the service only after all request handlers are setup. This is vital + // as otherwise the Initialize event can be lost - it's processed and discarded before the handler + // is hooked up to receive the message + serviceHost.Start().Wait(); + isLoaded = true; + } + } + return serviceHost; + } + + private static void InitializeRequestHandlersAndServices(ServiceHost serviceHost, SqlToolsContext sqlToolsContext) + { + // Load extension provider, which currently finds all exports in current DLL. Can be changed to find based + // on directory or assembly list quite easily in the future + ExtensionServiceProvider serviceProvider = ExtensionServiceProvider.CreateDefaultServiceProvider(inclusionList); + serviceProvider.RegisterSingleService(sqlToolsContext); + serviceProvider.RegisterSingleService(serviceHost); + + // Initialize and register singleton services so they're accessible for any MEF service. In the future, these + // could be updated to be IComposableServices, which would avoid the requirement to define a singleton instance + // and instead have MEF handle discovery & loading + WorkspaceService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(WorkspaceService.Instance); + + LanguageService.Instance.InitializeService(serviceHost, sqlToolsContext); + serviceProvider.RegisterSingleService(LanguageService.Instance); + + ConnectionService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(ConnectionService.Instance); + + CredentialService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(CredentialService.Instance); + + QueryExecutionService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(QueryExecutionService.Instance); + + ScriptingService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(ScriptingService.Instance); + + AdminService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(AdminService.Instance); + + MetadataService.Instance.InitializeService(serviceHost); + serviceProvider.RegisterSingleService(MetadataService.Instance); + + InitializeHostedServices(serviceProvider, serviceHost); + serviceHost.ServiceProvider = serviceProvider; + + serviceHost.InitializeRequestHandlers(); + } + + /// + /// Internal to support testing. Initializes instances in the service, + /// and registers them for their preferred service type + /// + internal static void InitializeHostedServices(RegisteredServiceProvider provider, IProtocolEndpoint host) + { + // Pre-register all services before initializing. This ensures that if one service wishes to reference + // another one during initialization, it will be able to safely do so + foreach (IHostedService service in provider.GetServices()) + { + provider.RegisterSingleService(service.ServiceType, service); + } + + ServiceHost serviceHost = host as ServiceHost; + foreach (IHostedService service in provider.GetServices()) + { + // Initialize all hosted services, and register them in the service provider for their requested + // service type. This ensures that when searching for the ConnectionService you can get it without + // searching for an IHostedService of type ConnectionService + service.InitializeService(host); + + IDisposable disposable = service as IDisposable; + if (serviceHost != null && disposable != null) + { + serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) => + { + disposable.Dispose(); + await Task.FromResult(0); + }); + } + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/AutoCompleteHelper.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/AutoCompleteHelper.cs new file mode 100644 index 0000000000..509e3722f5 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/AutoCompleteHelper.cs @@ -0,0 +1,112 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// All the conversion of intellisense info to vscode format is done in this class. + /// + public static class AutoCompleteHelper + { + /// + /// Create a completion item from the default item text since VS Code expects CompletionItems + /// + /// + /// + /// + /// + /// + /// + /// + public static CompletionItem CreateCompletionItem( + string label, + string detail, + string insertText, + CompletionItemKind kind, + int row, + int startColumn, + int endColumn) + { + CompletionItem item = new CompletionItem + { + Label = label, + Kind = kind, + Detail = detail, + InsertText = insertText, + TextEdit = new TextEdit + { + NewText = insertText, + Range = new Range + { + Start = new Position + { + Line = row, + Character = startColumn + }, + End = new Position + { + Line = row, + Character = endColumn + } + } + } + }; + + return item; + } + + /// + /// Converts QuickInfo object into a VS Code Hover object + /// + /// + /// + /// + /// + /// + public static Hover ConvertQuickInfoToHover( + string quickInfoText, + string language, + int row, + int startColumn, + int endColumn) + { + // convert from the parser format to the VS Code wire format + var markedStrings = new MarkedString[1]; + if (quickInfoText != null) + { + markedStrings[0] = new MarkedString() + { + Language = language, + Value = quickInfoText + }; + + return new Hover() + { + Contents = markedStrings, + Range = new Range + { + Start = new Position + { + Line = row, + Character = startColumn + }, + End = new Position + { + Line = row, + Character = endColumn + } + } + }; + } + else + { + return null; + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs new file mode 100644 index 0000000000..cf5635edfd --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/BindingQueue.cs @@ -0,0 +1,502 @@ +// +// 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.Data.SqlClient; +using System.Diagnostics; +using System.Linq; +using System.Net.Sockets; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Main class for the Binding Queue + /// + public class BindingQueue : IDisposable where T : IBindingContext, new() + { + internal const int QueueThreadStackSize = 5 * 1024 * 1024; + + private CancellationTokenSource processQueueCancelToken = null; + + private ManualResetEvent itemQueuedEvent = new ManualResetEvent(initialState: false); + + private object bindingQueueLock = new object(); + + private LinkedList bindingQueue = new LinkedList(); + + private object bindingContextLock = new object(); + + private Task queueProcessorTask; + + public delegate void UnhandledExceptionDelegate(string connectionKey, Exception ex); + + public event UnhandledExceptionDelegate OnUnhandledException; + + /// + /// Map from context keys to binding context instances + /// Internal for testing purposes only + /// + internal Dictionary BindingContextMap { get; set; } + + internal Dictionary BindingContextTasks { get; set; } = new Dictionary(); + + /// + /// Constructor for a binding queue instance + /// + public BindingQueue() + { + this.BindingContextMap = new Dictionary(); + this.StartQueueProcessor(); + } + + public void StartQueueProcessor() + { + this.queueProcessorTask = StartQueueProcessorAsync(); + } + + /// + /// Stops the binding queue by sending cancellation request + /// + /// + public bool StopQueueProcessor(int timeout) + { + this.processQueueCancelToken.Cancel(); + return this.queueProcessorTask.Wait(timeout); + } + + /// + /// Returns true if cancellation is requested + /// + /// + public bool IsCancelRequested + { + get + { + return this.processQueueCancelToken.IsCancellationRequested; + } + } + + /// + /// Queue a binding request item + /// + public virtual QueueItem QueueBindingOperation( + string key, + Func bindOperation, + Func timeoutOperation = null, + Func errorHandler = null, + int? bindingTimeout = null, + int? waitForLockTimeout = null) + { + // don't add null operations to the binding queue + if (bindOperation == null) + { + return null; + } + + QueueItem queueItem = new QueueItem() + { + Key = key, + BindOperation = bindOperation, + TimeoutOperation = timeoutOperation, + ErrorHandler = errorHandler, + BindingTimeout = bindingTimeout, + WaitForLockTimeout = waitForLockTimeout + }; + + lock (this.bindingQueueLock) + { + this.bindingQueue.AddLast(queueItem); + } + + this.itemQueuedEvent.Set(); + + return queueItem; + } + + /// + /// Checks if a particular binding context is connected or not + /// + /// + public bool IsBindingContextConnected(string key) + { + lock (this.bindingContextLock) + { + IBindingContext context; + if (this.BindingContextMap.TryGetValue(key, out context)) + { + return context.IsConnected; + } + return false; + } + } + + /// + /// Gets or creates a binding context for the provided context key + /// + /// + protected IBindingContext GetOrCreateBindingContext(string key) + { + // use a default binding context for disconnected requests + if (string.IsNullOrWhiteSpace(key)) + { + key = "disconnected_binding_context"; + } + + lock (this.bindingContextLock) + { + if (!this.BindingContextMap.ContainsKey(key)) + { + var bindingContext = new T(); + this.BindingContextMap.Add(key, bindingContext); + this.BindingContextTasks.Add(bindingContext, Task.Run(() => null)); + } + + return this.BindingContextMap[key]; + } + } + + protected IEnumerable GetBindingContexts(string keyPrefix) + { + // use a default binding context for disconnected requests + if (string.IsNullOrWhiteSpace(keyPrefix)) + { + keyPrefix = "disconnected_binding_context"; + } + + lock (this.bindingContextLock) + { + return this.BindingContextMap.Where(x => x.Key.StartsWith(keyPrefix)).Select(v => v.Value); + } + } + + /// + /// Checks if a binding context already exists for the provided context key + /// + protected bool BindingContextExists(string key) + { + lock (this.bindingContextLock) + { + return this.BindingContextMap.ContainsKey(key); + } + } + + /// + /// Remove the binding queue entry + /// + protected void RemoveBindingContext(string key) + { + lock (this.bindingContextLock) + { + if (this.BindingContextMap.ContainsKey(key)) + { + // disconnect existing connection + var bindingContext = this.BindingContextMap[key]; + if (bindingContext.ServerConnection != null && bindingContext.ServerConnection.IsOpen) + { + // Disconnecting can take some time so run it in a separate task so that it doesn't block removal + Task.Run(() => + { + bindingContext.ServerConnection.Cancel(); + bindingContext.ServerConnection.Disconnect(); + }); + } + + // remove key from the map + this.BindingContextMap.Remove(key); + this.BindingContextTasks.Remove(bindingContext); + } + } + } + + public bool HasPendingQueueItems + { + get + { + lock (this.bindingQueueLock) + { + return this.bindingQueue.Count > 0; + } + } + } + + /// + /// Gets the next pending queue item + /// + private QueueItem GetNextQueueItem() + { + lock (this.bindingQueueLock) + { + if (this.bindingQueue.Count == 0) + { + return null; + } + + QueueItem queueItem = this.bindingQueue.First.Value; + this.bindingQueue.RemoveFirst(); + return queueItem; + } + } + + /// + /// Starts the queue processing thread + /// + private Task StartQueueProcessorAsync() + { + if (this.processQueueCancelToken != null) + { + this.processQueueCancelToken.Dispose(); + } + this.processQueueCancelToken = new CancellationTokenSource(); + + return Task.Factory.StartNew( + ProcessQueue, + this.processQueueCancelToken.Token, + TaskCreationOptions.LongRunning, + TaskScheduler.Default); + } + + /// + /// The core queue processing method + /// + /// + private void ProcessQueue() + { + CancellationToken token = this.processQueueCancelToken.Token; + WaitHandle[] waitHandles = new WaitHandle[2] + { + this.itemQueuedEvent, + token.WaitHandle + }; + + while (true) + { + // wait for with an item to be queued or the a cancellation request + WaitHandle.WaitAny(waitHandles); + if (token.IsCancellationRequested) + { + break; + } + + try + { + // dispatch all pending queue items + while (this.HasPendingQueueItems) + { + QueueItem queueItem = GetNextQueueItem(); + if (queueItem == null) + { + continue; + } + + IBindingContext bindingContext = GetOrCreateBindingContext(queueItem.Key); + if (bindingContext == null) + { + queueItem.ItemProcessed.Set(); + continue; + } + + var bindingContextTask = this.BindingContextTasks[bindingContext]; + + // Run in the binding context task in case this task has to wait for a previous binding operation + this.BindingContextTasks[bindingContext] = bindingContextTask.ContinueWith((task) => + { + bool lockTaken = false; + try + { + // prefer the queue item binding item, otherwise use the context default timeout + int bindTimeout = queueItem.BindingTimeout ?? bindingContext.BindingTimeout; + + // handle the case a previous binding operation is still running + if (!bindingContext.BindingLock.WaitOne(queueItem.WaitForLockTimeout ?? 0)) + { + try + { + Logger.Write(TraceEventType.Warning, "Binding queue operation timed out waiting for previous operation to finish"); + queueItem.Result = queueItem.TimeoutOperation != null + ? queueItem.TimeoutOperation(bindingContext) + : null; + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Exception running binding queue lock timeout handler: " + ex.ToString()); + } + finally + { + queueItem.ItemProcessed.Set(); + } + + return; + } + + bindingContext.BindingLock.Reset(); + + lockTaken = true; + + // execute the binding operation + object result = null; + CancellationTokenSource cancelToken = new CancellationTokenSource(); + + // run the operation in a separate thread + var bindTask = Task.Run(() => + { + try + { + result = queueItem.BindOperation( + bindingContext, + cancelToken.Token); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unexpected exception on the binding queue: " + ex.ToString()); + if (queueItem.ErrorHandler != null) + { + try + { + result = queueItem.ErrorHandler(ex); + } + catch (Exception ex2) + { + Logger.Write(TraceEventType.Error, "Unexpected exception in binding queue error handler: " + ex2.ToString()); + } + } + + if (IsExceptionOfType(ex, typeof(SqlException)) || IsExceptionOfType(ex, typeof(SocketException))) + { + if (this.OnUnhandledException != null) + { + this.OnUnhandledException(queueItem.Key, ex); + } + + RemoveBindingContext(queueItem.Key); + } + } + }); + + Task.Run(() => + { + try + { + // check if the binding tasks completed within the binding timeout + if (bindTask.Wait(bindTimeout)) + { + queueItem.Result = result; + } + else + { + cancelToken.Cancel(); + + // if the task didn't complete then call the timeout callback + if (queueItem.TimeoutOperation != null) + { + queueItem.Result = queueItem.TimeoutOperation(bindingContext); + } + + bindTask.ContinueWithOnFaulted(t => Logger.Write(TraceEventType.Error, "Binding queue threw exception " + t.Exception.ToString())); + + // Give the task a chance to complete before moving on to the next operation + bindTask.Wait(); + } + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Binding queue task completion threw exception " + ex.ToString()); + } + finally + { + // set item processed to avoid deadlocks + if (lockTaken) + { + bindingContext.BindingLock.Set(); + } + queueItem.ItemProcessed.Set(); + } + }); + } + catch (Exception ex) + { + // catch and log any exceptions raised in the binding calls + // set item processed to avoid deadlocks + Logger.Write(TraceEventType.Error, "Binding queue threw exception " + ex.ToString()); + // set item processed to avoid deadlocks + if (lockTaken) + { + bindingContext.BindingLock.Set(); + } + queueItem.ItemProcessed.Set(); + } + }, TaskContinuationOptions.None); + + // if a queue processing cancellation was requested then exit the loop + if (token.IsCancellationRequested) + { + break; + } + } + } + finally + { + lock (this.bindingQueueLock) + { + // verify the binding queue is still empty + if (this.bindingQueue.Count == 0) + { + // reset the item queued event since we've processed all the pending items + this.itemQueuedEvent.Reset(); + } + } + } + } + } + + /// + /// Clear queued items + /// + public void ClearQueuedItems() + { + lock (this.bindingQueueLock) + { + if (this.bindingQueue.Count > 0) + { + this.bindingQueue.Clear(); + } + } + } + + public void Dispose() + { + if (this.processQueueCancelToken != null) + { + this.processQueueCancelToken.Dispose(); + } + + if (itemQueuedEvent != null) + { + itemQueuedEvent.Dispose(); + } + + if (this.BindingContextMap != null) + { + foreach (var item in this.BindingContextMap) + { + if (item.Value != null && item.Value.ServerConnection != null && item.Value.ServerConnection.SqlConnectionObject != null) + { + item.Value.ServerConnection.SqlConnectionObject.Close(); + } + } + } + } + + private bool IsExceptionOfType(Exception ex, Type t) + { + return ex.GetType() == t || (ex.InnerException != null && ex.InnerException.GetType() == t); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingContext.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingContext.cs new file mode 100644 index 0000000000..bde3a3816a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingContext.cs @@ -0,0 +1,223 @@ +// +// 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.Threading; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.SmoMetadataProvider; +using Microsoft.SqlServer.Management.SqlParser.Binder; +using Microsoft.SqlServer.Management.SqlParser.Common; +using Microsoft.SqlServer.Management.SqlParser.MetadataProvider; +using Microsoft.SqlServer.Management.SqlParser.Parser; +using Kusto.Data.Net.Client; +using Kusto.Data.Common; +using Kusto.Data; +using Microsoft.Kusto.ServiceLayer.DataSource; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Class for the binding context for connected sessions + /// + public class ConnectedBindingContext : IBindingContext + { + private ParseOptions parseOptions; + + private ManualResetEvent bindingLock; + + private ServerConnection serverConnection; + + /// + public IDataSource DataSource { get; set; } + + /// + /// Connected binding context constructor + /// + public ConnectedBindingContext() + { + this.bindingLock = new ManualResetEvent(initialState: true); + this.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout; + this.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider(); + } + + /// + /// Gets or sets a flag indicating if the binder is connected + /// + public bool IsConnected { get; set; } + + /// + /// Gets or sets the binding server connection + /// + public ServerConnection ServerConnection + { + get + { + return this.serverConnection; + } + set + { + this.serverConnection = value; + + // reset the parse options so the get recreated for the current connection + this.parseOptions = null; + } + } + + /// + /// Gets or sets the metadata display info provider + /// + public MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; } + + /// + /// Gets or sets the SMO metadata provider + /// + public SmoMetadataProvider SmoMetadataProvider { get; set; } + + /// + /// Gets or sets the binder + /// + public IBinder Binder { get; set; } + + /// + /// Gets the binding lock object + /// + public ManualResetEvent BindingLock + { + get + { + return this.bindingLock; + } + } + + /// + /// Gets or sets the binding operation timeout in milliseconds + /// + public int BindingTimeout { get; set; } + + /// + /// Gets the Language Service ServerVersion + /// + public ServerVersion ServerVersion + { + get + { + return this.ServerConnection != null + ? this.ServerConnection.ServerVersion + : null; + } + } + + /// + /// Gets the current DataEngineType + /// + public DatabaseEngineType DatabaseEngineType + { + get + { + return this.ServerConnection != null + ? this.ServerConnection.DatabaseEngineType + : DatabaseEngineType.Standalone; + } + } + + /// + /// Gets the current connections TransactSqlVersion + /// + public TransactSqlVersion TransactSqlVersion + { + get + { + return this.IsConnected + ? GetTransactSqlVersion(this.ServerVersion) + : TransactSqlVersion.Current; + } + } + + /// + /// Gets the current DatabaseCompatibilityLevel + /// + public DatabaseCompatibilityLevel DatabaseCompatibilityLevel + { + get + { + return this.IsConnected + ? GetDatabaseCompatibilityLevel(this.ServerVersion) + : DatabaseCompatibilityLevel.Current; + } + } + + /// + /// Gets the current ParseOptions + /// + public ParseOptions ParseOptions + { + get + { + if (this.parseOptions == null) + { + this.parseOptions = new ParseOptions( + batchSeparator: LanguageService.DefaultBatchSeperator, + isQuotedIdentifierSet: true, + compatibilityLevel: DatabaseCompatibilityLevel, + transactSqlVersion: TransactSqlVersion); + } + return this.parseOptions; + } + } + + + /// + /// Gets the database compatibility level from a server version + /// + /// + private static DatabaseCompatibilityLevel GetDatabaseCompatibilityLevel(ServerVersion serverVersion) + { + int versionMajor = Math.Max(serverVersion.Major, 8); + + switch (versionMajor) + { + case 8: + return DatabaseCompatibilityLevel.Version80; + case 9: + return DatabaseCompatibilityLevel.Version90; + case 10: + return DatabaseCompatibilityLevel.Version100; + case 11: + return DatabaseCompatibilityLevel.Version110; + case 12: + return DatabaseCompatibilityLevel.Version120; + case 13: + return DatabaseCompatibilityLevel.Version130; + default: + return DatabaseCompatibilityLevel.Current; + } + } + + /// + /// Gets the transaction sql version from a server version + /// + /// + private static TransactSqlVersion GetTransactSqlVersion(ServerVersion serverVersion) + { + int versionMajor = Math.Max(serverVersion.Major, 9); + + switch (versionMajor) + { + case 9: + case 10: + // In case of 10.0 we still use Version 10.5 as it is the closest available. + return TransactSqlVersion.Version105; + case 11: + return TransactSqlVersion.Version110; + case 12: + return TransactSqlVersion.Version120; + case 13: + return TransactSqlVersion.Version130; + default: + return TransactSqlVersion.Current; + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs new file mode 100644 index 0000000000..49391ea801 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ConnectedBindingQueue.cs @@ -0,0 +1,234 @@ +// +// 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.Data.SqlClient; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.SmoMetadataProvider; +using Microsoft.SqlServer.Management.SqlParser.Binder; +using Microsoft.SqlServer.Management.SqlParser.MetadataProvider; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Workspace; +using Microsoft.Kusto.ServiceLayer.DataSource; +using System.Threading; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + public interface IConnectedBindingQueue + { + void CloseConnections(string serverName, string databaseName, int millisecondsTimeout); + void OpenConnections(string serverName, string databaseName, int millisecondsTimeout); + string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false); + void Dispose(); + QueueItem QueueBindingOperation( + string key, + Func bindOperation, + Func timeoutOperation = null, + Func errorHandler = null, + int? bindingTimeout = null, + int? waitForLockTimeout = null); + } + + public class SqlConnectionOpener + { + /// + /// Virtual method used to support mocking and testing + /// + public virtual ServerConnection OpenServerConnection(ConnectionInfo connInfo, string featureName) + { + return ConnectionService.OpenServerConnection(connInfo, featureName); + } + } + + /// + /// ConnectedBindingQueue class for processing online binding requests + /// + public class ConnectedBindingQueue : BindingQueue, IConnectedBindingQueue + { + internal const int DefaultBindingTimeout = 500; + + internal const int DefaultMinimumConnectionTimeout = 30; + + /// + /// flag determing if the connection queue requires online metadata objects + /// it's much cheaper to not construct these objects if not needed + /// + private bool needsMetadata; + private SqlConnectionOpener connectionOpener; + + /// + /// Gets the current settings + /// + internal SqlToolsSettings CurrentSettings + { + get { return WorkspaceService.Instance.CurrentSettings; } + } + + public ConnectedBindingQueue() + : this(true) + { + } + + public ConnectedBindingQueue(bool needsMetadata) + { + this.needsMetadata = needsMetadata; + this.connectionOpener = new SqlConnectionOpener(); + } + + // For testing purposes only + internal void SetConnectionOpener(SqlConnectionOpener opener) + { + this.connectionOpener = opener; + } + + /// + /// Generate a unique key based on the ConnectionInfo object + /// + /// + internal static string GetConnectionContextKey(ConnectionDetails details) + { + string key = string.Format("{0}_{1}_{2}_{3}", + details.ServerName ?? "NULL", + details.DatabaseName ?? "NULL", + details.UserName ?? "NULL", + details.AuthenticationType ?? "NULL" + ); + + if (!string.IsNullOrEmpty(details.DatabaseDisplayName)) + { + key += "_" + details.DatabaseDisplayName; + } + + if (!string.IsNullOrEmpty(details.GroupId)) + { + key += "_" + details.GroupId; + } + + return Uri.EscapeUriString(key); + } + + /// + /// Generate a unique key based on the ConnectionInfo object + /// + /// + private string GetConnectionContextKey(string serverName, string databaseName) + { + return string.Format("{0}_{1}", + serverName ?? "NULL", + databaseName ?? "NULL"); + + } + + public void CloseConnections(string serverName, string databaseName, int millisecondsTimeout) + { + string connectionKey = GetConnectionContextKey(serverName, databaseName); + var contexts = GetBindingContexts(connectionKey); + foreach (var bindingContext in contexts) + { + if (bindingContext.BindingLock.WaitOne(millisecondsTimeout)) + { + bindingContext.ServerConnection.Disconnect(); + } + } + } + + public void OpenConnections(string serverName, string databaseName, int millisecondsTimeout) + { + string connectionKey = GetConnectionContextKey(serverName, databaseName); + var contexts = GetBindingContexts(connectionKey); + foreach (var bindingContext in contexts) + { + if (bindingContext.BindingLock.WaitOne(millisecondsTimeout)) + { + try + { + bindingContext.ServerConnection.Connect(); + } + catch + { + //TODO: remove the binding context? + } + } + } + } + + public void RemoveBindigContext(ConnectionInfo connInfo) + { + string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails); + if (BindingContextExists(connectionKey)) + { + RemoveBindingContext(connectionKey); + } + } + + /// + /// Use a ConnectionInfo item to create a connected binding context + /// + /// Connection info used to create binding context + /// Overwrite existing context + public virtual string AddConnectionContext(ConnectionInfo connInfo, string featureName = null, bool overwrite = false) + { + if (connInfo == null) + { + return string.Empty; + } + + // lookup the current binding contextna + string connectionKey = GetConnectionContextKey(connInfo.ConnectionDetails); + if (BindingContextExists(connectionKey)) + { + if (overwrite) + { + RemoveBindingContext(connectionKey); + } + else + { + // no need to populate the context again since the context already exists + return connectionKey; + } + } + IBindingContext bindingContext = this.GetOrCreateBindingContext(connectionKey); + + if (bindingContext.BindingLock.WaitOne()) + { + try + { + bindingContext.BindingLock.Reset(); + + // populate the binding context to work with the SMO metadata provider + bindingContext.ServerConnection = connectionOpener.OpenServerConnection(connInfo, featureName); + + string connectionString = ConnectionService.BuildConnectionString(connInfo.ConnectionDetails); + bindingContext.DataSource = DataSourceFactory.Create(DataSourceType.Kusto, connectionString, connInfo.ConnectionDetails.AzureAccountToken); + + if (this.needsMetadata) + { + bindingContext.SmoMetadataProvider = SmoMetadataProvider.CreateConnectedProvider(bindingContext.ServerConnection); + bindingContext.MetadataDisplayInfoProvider = new MetadataDisplayInfoProvider(); + bindingContext.MetadataDisplayInfoProvider.BuiltInCasing = + this.CurrentSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value + ? CasingStyle.Lowercase : CasingStyle.Uppercase; + bindingContext.Binder = BinderProvider.CreateBinder(bindingContext.SmoMetadataProvider); + } + + bindingContext.BindingTimeout = ConnectedBindingQueue.DefaultBindingTimeout; + bindingContext.IsConnected = true; + } + catch (Exception) + { + bindingContext.IsConnected = false; + } + finally + { + bindingContext.BindingLock.Set(); + } + } + + return connectionKey; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Completion.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Completion.cs new file mode 100644 index 0000000000..b9da23ebc8 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Completion.cs @@ -0,0 +1,111 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Diagnostics; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class CompletionRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/completion"); + } + + public class CompletionResolveRequest + { + public static readonly + RequestType Type = + RequestType.Create("completionItem/resolve"); + } + + public enum CompletionItemKind + { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18 + } + + public class Command + { + /// + /// Title of the command. + /// + public string Title { get; set; } + + /// + /// The identifier of the actual command handler, like `vsintellicode.completionItemSelected`. + /// + public string command { get; set; } + + /// + /// A tooltip for the command, when represented in the UI. + /// + public string Tooltip { get; set; } + + /// + /// Arguments that the command handler should be invoked with. + /// + public object[] Arguments { get; set; } + } + + [DebuggerDisplay("Kind = {Kind.ToString()}, Label = {Label}, Detail = {Detail}")] + public class CompletionItem + { + public string Label { get; set; } + + public CompletionItemKind? Kind { get; set; } + + public string Detail { get; set; } + + /// + /// Gets or sets the documentation string for the completion item. + /// + public string Documentation { get; set; } + + public string SortText { get; set; } + + public string FilterText { get; set; } + + public string InsertText { get; set; } + + public TextEdit TextEdit { get; set; } + + /// + /// Gets or sets a custom data field that allows the server to mark + /// each completion item with an identifier that will help correlate + /// the item to the previous completion request during a completion + /// resolve request. + /// + public object Data { get; set; } + + /// + /// Exposing a command field for a completion item for passing telemetry + /// + public Command Command { get; set; } + + /// + /// Whether this completion item is preselected or not + /// + public bool? Preselect { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Definition.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Definition.cs new file mode 100644 index 0000000000..c9772c47d3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Definition.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class DefinitionRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/definition"); + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Diagnostics.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Diagnostics.cs new file mode 100644 index 0000000000..cd2d9085a1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Diagnostics.cs @@ -0,0 +1,72 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class PublishDiagnosticsNotification + { + public static readonly + EventType Type = + EventType.Create("textDocument/publishDiagnostics"); + + /// + /// Gets or sets the URI for which diagnostic information is reported. + /// + public string Uri { get; set; } + + /// + /// Gets or sets the array of diagnostic information items. + /// + public Diagnostic[] Diagnostics { get; set; } + } + + public enum DiagnosticSeverity + { + /// + /// Indicates that the diagnostic represents an error. + /// + Error = 1, + + /// + /// Indicates that the diagnostic represents a warning. + /// + Warning = 2, + + /// + /// Indicates that the diagnostic represents an informational message. + /// + Information = 3, + + /// + /// Indicates that the diagnostic represents a hint. + /// + Hint = 4 + } + + public class Diagnostic + { + public Range Range { get; set; } + + /// + /// Gets or sets the severity of the diagnostic. If omitted, the + /// client should interpret the severity. + /// + public DiagnosticSeverity? Severity { get; set; } + + /// + /// Gets or sets the diagnostic's code (optional). + /// + public string Code { get; set; } + + /// + /// Gets or sets the diagnostic message. + /// + public string Message { get; set; } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/DocumentHighlight.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/DocumentHighlight.cs new file mode 100644 index 0000000000..59bac57004 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/DocumentHighlight.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public enum DocumentHighlightKind + { + Text = 1, + Read = 2, + Write = 3 + } + + public class DocumentHighlight + { + public Range Range { get; set; } + + public DocumentHighlightKind Kind { get; set; } + } + + public class DocumentHighlightRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/documentHighlight"); + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ExpandAliasRequest.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ExpandAliasRequest.cs new file mode 100644 index 0000000000..58beb96482 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ExpandAliasRequest.cs @@ -0,0 +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 Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class ExpandAliasRequest + { + public static readonly + RequestType Type = + RequestType.Create("SqlTools/expandAlias"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/FindModuleRequest.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/FindModuleRequest.cs new file mode 100644 index 0000000000..ad88def39c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/FindModuleRequest.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class FindModuleRequest + { + public static readonly + RequestType, object> Type = + RequestType, object>.Create("SqlTools/findModule"); + } + + + public class PSModuleMessage + { + public string Name { get; set; } + public string Description { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Hover.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Hover.cs new file mode 100644 index 0000000000..5dca753d32 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/Hover.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class MarkedString + { + public string Language { get; set; } + + public string Value { get; set; } + } + + public class Hover + { + public MarkedString[] Contents { get; set; } + + public Range? Range { get; set; } + } + + public class HoverRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/hover"); + + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/InstallModuleRequest.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/InstallModuleRequest.cs new file mode 100644 index 0000000000..f026e16048 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/InstallModuleRequest.cs @@ -0,0 +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 Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + class InstallModuleRequest + { + public static readonly + RequestType Type = + RequestType.Create("SqlTools/installModule"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/IntelliSenseReady.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/IntelliSenseReady.cs new file mode 100644 index 0000000000..1f3e09ca69 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/IntelliSenseReady.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + /// + /// Parameters sent back with an IntelliSense ready event + /// + public class IntelliSenseReadyParams + { + /// + /// URI identifying the text document + /// + public string OwnerUri { get; set; } + } + + /// + /// Event sent when the language service is finished updating after a connection + /// + public class IntelliSenseReadyNotification + { + public static readonly + EventType Type = + EventType.Create("textDocument/intelliSenseReady"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/RebuildIntelliSenseNotification.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/RebuildIntelliSenseNotification.cs new file mode 100644 index 0000000000..6c8fd34a51 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/RebuildIntelliSenseNotification.cs @@ -0,0 +1,30 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + /// + /// Parameters to be sent back with a rebuild IntelliSense event + /// + public class RebuildIntelliSenseParams + { + /// + /// URI identifying the file that should have its IntelliSense cache rebuilt + /// + public string OwnerUri { get; set; } + } + + /// + /// RebuildIntelliSenseNotification notification mapping entry + /// + public class RebuildIntelliSenseNotification + { + public static readonly + EventType Type = + EventType.Create("textDocument/rebuildIntelliSense"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/References.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/References.cs new file mode 100644 index 0000000000..fb84a9856a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/References.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class ReferencesRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/references"); + } + + public class ReferencesParams : TextDocumentPosition + { + public ReferencesContext Context { get; set; } + } + + public class ReferencesContext + { + public bool IncludeDeclaration { get; set; } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ShowOnlineHelpRequest.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ShowOnlineHelpRequest.cs new file mode 100644 index 0000000000..15298577ef --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/ShowOnlineHelpRequest.cs @@ -0,0 +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 Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class ShowOnlineHelpRequest + { + public static readonly + RequestType Type = + RequestType.Create("SqlTools/showOnlineHelp"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SignatureHelp.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SignatureHelp.cs new file mode 100644 index 0000000000..29b64dc022 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SignatureHelp.cs @@ -0,0 +1,43 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class SignatureHelpRequest + { + public static readonly + RequestType Type = + RequestType.Create("textDocument/signatureHelp"); + } + + public class ParameterInformation + { + public string Label { get; set; } + + public string Documentation { get; set; } + } + + public class SignatureInformation + { + public string Label { get; set; } + + public string Documentation { get; set; } + + public ParameterInformation[] Parameters { get; set; } + } + + public class SignatureHelp + { + public SignatureInformation[] Signatures { get; set; } + + public int? ActiveSignature { get; set; } + + public int? ActiveParameter { get; set; } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/StatusChangedNotification.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/StatusChangedNotification.cs new file mode 100644 index 0000000000..9c8b967d4d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/StatusChangedNotification.cs @@ -0,0 +1,35 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + /// + /// Parameters sent back with an status change event + /// + public class StatusChangeParams + { + /// + /// URI identifying the text document + /// + public string OwnerUri { get; set; } + + /// + /// The new status for the document + /// + public string Status { get; set; } + } + + /// + /// Event sent for language service status change notification + /// + public class StatusChangedNotification + { + public static readonly + EventType Type = + EventType.Create("textDocument/statusChanged"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SyntaxParse.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SyntaxParse.cs new file mode 100644 index 0000000000..3d52fdac18 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/SyntaxParse.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class SyntaxParseParams + { + public string OwnerUri { get; set; } + public string Query { get; set; } + } + + public class SyntaxParseResult + { + public bool Parseable { get; set; } + + public string[] Errors { get; set; } + } + + public class SyntaxParseRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/syntaxparse"); + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TelemetryNotification.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TelemetryNotification.cs new file mode 100644 index 0000000000..a14250be65 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TelemetryNotification.cs @@ -0,0 +1,100 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + public class TelemetryProperties + { + public string EventName { get; set; } + + /// + /// Telemetry properties + /// + public Dictionary Properties { get; set; } + + /// + /// Telemetry measures + /// + public Dictionary Measures { get; set; } + } + + /// + /// Parameters sent back with an IntelliSense ready event + /// + public class TelemetryParams + { + public TelemetryProperties Params { get; set; } + } + + /// + /// Event sent when the language service needs to add a telemetry event + /// + public class TelemetryNotification + { + public static readonly + EventType Type = + EventType.Create("telemetry/sqlevent"); + } + + /// + /// List of telemetry events + /// + public static class TelemetryEventNames + { + /// + /// telemetry event name for auto complete response time + /// + public const string IntellisenseQuantile = "IntellisenseQuantile"; + + /// + /// telemetry event name for when definition is requested + /// + public const string PeekDefinitionRequested = "PeekDefinitionRequested"; + + /// + /// telemetry event name for when definition is requested + /// + public const string FormatCode = "FormatCode"; + } + + /// + /// List of properties used in telemetry events + /// + public static class TelemetryPropertyNames + { + /// + /// Is a connection to an Azure database or not + /// + public const string IsAzure = "IsAzure"; + + /// + /// Did an event succeed or not + /// + public const string Succeeded = "Succeeded"; + + /// + /// Was the action against a connected file or similar resource, or not + /// + public const string Connected = "Connected"; + + /// + /// Format type property - should be one of or + /// + public const string FormatType = "FormatType"; + + /// + /// A full document format + /// + public const string DocumentFormatType = "Document"; + + /// + /// A document range format + /// + public const string RangeFormatType = "Range"; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TextEdit.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TextEdit.cs new file mode 100644 index 0000000000..660dbb349e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/Contracts/TextEdit.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Diagnostics; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts +{ + + [DebuggerDisplay("NewText = {NewText}, Range = {Range.Start.Line}:{Range.Start.Character} - {Range.End.Line}:{Range.End.Character}")] + public class TextEdit + { + public Range Range { get; set; } + + public string NewText { get; set; } + } + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DiagnosticsHelper.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DiagnosticsHelper.cs new file mode 100644 index 0000000000..163c366ffa --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DiagnosticsHelper.cs @@ -0,0 +1,124 @@ +// +// 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.Linq; +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.SqlTools.Utility; +using Range = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Range; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Main class for Language Service functionality including anything that reqires knowledge of + /// the language to perfom, such as definitions, intellisense, etc. + /// + public static class DiagnosticsHelper + { + /// + /// Send the diagnostic results back to the host application + /// + /// + /// + /// + internal static async Task PublishScriptDiagnostics( + ScriptFile scriptFile, + ScriptFileMarker[] semanticMarkers, + EventContext eventContext) + { + var allMarkers = scriptFile.SyntaxMarkers != null + ? scriptFile.SyntaxMarkers.Concat(semanticMarkers) + : semanticMarkers; + + // Always send syntax and semantic errors. We want to + // make sure no out-of-date markers are being displayed. + await eventContext.SendEvent( + PublishDiagnosticsNotification.Type, + new PublishDiagnosticsNotification + { + Uri = scriptFile.ClientUri, + Diagnostics = + allMarkers + .Select(GetDiagnosticFromMarker) + .ToArray() + }); + } + + /// + /// Send the diagnostic results back to the host application + /// + /// + /// + /// + internal static async Task ClearScriptDiagnostics( + string uri, + EventContext eventContext) + { + Validate.IsNotNullOrEmptyString(nameof(uri), uri); + Validate.IsNotNull(nameof(eventContext), eventContext); + // Always send syntax and semantic errors. We want to + // make sure no out-of-date markers are being displayed. + await eventContext.SendEvent( + PublishDiagnosticsNotification.Type, + new PublishDiagnosticsNotification + { + Uri = uri, + Diagnostics = Array.Empty() + }); + } + + /// + /// Convert a ScriptFileMarker to a Diagnostic that is Language Service compatible + /// + /// + /// + internal static Diagnostic GetDiagnosticFromMarker(ScriptFileMarker scriptFileMarker) + { + return new Diagnostic + { + Severity = MapDiagnosticSeverity(scriptFileMarker.Level), + Message = scriptFileMarker.Message, + Range = new Range + { + Start = new Position + { + Line = scriptFileMarker.ScriptRegion.StartLineNumber - 1, + Character = scriptFileMarker.ScriptRegion.StartColumnNumber - 1 + }, + End = new Position + { + Line = scriptFileMarker.ScriptRegion.EndLineNumber - 1, + Character = scriptFileMarker.ScriptRegion.EndColumnNumber - 1 + } + } + }; + } + + /// + /// Map ScriptFileMarker severity to Diagnostic severity + /// + /// + internal static DiagnosticSeverity MapDiagnosticSeverity(ScriptFileMarkerLevel markerLevel) + { + switch (markerLevel) + { + case ScriptFileMarkerLevel.Error: + return DiagnosticSeverity.Error; + + case ScriptFileMarkerLevel.Warning: + return DiagnosticSeverity.Warning; + + case ScriptFileMarkerLevel.Information: + return DiagnosticSeverity.Information; + + default: + return DiagnosticSeverity.Error; + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DocumentStatusHelper.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DocumentStatusHelper.cs new file mode 100644 index 0000000000..c18c346247 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/DocumentStatusHelper.cs @@ -0,0 +1,77 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using Microsoft.SqlTools.Utility; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Helper class to send events to the client + /// + public class DocumentStatusHelper + { + public const string DefinitionRequested = "DefinitionRequested"; + public const string DefinitionRequestCompleted = "DefinitionRequestCompleted"; + + /// + /// Sends an event for specific document using the existing request context + /// + public static void SendStatusChange(RequestContext requestContext, TextDocumentPosition textDocumentPosition, string status) + { + Task.Factory.StartNew(async () => + { + if (requestContext != null) + { + string ownerUri = textDocumentPosition != null && textDocumentPosition.TextDocument != null ? textDocumentPosition.TextDocument.Uri : ""; + await requestContext.SendEvent(StatusChangedNotification.Type, new StatusChangeParams() + { + OwnerUri = ownerUri, + Status = status + }); + } + }); + } + + /// + /// Sends a telemetry event for specific document using the existing request context + /// + public static void SendTelemetryEvent(RequestContext requestContext, string telemetryEvent) + { + Validate.IsNotNull(nameof(requestContext), requestContext); + Validate.IsNotNullOrWhitespaceString(nameof(telemetryEvent), telemetryEvent); + Task.Factory.StartNew(async () => + { + await requestContext.SendEvent(TelemetryNotification.Type, new TelemetryParams() + { + Params = new TelemetryProperties + { + EventName = telemetryEvent + } + }); + }); + } + + /// + /// Sends a telemetry event for specific document using the existing request context + /// + public static void SendTelemetryEvent(RequestContext requestContext, TelemetryProperties telemetryProps) + { + Validate.IsNotNull(nameof(requestContext), requestContext); + Validate.IsNotNull(nameof(telemetryProps), telemetryProps); + Validate.IsNotNullOrWhitespaceString("telemetryProps.EventName", telemetryProps.EventName); + Task.Factory.StartNew(async () => + { + await requestContext.SendEvent(TelemetryNotification.Type, new TelemetryParams() + { + Params = telemetryProps + }); + }); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/IBindingContext.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/IBindingContext.cs new file mode 100644 index 0000000000..2163f816ba --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/IBindingContext.cs @@ -0,0 +1,88 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Threading; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlServer.Management.SmoMetadataProvider; +using Microsoft.SqlServer.Management.SqlParser.Binder; +using Microsoft.SqlServer.Management.SqlParser.Common; +using Microsoft.SqlServer.Management.SqlParser.MetadataProvider; +using Microsoft.SqlServer.Management.SqlParser.Parser; +using Microsoft.Kusto.ServiceLayer.DataSource; + + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// The context used for binding requests + /// + public interface IBindingContext + { + /// + /// Gets or sets a flag indicating if the context is connected + /// + bool IsConnected { get; set; } + + /// + /// Gets or sets the binding server connection + /// + ServerConnection ServerConnection { get; set; } + + /// + /// Gets or sets data source interface + /// + IDataSource DataSource { get; set; } + + /// + /// Gets or sets the metadata display info provider + /// + MetadataDisplayInfoProvider MetadataDisplayInfoProvider { get; set; } + + /// + /// Gets or sets the SMO metadata provider + /// + SmoMetadataProvider SmoMetadataProvider { get; set; } + + /// + /// Gets or sets the binder + /// + IBinder Binder { get; set; } + + /// + /// Gets the binding lock object + /// + ManualResetEvent BindingLock { get; } + + /// + /// Gets or sets the binding operation timeout in milliseconds + /// + int BindingTimeout { get; set; } + + /// + /// Gets or sets the current connection parse options + /// + ParseOptions ParseOptions { get; } + + /// + /// Gets or sets the current connection server version + /// + ServerVersion ServerVersion { get; } + + /// + /// Gets or sets the database engine type + /// + DatabaseEngineType DatabaseEngineType { get; } + + /// + /// Gets or sets the T-SQL version + /// + TransactSqlVersion TransactSqlVersion { get; } + + /// + /// Gets or sets the database compatibility level + /// + DatabaseCompatibilityLevel DatabaseCompatibilityLevel { get; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/InteractionMetrics.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/InteractionMetrics.cs new file mode 100644 index 0000000000..aa085a014a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/InteractionMetrics.cs @@ -0,0 +1,98 @@ +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer +{ + /// + /// A class to calculate the value for the metrics using the given bucket + /// + public class InteractionMetrics + { + /// + /// Creates new instance given a bucket of metrics + /// + public InteractionMetrics(int[] metrics) + { + Validate.IsNotNull("metrics", metrics); + if(metrics.Length == 0) + { + throw new ArgumentOutOfRangeException("metrics"); + } + + Counters = new ConcurrentDictionary(); + if (!IsSorted(metrics)) + { + Array.Sort(metrics); + } + Metrics = metrics; + } + + private ConcurrentDictionary Counters { get; } + + private object perfCountersLock = new object(); + + /// + /// The metrics bucket + /// + public int[] Metrics { get; private set; } + + /// + /// Returns true if the given list is sorted + /// + private bool IsSorted(int[] metrics) + { + if (metrics.Length > 1) + { + int previous = metrics[0]; + for (int i = 1; i < metrics.Length; i++) + { + if(metrics[i] < previous) + { + return false; + } + previous = metrics[i]; + } + } + return true; + } + + /// + /// Update metric value given new number + /// + public void UpdateMetrics(double duration, T newValue, Func updateValueFactory) + { + int metric = Metrics[Metrics.Length - 1]; + for (int i = 0; i < Metrics.Length; i++) + { + if (duration <= Metrics[i]) + { + metric = Metrics[i]; + break; + } + } + string key = metric.ToString(); + Counters.AddOrUpdate(key, newValue, updateValueFactory); + } + + /// + /// Returns the quantile + /// + public Dictionary Quantile + { + get + { + return Counters.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); + } + } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs new file mode 100644 index 0000000000..a2ed3e6e2e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/LanguageService.cs @@ -0,0 +1,1200 @@ +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlServer.Management.SqlParser.Common; +using Microsoft.SqlServer.Management.SqlParser.Parser; +using Microsoft.SqlServer.Management.SqlParser.SqlCodeDom; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Completion; +using Microsoft.Kusto.ServiceLayer.LanguageServices.Contracts; +using SqlToolsContext = Microsoft.SqlTools.ServiceLayer.SqlContext.SqlToolsContext; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.Workspace; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.SqlTools.Utility; +using Location = Microsoft.Kusto.ServiceLayer.Workspace.Contracts.Location; +using SqlToolsSettings = Microsoft.Kusto.ServiceLayer.SqlContext.SqlToolsSettings; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Main class for Language Service functionality including anything that requires knowledge of + /// the language to perform, such as definitions, intellisense, etc. + /// + public class LanguageService: IDisposable + { + #region Singleton Instance Implementation + + private static readonly Lazy instance = new Lazy(() => new LanguageService()); + + /// + /// Gets the singleton instance object + /// + public static LanguageService Instance + { + get { return instance.Value; } + } + + #endregion + + #region Instance fields and constructor + + private const int OneSecond = 1000; + + private const int PrepopulateBindTimeout = 60000; + + internal const string DefaultBatchSeperator = "GO"; + + internal const int DiagnosticParseDelay = 750; + + internal const int HoverTimeout = 500; + + internal const int BindingTimeout = 500; + + internal const int OnConnectionWaitTimeout = 300 * OneSecond; + + internal const int PeekDefinitionTimeout = 10 * OneSecond; + + // For testability only + internal Task DelayedDiagnosticsTask = null; + + private ConnectionService connectionService = null; + + private WorkspaceService workspaceServiceInstance; + + private ServiceHost serviceHostInstance; + + private object parseMapLock = new object(); + + private ScriptParseInfo currentCompletionParseInfo; + + private ConnectedBindingQueue bindingQueue = new ConnectedBindingQueue(); + + private ParseOptions defaultParseOptions = new ParseOptions( + batchSeparator: LanguageService.DefaultBatchSeperator, + isQuotedIdentifierSet: true, + compatibilityLevel: DatabaseCompatibilityLevel.Current, + transactSqlVersion: TransactSqlVersion.Current); + + private ConcurrentDictionary nonMssqlUriMap = new ConcurrentDictionary(); + + private Lazy> scriptParseInfoMap + = new Lazy>(() => new Dictionary()); + + /// + /// Gets a mapping dictionary for SQL file URIs to ScriptParseInfo objects + /// + internal Dictionary ScriptParseInfoMap + { + get + { + return this.scriptParseInfoMap.Value; + } + } + + private ParseOptions DefaultParseOptions + { + get + { + return this.defaultParseOptions; + } + } + + /// + /// Default, parameterless constructor. + /// + internal LanguageService() + { + } + + #endregion + + #region Properties + + /// + /// Gets or sets the binding queue instance + /// Internal for testing purposes only + /// + internal ConnectedBindingQueue BindingQueue + { + get + { + return this.bindingQueue; + } + set + { + this.bindingQueue = value; + } + } + + /// + /// Internal for testing purposes only + /// + internal ConnectionService ConnectionServiceInstance + { + get + { + if (connectionService == null) + { + connectionService = ConnectionService.Instance; + connectionService.RegisterConnectedQueue("LanguageService", bindingQueue); + } + return connectionService; + } + + set + { + connectionService = value; + } + } + + private CancellationTokenSource existingRequestCancellation; + + /// + /// Gets or sets the current workspace service instance + /// Setter for internal testing purposes only + /// + internal WorkspaceService WorkspaceServiceInstance + { + get + { + if (workspaceServiceInstance == null) + { + workspaceServiceInstance = WorkspaceService.Instance; + } + return workspaceServiceInstance; + } + set + { + workspaceServiceInstance = value; + } + } + + internal ServiceHost ServiceHostInstance + { + get + { + if (this.serviceHostInstance == null) + { + this.serviceHostInstance = ServiceHost.Instance; + } + return this.serviceHostInstance; + } + set + { + this.serviceHostInstance = value; + } + } + + /// + /// Gets the current settings + /// + internal SqlToolsSettings CurrentWorkspaceSettings + { + get { return WorkspaceServiceInstance.CurrentSettings; } + } + + /// + /// Gets the current workspace instance + /// + internal Workspace.Workspace CurrentWorkspace + { + get { return WorkspaceServiceInstance.Workspace; } + } + + /// + /// Gets or sets the current SQL Tools context + /// + /// + internal SqlToolsContext Context { get; set; } + + #endregion + + #region Public Methods + + /// + /// Initializes the Language Service instance + /// + /// + /// + public void InitializeService(ServiceHost serviceHost, SqlToolsContext context) + { + // Register the requests that this service will handle + + // turn off until needed (10/28/2016) + // serviceHost.SetRequestHandler(ReferencesRequest.Type, HandleReferencesRequest); + // serviceHost.SetRequestHandler(DocumentHighlightRequest.Type, HandleDocumentHighlightRequest); + + //serviceHost.SetRequestHandler(SignatureHelpRequest.Type, HandleSignatureHelpRequest); // Kusto api doesnt support this as of now. Implement it wherever applicable. Hover help is closest to signature help + serviceHost.SetRequestHandler(CompletionResolveRequest.Type, HandleCompletionResolveRequest); + serviceHost.SetRequestHandler(HoverRequest.Type, HandleHoverRequest); + serviceHost.SetRequestHandler(CompletionRequest.Type, HandleCompletionRequest); + serviceHost.SetRequestHandler(DefinitionRequest.Type, HandleDefinitionRequest); // Parses "Go to definition" functionality + serviceHost.SetRequestHandler(SyntaxParseRequest.Type, HandleSyntaxParseRequest); // Parses syntax errors + //serviceHost.SetRequestHandler(CompletionExtLoadRequest.Type, HandleCompletionExtLoadRequest); + serviceHost.SetEventHandler(RebuildIntelliSenseNotification.Type, HandleRebuildIntelliSenseNotification); + //serviceHost.SetEventHandler(LanguageFlavorChangeNotification.Type, HandleDidChangeLanguageFlavorNotification); + + // Register a no-op shutdown task for validation of the shutdown logic + serviceHost.RegisterShutdownTask(async (shutdownParams, shutdownRequestContext) => + { + Logger.Write(TraceEventType.Verbose, "Shutting down language service"); + DeletePeekDefinitionScripts(); + this.Dispose(); + await Task.FromResult(0); + }); + + ServiceHostInstance = serviceHost; + + // Register the configuration update handler + WorkspaceServiceInstance.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification); + + // Register the file change update handler + WorkspaceServiceInstance.RegisterTextDocChangeCallback(HandleDidChangeTextDocumentNotification); + + // Register the file open update handler + WorkspaceServiceInstance.RegisterTextDocOpenCallback(HandleDidOpenTextDocumentNotification); + + // Register a callback for when a connection is created + ConnectionServiceInstance.RegisterOnConnectionTask(UpdateLanguageServiceOnConnection); + + // Register a callback for when a connection is closed + ConnectionServiceInstance.RegisterOnDisconnectTask(RemoveAutoCompleteCacheUriReference); + + // Store the SqlToolsContext for future use + Context = context; + + } + + #endregion + + #region Request Handlers + + /// + /// T-SQL syntax parse request callback + /// + /// + /// + /// + internal async Task HandleSyntaxParseRequest(SyntaxParseParams param, RequestContext requestContext) + { + await Task.Run(async () => + { + try + { + ParseResult result = Parser.Parse(param.Query); + SyntaxParseResult syntaxResult = new SyntaxParseResult(); + if (result != null && result.Errors.Count() == 0) + { + syntaxResult.Parseable = true; + } else + { + syntaxResult.Parseable = false; + string[] errorMessages = new string[result.Errors.Count()]; + for (int i = 0; i < result.Errors.Count(); i++) + { + errorMessages[i] = result.Errors.ElementAt(i).Message; + } + syntaxResult.Errors = errorMessages; + } + await requestContext.SendResult(syntaxResult); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + }); + } + + /// + /// Auto-complete completion provider request callback + /// + /// + /// + /// + internal async Task HandleCompletionRequest( + TextDocumentPosition textDocumentPosition, + RequestContext requestContext) + { + try + { + // check if Intellisense suggestions are enabled + if (ShouldSkipIntellisense(textDocumentPosition.TextDocument.Uri)) + { + await requestContext.SendResult(null); + } + else + { + // get the current list of completion items and return to client + var scriptFile = CurrentWorkspace.GetFile( + textDocumentPosition.TextDocument.Uri); + if (scriptFile == null) + { + await requestContext.SendResult(null); + return; + } + + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + scriptFile.ClientUri, + out connInfo); + + var completionItems = GetCompletionItems( + textDocumentPosition, scriptFile, connInfo); + + await requestContext.SendResult(completionItems); + } + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Handle the resolve completion request event to provide additional + /// autocomplete metadata to the currently select completion item + /// + /// + /// + /// + internal async Task HandleCompletionResolveRequest( + CompletionItem completionItem, + RequestContext requestContext) + { + try + { + // check if Intellisense suggestions are enabled + // Note: Do not know file, so no need to check for MSSQL flavor + if (!CurrentWorkspaceSettings.IsSuggestionsEnabled) + { + await requestContext.SendResult(completionItem); + } + else + { + completionItem = ResolveCompletionItem(completionItem); + await requestContext.SendResult(completionItem); + } + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + internal async Task HandleDefinitionRequest(TextDocumentPosition textDocumentPosition, RequestContext requestContext) + { + try + { + DocumentStatusHelper.SendStatusChange(requestContext, textDocumentPosition, DocumentStatusHelper.DefinitionRequested); + + if (!ShouldSkipIntellisense(textDocumentPosition.TextDocument.Uri)) + { + // Retrieve document and connection + ConnectionInfo connInfo; + var scriptFile = CurrentWorkspace.GetFile(textDocumentPosition.TextDocument.Uri); + bool isConnected = false; + bool succeeded = false; + DefinitionResult definitionResult = null; + if (scriptFile != null) + { + isConnected = ConnectionServiceInstance.TryFindConnection(scriptFile.ClientUri, out connInfo); + definitionResult = GetDefinition(textDocumentPosition, scriptFile, connInfo); + } + + if (definitionResult != null && !definitionResult.IsErrorResult) + { + await requestContext.SendResult(definitionResult.Locations); + succeeded = true; + } + else + { + await requestContext.SendResult(Array.Empty()); + } + + DocumentStatusHelper.SendTelemetryEvent(requestContext, CreatePeekTelemetryProps(succeeded, isConnected)); + } + else + { + // Send an empty result so that processing does not hang when peek def service called from non-mssql clients + await requestContext.SendResult(Array.Empty()); + } + + DocumentStatusHelper.SendStatusChange(requestContext, textDocumentPosition, DocumentStatusHelper.DefinitionRequestCompleted); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + private static TelemetryProperties CreatePeekTelemetryProps(bool succeeded, bool connected) + { + return new TelemetryProperties + { + Properties = new Dictionary + { + { TelemetryPropertyNames.Succeeded, succeeded.ToOneOrZeroString() }, + { TelemetryPropertyNames.Connected, connected.ToOneOrZeroString() } + }, + EventName = TelemetryEventNames.PeekDefinitionRequested + }; + } + +// turn off this code until needed (10/28/2016) +#if false + private async Task HandleReferencesRequest( + ReferencesParams referencesParams, + RequestContext requestContext) + { + await requestContext.SendResult(null); + } + + private async Task HandleDocumentHighlightRequest( + TextDocumentPosition textDocumentPosition, + RequestContext requestContext) + { + await requestContext.SendResult(null); + } +#endif + + private async Task HandleHoverRequest( + TextDocumentPosition textDocumentPosition, + RequestContext requestContext) + { + try + { + // check if Quick Info hover tooltips are enabled + if (CurrentWorkspaceSettings.IsQuickInfoEnabled) + { + var scriptFile = CurrentWorkspace.GetFile( + textDocumentPosition.TextDocument.Uri); + + Hover hover = null; + if (scriptFile != null) + { + hover = GetHoverItem(textDocumentPosition, scriptFile); + } + if (hover != null) + { + await requestContext.SendResult(hover); + } + } + await requestContext.SendResult(null); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + #endregion + + #region Handlers for Events from Other Services + + /// + /// Handle the file open notification + /// + /// + /// + /// + /// + public async Task HandleDidOpenTextDocumentNotification( + string uri, + ScriptFile scriptFile, + EventContext eventContext) + { + try + { + // if not in the preview window and diagnostics are enabled then run diagnostics + if (!IsPreviewWindow(scriptFile) + && CurrentWorkspaceSettings.IsDiagnosticsEnabled) + { + await RunScriptDiagnostics( + new ScriptFile[] { scriptFile }, + eventContext); + } + + await Task.FromResult(true); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + // TODO: need mechanism return errors from event handlers + } + } + + /// + /// Handles text document change events + /// + /// + /// + public async Task HandleDidChangeTextDocumentNotification(ScriptFile[] changedFiles, EventContext eventContext) + { + try + { + if (CurrentWorkspaceSettings.IsDiagnosticsEnabled) + { + // Only process files that are MSSQL flavor + await this.RunScriptDiagnostics( + changedFiles.ToArray(), + eventContext); + } + + await Task.FromResult(true); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + // TODO: need mechanism return errors from event handlers + } + } + + /// + /// Handle the rebuild IntelliSense cache notification + /// + public async Task HandleRebuildIntelliSenseNotification( + RebuildIntelliSenseParams rebuildParams, + EventContext eventContext) + { + try + { + Logger.Write(TraceEventType.Verbose, "HandleRebuildIntelliSenseNotification"); + + // Skip closing this file if the file doesn't exist + var scriptFile = this.CurrentWorkspace.GetFile(rebuildParams.OwnerUri); + if (scriptFile == null) + { + return; + } + + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + scriptFile.ClientUri, + out connInfo); + + // check that there is an active connection for the current editor + if (connInfo != null) + { + await Task.Run(() => + { + // Get the current ScriptInfo if one exists so we can lock it while we're rebuilding the cache + ScriptParseInfo scriptInfo = GetScriptParseInfo(connInfo.OwnerUri, createIfNotExists: false); + if (scriptInfo != null && scriptInfo.IsConnected && + Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) + { + try + { + this.BindingQueue.AddConnectionContext(connInfo, featureName: "LanguageService", overwrite: true); + RemoveScriptParseInfo(rebuildParams.OwnerUri); + UpdateLanguageServiceOnConnection(connInfo).Wait(); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + } + finally + { + // Set Metadata Build event to Signal state. + Monitor.Exit(scriptInfo.BuildingMetadataLock); + } + } + + // if not in the preview window and diagnostics are enabled then run diagnostics + if (!IsPreviewWindow(scriptFile) + && CurrentWorkspaceSettings.IsDiagnosticsEnabled) + { + RunScriptDiagnostics( + new ScriptFile[] { scriptFile }, + eventContext); + } + + // Send a notification to signal that autocomplete is ready + ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri}); + }); + } + else + { + // Send a notification to signal that autocomplete is ready + await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri}); + } + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + await ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = rebuildParams.OwnerUri}); + } + } + + /// + /// Handle the file configuration change notification + /// + /// + /// + /// + public async Task HandleDidChangeConfigurationNotification( + SqlToolsSettings newSettings, + SqlToolsSettings oldSettings, + EventContext eventContext) + { + try + { + bool oldEnableIntelliSense = oldSettings.SqlTools.IntelliSense.EnableIntellisense; + bool? oldEnableDiagnostics = oldSettings.SqlTools.IntelliSense.EnableErrorChecking; + + // update the current settings to reflect any changes + CurrentWorkspaceSettings.Update(newSettings); + + // if script analysis settings have changed we need to clear the current diagnostic markers + if (oldEnableIntelliSense != newSettings.SqlTools.IntelliSense.EnableIntellisense + || oldEnableDiagnostics != newSettings.SqlTools.IntelliSense.EnableErrorChecking) + { + // if the user just turned off diagnostics then send an event to clear the error markers + if (!newSettings.IsDiagnosticsEnabled) + { + ScriptFileMarker[] emptyAnalysisDiagnostics = new ScriptFileMarker[0]; + + foreach (var scriptFile in CurrentWorkspace.GetOpenedFiles()) + { + await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientUri, eventContext); + } + } + // otherwise rerun diagnostic analysis on all opened SQL files + else + { + await this.RunScriptDiagnostics(CurrentWorkspace.GetOpenedFiles(), eventContext); + } + } + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + // TODO: need mechanism return errors from event handlers + } + } + + #endregion + + + #region "AutoComplete Provider methods" + + /// + /// Remove a reference to an autocomplete cache from a URI. If + /// it is the last URI connected to a particular connection, + /// then remove the cache. + /// + public async Task RemoveAutoCompleteCacheUriReference(IConnectionSummary summary, string ownerUri) + { + RemoveScriptParseInfo(ownerUri); + + // currently this method is disabled, but we need to reimplement now that the + // implementation of the 'cache' has changed. + await Task.FromResult(0); + } + + /// + /// Update the autocomplete metadata provider when the user connects to a database + /// + /// + public async Task UpdateLanguageServiceOnConnection(ConnectionInfo connInfo) + { + await Task.Run(() => + { + if (ConnectionService.IsDedicatedAdminConnection(connInfo.ConnectionDetails)) + { + // Intellisense cannot be run on these connections as only 1 SqlConnection can be opened on them at a time + return; + } + ScriptParseInfo scriptInfo = GetScriptParseInfo(connInfo.OwnerUri, createIfNotExists: true); + if (Monitor.TryEnter(scriptInfo.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) + { + try + { + scriptInfo.ConnectionKey = this.BindingQueue.AddConnectionContext(connInfo, "languageService"); + scriptInfo.IsConnected = this.BindingQueue.IsBindingContextConnected(scriptInfo.ConnectionKey); + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error in OnConnection " + ex.ToString()); + scriptInfo.IsConnected = false; + } + finally + { + // Set Metadata Build event to Signal state. + // (Tell Language Service that I am ready with Metadata Provider Object) + Monitor.Exit(scriptInfo.BuildingMetadataLock); + } + } + + // TODOKusto: I dont think its required. Confirm later + // PrepopulateCommonMetadata(connInfo, scriptInfo, this.BindingQueue); + + // Send a notification to signal that autocomplete is ready + ServiceHostInstance.SendEvent(IntelliSenseReadyNotification.Type, new IntelliSenseReadyParams() {OwnerUri = connInfo.OwnerUri}); + }); + } + + /// + /// Checks if a given URI is not an MSSQL file. Only files explicitly excluded by a language flavor change + /// notification will be treated as skippable + /// + public virtual bool ShouldSkipNonMssqlFile(string uri) + { + bool isNonMssql = false; + nonMssqlUriMap.TryGetValue(uri, out isNonMssql); + return isNonMssql; + } + + /// + /// Determines whether intellisense should be skipped for a document. + /// If IntelliSense is disabled or it's a non-MSSQL doc this will be skipped + /// + private bool ShouldSkipIntellisense(string uri) + { + return !CurrentWorkspaceSettings.IsSuggestionsEnabled + || ShouldSkipNonMssqlFile(uri); + } + + /// + /// Resolves the details and documentation for a completion item. Move functionality to data source specific file when Language API supports description/details info. + /// TODOKusto:Currently Kusto doesnt support getting the description details + /// + /// + internal CompletionItem ResolveCompletionItem(CompletionItem completionItem) + { + return completionItem; + } + + /// + /// Get definition for a selected text from DataSource. + /// + /// + /// + /// + /// Location with the URI of the script file + internal DefinitionResult GetDefinition(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ConnectionInfo connInfo) + { + // Parse sql + ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri); + if (scriptParseInfo == null) + { + return null; + } + + if (scriptParseInfo.IsConnected) + { + ReliableDataSourceConnection connection; + connInfo.TryGetConnection("Default", out connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + + return dataSource.GetDefinition(scriptFile.Contents, textDocumentPosition.Position.Character, 1, 1); + } + else + { + // User is not connected. + return new DefinitionResult + { + IsErrorResult = true, + Message = SR.PeekDefinitionNotConnectedError, + Locations = null + }; + } + } + + /// + /// Get quick info hover tooltips for the current position + /// + /// + /// + internal Hover GetHoverItem(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile) + { + int startLine = textDocumentPosition.Position.Line; + int startColumn = TextUtilities.PositionOfPrevDelimeter( + scriptFile.Contents, + textDocumentPosition.Position.Line, + textDocumentPosition.Position.Character); + int endColumn = textDocumentPosition.Position.Character; + + ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri); + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + scriptFile.ClientUri, + out connInfo); + + if (scriptParseInfo != null && scriptParseInfo.ParseResult != null) // populate parseresult or check why it is used. + { + if (Monitor.TryEnter(scriptParseInfo.BuildingMetadataLock)) + { + try + { + QueueItem queueItem = this.BindingQueue.QueueBindingOperation( + key: scriptParseInfo.ConnectionKey, + bindingTimeout: LanguageService.HoverTimeout, + bindOperation: (bindingContext, cancelToken) => + { + // get the current quick info text + ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo); + + ReliableDataSourceConnection connection; + connInfo.TryGetConnection("Default", out connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + + return dataSource.GetHoverHelp(scriptDocumentInfo, textDocumentPosition.Position); + }); + + queueItem.ItemProcessed.WaitOne(); + return queueItem.GetResultAsT(); + } + finally + { + Monitor.Exit(scriptParseInfo.BuildingMetadataLock); + } + } + } + + // return null if there isn't a tooltip for the current location + return null; + } + + /// + /// Return the completion item list for the current text position. + /// This method does not await cache builds since it expects to return quickly + /// + /// + public CompletionItem[] GetCompletionItems( + TextDocumentPosition textDocumentPosition, + ScriptFile scriptFile, + ConnectionInfo connInfo) + { + // initialize some state to parse and bind the current script file + this.currentCompletionParseInfo = null; + CompletionItem[] resultCompletionItems = null; + bool useLowerCaseSuggestions = this.CurrentWorkspaceSettings.SqlTools.IntelliSense.LowerCaseSuggestions.Value; + + // get the current script parse info object + ScriptParseInfo scriptParseInfo = GetScriptParseInfo(scriptFile.ClientUri); + + if (scriptParseInfo == null) + { + var scriptDocInfo = ScriptDocumentInfo.CreateDefaultDocumentInfo(textDocumentPosition, scriptFile); + resultCompletionItems = resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocInfo, textDocumentPosition.Position); //TODO_KUSTO: DataSourceFactory.GetDefaultAutoComplete 1st param should get the datasource type generically instead of hard coded DataSourceType.Kusto + return resultCompletionItems; + } + + ScriptDocumentInfo scriptDocumentInfo = new ScriptDocumentInfo(textDocumentPosition, scriptFile, scriptParseInfo); + + if(connInfo != null){ + ReliableDataSourceConnection connection; + connInfo.TryGetConnection("Default", out connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + + resultCompletionItems = dataSource.GetAutoCompleteSuggestions(scriptDocumentInfo, textDocumentPosition.Position); + } + else{ + resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocumentInfo, textDocumentPosition.Position); + } + + // cache the current script parse info object to resolve completions later. Used for the detailed description. + this.currentCompletionParseInfo = scriptParseInfo; + + + // if the parse failed then return the default list + if (scriptParseInfo.ParseResult == null) + { + resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocumentInfo, textDocumentPosition.Position); + return resultCompletionItems; + } + + // if there are no completions then provide the default list + if (resultCompletionItems == null) // this is the getting default keyword option when its not connected + { + resultCompletionItems = DataSourceFactory.GetDefaultAutoComplete(DataSourceType.Kusto, scriptDocumentInfo, textDocumentPosition.Position); + } + + return resultCompletionItems; + } + + #endregion + + #region Diagnostic Provider methods + + /// + /// Runs script diagnostics on changed files + /// + /// + /// + private Task RunScriptDiagnostics(ScriptFile[] filesToAnalyze, EventContext eventContext) + { + if (!CurrentWorkspaceSettings.IsDiagnosticsEnabled) + { + // If the user has disabled script analysis, skip it entirely + return Task.FromResult(true); + } + + // If there's an existing task, attempt to cancel it + try + { + if (existingRequestCancellation != null) + { + // Try to cancel the request + existingRequestCancellation.Cancel(); + + // If cancellation didn't throw an exception, + // clean up the existing token + existingRequestCancellation.Dispose(); + existingRequestCancellation = null; + } + } + catch (Exception e) + { + Logger.Write(TraceEventType.Error, string.Format("Exception while cancelling analysis task:\n\n{0}", e.ToString())); + + TaskCompletionSource cancelTask = new TaskCompletionSource(); + cancelTask.SetCanceled(); + return cancelTask.Task; + } + + // Create a fresh cancellation token and then start the task. + // We create this on a different TaskScheduler so that we + // don't block the main message loop thread. + existingRequestCancellation = new CancellationTokenSource(); + Task.Factory.StartNew( + () => + this.DelayedDiagnosticsTask = DelayThenInvokeDiagnostics( + LanguageService.DiagnosticParseDelay, + filesToAnalyze, + eventContext, + existingRequestCancellation.Token), + CancellationToken.None, + TaskCreationOptions.None, + TaskScheduler.Default); + + return Task.FromResult(true); + } + + /// + /// Actually run the script diagnostics after waiting for some small delay + /// + /// + /// + /// + /// + private async Task DelayThenInvokeDiagnostics( + int delayMilliseconds, + ScriptFile[] filesToAnalyze, + EventContext eventContext, + CancellationToken cancellationToken) + { + // First of all, wait for the desired delay period before + // analyzing the provided list of files + try + { + await Task.Delay(delayMilliseconds, cancellationToken); + } + catch (TaskCanceledException) + { + // If the task is cancelled, exit directly + return; + } + + // If we've made it past the delay period then we don't care + // about the cancellation token anymore. This could happen + // when the user stops typing for long enough that the delay + // period ends but then starts typing while analysis is going + // on. It makes sense to send back the results from the first + // delay period while the second one is ticking away. + + // Get the requested files + foreach (ScriptFile scriptFile in filesToAnalyze) + { + if (IsPreviewWindow(scriptFile)) + { + continue; + } + else if (ShouldSkipNonMssqlFile(scriptFile.ClientUri)) + { + // Clear out any existing markers in case file type was changed + await DiagnosticsHelper.ClearScriptDiagnostics(scriptFile.ClientUri, eventContext); + continue; + } + + Logger.Write(TraceEventType.Verbose, "Analyzing script file: " + scriptFile.FilePath); + + // TODOKusto: Add file for mapping here, parity from parseAndbind function. Confirm it. + ScriptParseInfo parseInfo = GetScriptParseInfo(scriptFile.ClientUri, createIfNotExists: true); + + ScriptFileMarker[] semanticMarkers = null; + ConnectionInfo connInfo; + ConnectionServiceInstance.TryFindConnection( + scriptFile.ClientUri, + out connInfo); + + if(connInfo != null){ + connInfo.TryGetConnection("Default", out var connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + + semanticMarkers = dataSource.GetSemanticMarkers(parseInfo, scriptFile, scriptFile.Contents); + } + else{ + semanticMarkers = DataSourceFactory.GetDefaultSemanticMarkers(DataSourceType.Kusto, parseInfo, scriptFile, scriptFile.Contents); + } + + Logger.Write(TraceEventType.Verbose, "Analysis complete."); + + await DiagnosticsHelper.PublishScriptDiagnostics(scriptFile, semanticMarkers, eventContext); + } + } + + #endregion + + /// + /// Gets a script parse info object for a file from the local cache + /// Internal for testing purposes only + /// + /// + /// Creates a new instance if one doesn't exist + internal ScriptParseInfo GetScriptParseInfo(string uri, bool createIfNotExists = false) + { + lock (this.parseMapLock) + { + if (this.ScriptParseInfoMap.ContainsKey(uri)) + { + return this.ScriptParseInfoMap[uri]; + } + else if (createIfNotExists) + { + // create a new script parse info object and initialize with the current settings + ScriptParseInfo scriptInfo = new ScriptParseInfo(); + this.ScriptParseInfoMap.Add(uri, scriptInfo); + return scriptInfo; + } + else + { + return null; + } + } + } + + internal bool RemoveScriptParseInfo(string uri) + { + lock (this.parseMapLock) + { + if (this.ScriptParseInfoMap.ContainsKey(uri)) + { + return this.ScriptParseInfoMap.Remove(uri); + } + else + { + return false; + } + } + } + + /// + /// Returns a flag indicating if the ScriptFile refers to the output window. + /// + /// + internal bool IsPreviewWindow(ScriptFile scriptFile) + { + if (scriptFile != null && !string.IsNullOrWhiteSpace(scriptFile.ClientUri)) + { + return scriptFile.ClientUri.StartsWith("tsqloutput:"); + } + else + { + return false; + } + } + + internal void DeletePeekDefinitionScripts() + { + // Delete temp folder created to store peek definition scripts + if (FileUtilities.SafeDirectoryExists(FileUtilities.PeekDefinitionTempFolder)) + { + FileUtilities.SafeDirectoryDelete(FileUtilities.PeekDefinitionTempFolder, true); + } + } + + internal string ParseStatementAtPosition(string sql, int line, int column) + { + // adjust from 0-based to 1-based index + int parserLine = line + 1; + int parserColumn = column + 1; + + // parse current SQL file contents to retrieve a list of errors + ParseResult parseResult = Parser.Parse(sql, this.DefaultParseOptions); + if (parseResult != null && parseResult.Script != null && parseResult.Script.Batches != null) + { + foreach (var batch in parseResult.Script.Batches) + { + if (batch.Statements == null) + { + continue; + } + + // If there is a single statement on the line, track it so that we can return it regardless of where the user's cursor is + SqlStatement lineStatement = null; + bool? lineHasSingleStatement = null; + + // check if the batch matches parameters + if (batch.StartLocation.LineNumber <= parserLine + && batch.EndLocation.LineNumber >= parserLine) + { + foreach (var statement in batch.Statements) + { + // check if the statement matches parameters + if (statement.StartLocation.LineNumber <= parserLine + && statement.EndLocation.LineNumber >= parserLine) + { + if (statement.EndLocation.LineNumber == parserLine && statement.EndLocation.ColumnNumber < parserColumn + || statement.StartLocation.LineNumber == parserLine && statement.StartLocation.ColumnNumber > parserColumn) + { + if (lineHasSingleStatement == null) + { + lineHasSingleStatement = true; + lineStatement = statement; + } + else if (lineHasSingleStatement == true) + { + lineHasSingleStatement = false; + } + continue; + } + return statement.Sql; + } + } + } + + if (lineHasSingleStatement == true) + { + return lineStatement.Sql; + } + } + } + + return string.Empty; + } + + public void Dispose() + { + if (bindingQueue != null) + { + bindingQueue.Dispose(); + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/PeekDefinitionResult.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/PeekDefinitionResult.cs new file mode 100644 index 0000000000..b9884df907 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/PeekDefinitionResult.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// /// Result object for PeekDefinition + /// + public class DefinitionResult + { + /// + /// True, if definition error occured + /// + public bool IsErrorResult; + + /// + /// Error message, if any + /// + public string Message { get; set; } + + /// + /// Location object representing the definition script file + /// + public Location[] Locations; + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/QueueItem.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/QueueItem.cs new file mode 100644 index 0000000000..d9610ddbd4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/QueueItem.cs @@ -0,0 +1,77 @@ +// +// 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.Threading; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices +{ + /// + /// Class that stores the state of a binding queue request item + /// + public class QueueItem + { + /// + /// QueueItem constructor + /// + public QueueItem() + { + this.ItemProcessed = new ManualResetEvent(initialState: false); + } + + /// + /// Gets or sets the queue item key + /// + public string Key { get; set; } + + /// + /// Gets or sets the bind operation callback method + /// + public Func BindOperation { get; set; } + + /// + /// Gets or sets the timeout operation to call if the bind operation doesn't finish within timeout period + /// + public Func TimeoutOperation { get; set; } + + /// + /// Gets or sets the operation to call if the bind operation encounters an unexpected exception. + /// Supports returning an object in case of the exception occurring since in some cases we need to be + /// tolerant of error cases and still return some value + /// + public Func ErrorHandler { get; set; } + + /// + /// Gets or sets an event to signal when this queue item has been processed + /// + public virtual ManualResetEvent ItemProcessed { get; set; } + + /// + /// Gets or sets the result of the queued task + /// + public object Result { get; set; } + + /// + /// Gets or sets the binding operation timeout in milliseconds + /// + public int? BindingTimeout { get; set; } + + /// + /// Gets or sets the timeout for how long to wait for the binding lock + /// + public int? WaitForLockTimeout { get; set; } + + /// + /// Converts the result of the execution to type T + /// + public T GetResultAsT() where T : class + { + //var task = this.ResultsTask; + return (this.Result != null) + ? this.Result as T + : null; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs new file mode 100644 index 0000000000..0f8eb96842 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/LanguageServices/ScriptDocumentInfo.cs @@ -0,0 +1,107 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlServer.Management.SqlParser.Parser; +using Microsoft.SqlTools.Utility; +using Microsoft.Kusto.ServiceLayer.DataSource.DataSourceIntellisense; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.LanguageServices.Completion +{ + /// + /// A class to calculate the numbers used by SQL parser using the text positions and content + /// + public class ScriptDocumentInfo + { + /// + /// Create new instance + /// + public ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile, ScriptParseInfo scriptParseInfo) + : this(textDocumentPosition, scriptFile) + { + Validate.IsNotNull(nameof(scriptParseInfo), scriptParseInfo); + + ScriptParseInfo = scriptParseInfo; + } + + private ScriptDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile) + { + StartLine = textDocumentPosition.Position.Line; + ParserLine = textDocumentPosition.Position.Line + 1; + StartColumn = TextUtilities.PositionOfPrevDelimeter( + scriptFile.Contents, + textDocumentPosition.Position.Line, + textDocumentPosition.Position.Character); + EndColumn = TextUtilities.PositionOfNextDelimeter( + scriptFile.Contents, + textDocumentPosition.Position.Line, + textDocumentPosition.Position.Character); + ParserColumn = textDocumentPosition.Position.Character + 1; + Contents = scriptFile.Contents; + } + + /// + /// Creates a new with no backing defined + /// + /// A + /// A to process + /// + public static ScriptDocumentInfo CreateDefaultDocumentInfo(TextDocumentPosition textDocumentPosition, ScriptFile scriptFile) + { + return new ScriptDocumentInfo(textDocumentPosition, scriptFile); + } + + /// + /// Gets a string containing the full contents of the file. + /// + public string Contents { get; private set; } + + /// + /// Script Parse Info Instance + /// + public ScriptParseInfo ScriptParseInfo { get; private set; } + + /// + /// Start Line + /// + public int StartLine { get; private set; } + + /// + /// Parser Line + /// + public int ParserLine { get; private set; } + + /// + /// Start Column + /// + public int StartColumn { get; private set; } + + /// + /// end Column + /// + public int EndColumn { get; private set; } + + /// + /// Parser Column + /// + public int ParserColumn { get; private set; } + + /// + /// The token text in the file content used for completion list + /// + public virtual string TokenText + { + get + { + return Token != null ? Token.Text : null; + } + } + + /// + /// The token in the file content used for completion list + /// + public Token Token { get; private set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.cs b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.cs new file mode 100644 index 0000000000..ba7f753f46 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.cs @@ -0,0 +1,4365 @@ +// WARNING: +// This file was generated by the Microsoft DataWarehouse String Resource Tool 4.0.0.0 +// from information in sr.strings +// DO NOT MODIFY THIS FILE'S CONTENTS, THEY WILL BE OVERWRITTEN +// +namespace Microsoft.Kusto.ServiceLayer +{ + using System; + using System.Reflection; + using System.Resources; + using System.Globalization; + + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class SR + { + protected SR() + { } + + public static CultureInfo Culture + { + get + { + return Keys.Culture; + } + set + { + Keys.Culture = value; + } + } + + + public static string ConnectionServiceConnectErrorNullParams + { + get + { + return Keys.GetString(Keys.ConnectionServiceConnectErrorNullParams); + } + } + + public static string ConnectionServiceListDbErrorNullOwnerUri + { + get + { + return Keys.GetString(Keys.ConnectionServiceListDbErrorNullOwnerUri); + } + } + + public static string ConnectionServiceConnectionCanceled + { + get + { + return Keys.GetString(Keys.ConnectionServiceConnectionCanceled); + } + } + + public static string ConnectionParamsValidateNullOwnerUri + { + get + { + return Keys.GetString(Keys.ConnectionParamsValidateNullOwnerUri); + } + } + + public static string ConnectionParamsValidateNullConnection + { + get + { + return Keys.GetString(Keys.ConnectionParamsValidateNullConnection); + } + } + + public static string ConnectionParamsValidateNullServerName + { + get + { + return Keys.GetString(Keys.ConnectionParamsValidateNullServerName); + } + } + + public static string AzureSqlDbEdition + { + get + { + return Keys.GetString(Keys.AzureSqlDbEdition); + } + } + + public static string AzureSqlDwEdition + { + get + { + return Keys.GetString(Keys.AzureSqlDwEdition); + } + } + + public static string AzureSqlStretchEdition + { + get + { + return Keys.GetString(Keys.AzureSqlStretchEdition); + } + } + + public static string QueryServiceCancelAlreadyCompleted + { + get + { + return Keys.GetString(Keys.QueryServiceCancelAlreadyCompleted); + } + } + + public static string QueryServiceCancelDisposeFailed + { + get + { + return Keys.GetString(Keys.QueryServiceCancelDisposeFailed); + } + } + + public static string QueryServiceQueryCancelled + { + get + { + return Keys.GetString(Keys.QueryServiceQueryCancelled); + } + } + + public static string QueryServiceSubsetBatchNotCompleted + { + get + { + return Keys.GetString(Keys.QueryServiceSubsetBatchNotCompleted); + } + } + + public static string QueryServiceSubsetBatchOutOfRange + { + get + { + return Keys.GetString(Keys.QueryServiceSubsetBatchOutOfRange); + } + } + + public static string QueryServiceSubsetResultSetOutOfRange + { + get + { + return Keys.GetString(Keys.QueryServiceSubsetResultSetOutOfRange); + } + } + + public static string QueryServiceDataReaderByteCountInvalid + { + get + { + return Keys.GetString(Keys.QueryServiceDataReaderByteCountInvalid); + } + } + + public static string QueryServiceDataReaderCharCountInvalid + { + get + { + return Keys.GetString(Keys.QueryServiceDataReaderCharCountInvalid); + } + } + + public static string QueryServiceDataReaderXmlCountInvalid + { + get + { + return Keys.GetString(Keys.QueryServiceDataReaderXmlCountInvalid); + } + } + + public static string QueryServiceFileWrapperWriteOnly + { + get + { + return Keys.GetString(Keys.QueryServiceFileWrapperWriteOnly); + } + } + + public static string QueryServiceFileWrapperNotInitialized + { + get + { + return Keys.GetString(Keys.QueryServiceFileWrapperNotInitialized); + } + } + + public static string QueryServiceFileWrapperReadOnly + { + get + { + return Keys.GetString(Keys.QueryServiceFileWrapperReadOnly); + } + } + + public static string QueryServiceAffectedOneRow + { + get + { + return Keys.GetString(Keys.QueryServiceAffectedOneRow); + } + } + + public static string QueryServiceCompletedSuccessfully + { + get + { + return Keys.GetString(Keys.QueryServiceCompletedSuccessfully); + } + } + + public static string QueryServiceColumnNull + { + get + { + return Keys.GetString(Keys.QueryServiceColumnNull); + } + } + + public static string QueryServiceCellNull + { + get + { + return Keys.GetString(Keys.QueryServiceCellNull); + } + } + + public static string QueryServiceRequestsNoQuery + { + get + { + return Keys.GetString(Keys.QueryServiceRequestsNoQuery); + } + } + + public static string QueryServiceQueryInvalidOwnerUri + { + get + { + return Keys.GetString(Keys.QueryServiceQueryInvalidOwnerUri); + } + } + + public static string QueryServiceQueryInProgress + { + get + { + return Keys.GetString(Keys.QueryServiceQueryInProgress); + } + } + + public static string QueryServiceMessageSenderNotSql + { + get + { + return Keys.GetString(Keys.QueryServiceMessageSenderNotSql); + } + } + + public static string QueryServiceResultSetAddNoRows + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetAddNoRows); + } + } + + public static string QueryServiceResultSetHasNoResults + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetHasNoResults); + } + } + + public static string QueryServiceResultSetTooLarge + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetTooLarge); + } + } + + public static string QueryServiceSaveAsResultSetNotComplete + { + get + { + return Keys.GetString(Keys.QueryServiceSaveAsResultSetNotComplete); + } + } + + public static string QueryServiceSaveAsMiscStartingError + { + get + { + return Keys.GetString(Keys.QueryServiceSaveAsMiscStartingError); + } + } + + public static string QueryServiceSaveAsInProgress + { + get + { + return Keys.GetString(Keys.QueryServiceSaveAsInProgress); + } + } + + public static string QueryServiceResultSetNotRead + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetNotRead); + } + } + + public static string QueryServiceResultSetStartRowOutOfRange + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetStartRowOutOfRange); + } + } + + public static string QueryServiceResultSetRowCountOutOfRange + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetRowCountOutOfRange); + } + } + + public static string QueryServiceResultSetNoColumnSchema + { + get + { + return Keys.GetString(Keys.QueryServiceResultSetNoColumnSchema); + } + } + + public static string QueryServiceExecutionPlanNotFound + { + get + { + return Keys.GetString(Keys.QueryServiceExecutionPlanNotFound); + } + } + + public static string PeekDefinitionNoResultsError + { + get + { + return Keys.GetString(Keys.PeekDefinitionNoResultsError); + } + } + + public static string PeekDefinitionDatabaseError + { + get + { + return Keys.GetString(Keys.PeekDefinitionDatabaseError); + } + } + + public static string PeekDefinitionNotConnectedError + { + get + { + return Keys.GetString(Keys.PeekDefinitionNotConnectedError); + } + } + + public static string PeekDefinitionTimedoutError + { + get + { + return Keys.GetString(Keys.PeekDefinitionTimedoutError); + } + } + + public static string PeekDefinitionTypeNotSupportedError + { + get + { + return Keys.GetString(Keys.PeekDefinitionTypeNotSupportedError); + } + } + + public static string ErrorEmptyStringReplacement + { + get + { + return Keys.GetString(Keys.ErrorEmptyStringReplacement); + } + } + + public static string WorkspaceServicePositionLineOutOfRange + { + get + { + return Keys.GetString(Keys.WorkspaceServicePositionLineOutOfRange); + } + } + + public static string EditDataObjectNotFound + { + get + { + return Keys.GetString(Keys.EditDataObjectNotFound); + } + } + + public static string EditDataSessionNotFound + { + get + { + return Keys.GetString(Keys.EditDataSessionNotFound); + } + } + + public static string EditDataSessionAlreadyExists + { + get + { + return Keys.GetString(Keys.EditDataSessionAlreadyExists); + } + } + + public static string EditDataSessionNotInitialized + { + get + { + return Keys.GetString(Keys.EditDataSessionNotInitialized); + } + } + + public static string EditDataSessionAlreadyInitialized + { + get + { + return Keys.GetString(Keys.EditDataSessionAlreadyInitialized); + } + } + + public static string EditDataSessionAlreadyInitializing + { + get + { + return Keys.GetString(Keys.EditDataSessionAlreadyInitializing); + } + } + + public static string EditDataMetadataNotExtended + { + get + { + return Keys.GetString(Keys.EditDataMetadataNotExtended); + } + } + + public static string EditDataMetadataObjectNameRequired + { + get + { + return Keys.GetString(Keys.EditDataMetadataObjectNameRequired); + } + } + + public static string EditDataMetadataTooManyIdentifiers + { + get + { + return Keys.GetString(Keys.EditDataMetadataTooManyIdentifiers); + } + } + + public static string EditDataFilteringNegativeLimit + { + get + { + return Keys.GetString(Keys.EditDataFilteringNegativeLimit); + } + } + + public static string EditDataQueryFailed + { + get + { + return Keys.GetString(Keys.EditDataQueryFailed); + } + } + + public static string EditDataQueryNotCompleted + { + get + { + return Keys.GetString(Keys.EditDataQueryNotCompleted); + } + } + + public static string EditDataQueryImproperResultSets + { + get + { + return Keys.GetString(Keys.EditDataQueryImproperResultSets); + } + } + + public static string EditDataFailedAddRow + { + get + { + return Keys.GetString(Keys.EditDataFailedAddRow); + } + } + + public static string EditDataRowOutOfRange + { + get + { + return Keys.GetString(Keys.EditDataRowOutOfRange); + } + } + + public static string EditDataUpdatePending + { + get + { + return Keys.GetString(Keys.EditDataUpdatePending); + } + } + + public static string EditDataUpdateNotPending + { + get + { + return Keys.GetString(Keys.EditDataUpdateNotPending); + } + } + + public static string EditDataObjectMetadataNotFound + { + get + { + return Keys.GetString(Keys.EditDataObjectMetadataNotFound); + } + } + + public static string EditDataInvalidFormatBinary + { + get + { + return Keys.GetString(Keys.EditDataInvalidFormatBinary); + } + } + + public static string EditDataInvalidFormatBoolean + { + get + { + return Keys.GetString(Keys.EditDataInvalidFormatBoolean); + } + } + + public static string EditDataDeleteSetCell + { + get + { + return Keys.GetString(Keys.EditDataDeleteSetCell); + } + } + + public static string EditDataColumnIdOutOfRange + { + get + { + return Keys.GetString(Keys.EditDataColumnIdOutOfRange); + } + } + + public static string EditDataColumnCannotBeEdited + { + get + { + return Keys.GetString(Keys.EditDataColumnCannotBeEdited); + } + } + + public static string EditDataColumnNoKeyColumns + { + get + { + return Keys.GetString(Keys.EditDataColumnNoKeyColumns); + } + } + + public static string EditDataScriptFilePathNull + { + get + { + return Keys.GetString(Keys.EditDataScriptFilePathNull); + } + } + + public static string EditDataCommitInProgress + { + get + { + return Keys.GetString(Keys.EditDataCommitInProgress); + } + } + + public static string EditDataComputedColumnPlaceholder + { + get + { + return Keys.GetString(Keys.EditDataComputedColumnPlaceholder); + } + } + + public static string EditDataTimeOver24Hrs + { + get + { + return Keys.GetString(Keys.EditDataTimeOver24Hrs); + } + } + + public static string EditDataNullNotAllowed + { + get + { + return Keys.GetString(Keys.EditDataNullNotAllowed); + } + } + + public static string EditDataMultiTableNotSupported + { + get + { + return Keys.GetString(Keys.EditDataMultiTableNotSupported); + } + } + + public static string EditDataAliasesNotSupported + { + get + { + return Keys.GetString(Keys.EditDataAliasesNotSupported); + } + } + + public static string EditDataExpressionsNotSupported + { + get + { + return Keys.GetString(Keys.EditDataExpressionsNotSupported); + } + } + + public static string EditDataDuplicateColumnsNotSupported + { + get + { + return Keys.GetString(Keys.EditDataDuplicateColumnsNotSupported); + } + } + + public static string EE_ExecutionInfo_InitializingLoop + { + get + { + return Keys.GetString(Keys.EE_ExecutionInfo_InitializingLoop); + } + } + + public static string EE_BatchExecutionError_Ignoring + { + get + { + return Keys.GetString(Keys.EE_BatchExecutionError_Ignoring); + } + } + + public static string EE_ExecutionInfo_FinalizingLoop + { + get + { + return Keys.GetString(Keys.EE_ExecutionInfo_FinalizingLoop); + } + } + + public static string BatchParserWrapperExecutionError + { + get + { + return Keys.GetString(Keys.BatchParserWrapperExecutionError); + } + } + + public static string TestLocalizationConstant + { + get + { + return Keys.GetString(Keys.TestLocalizationConstant); + } + } + + public static string SqlScriptFormatterDecimalMissingPrecision + { + get + { + return Keys.GetString(Keys.SqlScriptFormatterDecimalMissingPrecision); + } + } + + public static string SqlScriptFormatterLengthTypeMissingSize + { + get + { + return Keys.GetString(Keys.SqlScriptFormatterLengthTypeMissingSize); + } + } + + public static string SqlScriptFormatterScalarTypeMissingScale + { + get + { + return Keys.GetString(Keys.SqlScriptFormatterScalarTypeMissingScale); + } + } + + public static string TreeNodeError + { + get + { + return Keys.GetString(Keys.TreeNodeError); + } + } + + public static string ServerNodeConnectionError + { + get + { + return Keys.GetString(Keys.ServerNodeConnectionError); + } + } + + public static string SchemaHierarchy_Aggregates + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Aggregates); + } + } + + public static string SchemaHierarchy_ServerRoles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerRoles); + } + } + + public static string SchemaHierarchy_ApplicationRoles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ApplicationRoles); + } + } + + public static string SchemaHierarchy_Assemblies + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Assemblies); + } + } + + public static string SchemaHierarchy_AssemblyFiles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_AssemblyFiles); + } + } + + public static string SchemaHierarchy_AsymmetricKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_AsymmetricKeys); + } + } + + public static string SchemaHierarchy_DatabaseAsymmetricKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseAsymmetricKeys); + } + } + + public static string SchemaHierarchy_DataCompressionOptions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DataCompressionOptions); + } + } + + public static string SchemaHierarchy_Certificates + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Certificates); + } + } + + public static string SchemaHierarchy_FileTables + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FileTables); + } + } + + public static string SchemaHierarchy_DatabaseCertificates + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseCertificates); + } + } + + public static string SchemaHierarchy_CheckConstraints + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_CheckConstraints); + } + } + + public static string SchemaHierarchy_Columns + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Columns); + } + } + + public static string SchemaHierarchy_Constraints + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Constraints); + } + } + + public static string SchemaHierarchy_Contracts + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Contracts); + } + } + + public static string SchemaHierarchy_Credentials + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Credentials); + } + } + + public static string SchemaHierarchy_ErrorMessages + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ErrorMessages); + } + } + + public static string SchemaHierarchy_ServerRoleMembership + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerRoleMembership); + } + } + + public static string SchemaHierarchy_DatabaseOptions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseOptions); + } + } + + public static string SchemaHierarchy_DatabaseRoles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseRoles); + } + } + + public static string SchemaHierarchy_RoleMemberships + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_RoleMemberships); + } + } + + public static string SchemaHierarchy_DatabaseTriggers + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseTriggers); + } + } + + public static string SchemaHierarchy_DefaultConstraints + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DefaultConstraints); + } + } + + public static string SchemaHierarchy_Defaults + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Defaults); + } + } + + public static string SchemaHierarchy_Sequences + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Sequences); + } + } + + public static string SchemaHierarchy_Endpoints + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Endpoints); + } + } + + public static string SchemaHierarchy_EventNotifications + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_EventNotifications); + } + } + + public static string SchemaHierarchy_ServerEventNotifications + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerEventNotifications); + } + } + + public static string SchemaHierarchy_ExtendedProperties + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExtendedProperties); + } + } + + public static string SchemaHierarchy_FileGroups + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FileGroups); + } + } + + public static string SchemaHierarchy_ForeignKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ForeignKeys); + } + } + + public static string SchemaHierarchy_FullTextCatalogs + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FullTextCatalogs); + } + } + + public static string SchemaHierarchy_FullTextIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FullTextIndexes); + } + } + + public static string SchemaHierarchy_Functions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Functions); + } + } + + public static string SchemaHierarchy_Indexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Indexes); + } + } + + public static string SchemaHierarchy_InlineFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_InlineFunctions); + } + } + + public static string SchemaHierarchy_Keys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Keys); + } + } + + public static string SchemaHierarchy_LinkedServers + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_LinkedServers); + } + } + + public static string SchemaHierarchy_LinkedServerLogins + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_LinkedServerLogins); + } + } + + public static string SchemaHierarchy_Logins + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Logins); + } + } + + public static string SchemaHierarchy_MasterKey + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_MasterKey); + } + } + + public static string SchemaHierarchy_MasterKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_MasterKeys); + } + } + + public static string SchemaHierarchy_MessageTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_MessageTypes); + } + } + + public static string SchemaHierarchy_MultiSelectFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_MultiSelectFunctions); + } + } + + public static string SchemaHierarchy_Parameters + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Parameters); + } + } + + public static string SchemaHierarchy_PartitionFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_PartitionFunctions); + } + } + + public static string SchemaHierarchy_PartitionSchemes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_PartitionSchemes); + } + } + + public static string SchemaHierarchy_Permissions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Permissions); + } + } + + public static string SchemaHierarchy_PrimaryKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_PrimaryKeys); + } + } + + public static string SchemaHierarchy_Programmability + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Programmability); + } + } + + public static string SchemaHierarchy_Queues + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Queues); + } + } + + public static string SchemaHierarchy_RemoteServiceBindings + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_RemoteServiceBindings); + } + } + + public static string SchemaHierarchy_ReturnedColumns + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ReturnedColumns); + } + } + + public static string SchemaHierarchy_Roles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Roles); + } + } + + public static string SchemaHierarchy_Routes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Routes); + } + } + + public static string SchemaHierarchy_Rules + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Rules); + } + } + + public static string SchemaHierarchy_Schemas + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Schemas); + } + } + + public static string SchemaHierarchy_Security + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Security); + } + } + + public static string SchemaHierarchy_ServerObjects + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerObjects); + } + } + + public static string SchemaHierarchy_Management + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Management); + } + } + + public static string SchemaHierarchy_ServerTriggers + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerTriggers); + } + } + + public static string SchemaHierarchy_ServiceBroker + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServiceBroker); + } + } + + public static string SchemaHierarchy_Services + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Services); + } + } + + public static string SchemaHierarchy_Signatures + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Signatures); + } + } + + public static string SchemaHierarchy_LogFiles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_LogFiles); + } + } + + public static string SchemaHierarchy_Statistics + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Statistics); + } + } + + public static string SchemaHierarchy_Storage + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Storage); + } + } + + public static string SchemaHierarchy_StoredProcedures + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_StoredProcedures); + } + } + + public static string SchemaHierarchy_SymmetricKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SymmetricKeys); + } + } + + public static string SchemaHierarchy_Synonyms + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Synonyms); + } + } + + public static string SchemaHierarchy_Tables + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Tables); + } + } + + public static string SchemaHierarchy_Triggers + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Triggers); + } + } + + public static string SchemaHierarchy_Types + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Types); + } + } + + public static string SchemaHierarchy_UniqueKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UniqueKeys); + } + } + + public static string SchemaHierarchy_UserDefinedDataTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UserDefinedDataTypes); + } + } + + public static string SchemaHierarchy_UserDefinedTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UserDefinedTypes); + } + } + + public static string SchemaHierarchy_Users + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Users); + } + } + + public static string SchemaHierarchy_Views + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Views); + } + } + + public static string SchemaHierarchy_XmlIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_XmlIndexes); + } + } + + public static string SchemaHierarchy_XMLSchemaCollections + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_XMLSchemaCollections); + } + } + + public static string SchemaHierarchy_UserDefinedTableTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UserDefinedTableTypes); + } + } + + public static string SchemaHierarchy_FilegroupFiles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FilegroupFiles); + } + } + + public static string MissingCaption + { + get + { + return Keys.GetString(Keys.MissingCaption); + } + } + + public static string SchemaHierarchy_BrokerPriorities + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_BrokerPriorities); + } + } + + public static string SchemaHierarchy_CryptographicProviders + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_CryptographicProviders); + } + } + + public static string SchemaHierarchy_DatabaseAuditSpecifications + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseAuditSpecifications); + } + } + + public static string SchemaHierarchy_DatabaseEncryptionKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseEncryptionKeys); + } + } + + public static string SchemaHierarchy_EventSessions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_EventSessions); + } + } + + public static string SchemaHierarchy_FullTextStopLists + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_FullTextStopLists); + } + } + + public static string SchemaHierarchy_ResourcePools + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ResourcePools); + } + } + + public static string SchemaHierarchy_ServerAudits + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerAudits); + } + } + + public static string SchemaHierarchy_ServerAuditSpecifications + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerAuditSpecifications); + } + } + + public static string SchemaHierarchy_SpatialIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SpatialIndexes); + } + } + + public static string SchemaHierarchy_WorkloadGroups + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_WorkloadGroups); + } + } + + public static string SchemaHierarchy_SqlFiles + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SqlFiles); + } + } + + public static string SchemaHierarchy_ServerFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerFunctions); + } + } + + public static string SchemaHierarchy_SqlType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SqlType); + } + } + + public static string SchemaHierarchy_ServerOptions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerOptions); + } + } + + public static string SchemaHierarchy_DatabaseDiagrams + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseDiagrams); + } + } + + public static string SchemaHierarchy_SystemTables + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemTables); + } + } + + public static string SchemaHierarchy_Databases + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Databases); + } + } + + public static string SchemaHierarchy_SystemContracts + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemContracts); + } + } + + public static string SchemaHierarchy_SystemDatabases + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemDatabases); + } + } + + public static string SchemaHierarchy_SystemMessageTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemMessageTypes); + } + } + + public static string SchemaHierarchy_SystemQueues + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemQueues); + } + } + + public static string SchemaHierarchy_SystemServices + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemServices); + } + } + + public static string SchemaHierarchy_SystemStoredProcedures + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemStoredProcedures); + } + } + + public static string SchemaHierarchy_SystemViews + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemViews); + } + } + + public static string SchemaHierarchy_DataTierApplications + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DataTierApplications); + } + } + + public static string SchemaHierarchy_ExtendedStoredProcedures + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExtendedStoredProcedures); + } + } + + public static string SchemaHierarchy_SystemAggregateFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemAggregateFunctions); + } + } + + public static string SchemaHierarchy_SystemApproximateNumerics + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemApproximateNumerics); + } + } + + public static string SchemaHierarchy_SystemBinaryStrings + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemBinaryStrings); + } + } + + public static string SchemaHierarchy_SystemCharacterStrings + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemCharacterStrings); + } + } + + public static string SchemaHierarchy_SystemCLRDataTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemCLRDataTypes); + } + } + + public static string SchemaHierarchy_SystemConfigurationFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemConfigurationFunctions); + } + } + + public static string SchemaHierarchy_SystemCursorFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemCursorFunctions); + } + } + + public static string SchemaHierarchy_SystemDataTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemDataTypes); + } + } + + public static string SchemaHierarchy_SystemDateAndTime + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemDateAndTime); + } + } + + public static string SchemaHierarchy_SystemDateAndTimeFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemDateAndTimeFunctions); + } + } + + public static string SchemaHierarchy_SystemExactNumerics + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemExactNumerics); + } + } + + public static string SchemaHierarchy_SystemFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemFunctions); + } + } + + public static string SchemaHierarchy_SystemHierarchyIdFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemHierarchyIdFunctions); + } + } + + public static string SchemaHierarchy_SystemMathematicalFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemMathematicalFunctions); + } + } + + public static string SchemaHierarchy_SystemMetadataFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemMetadataFunctions); + } + } + + public static string SchemaHierarchy_SystemOtherDataTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemOtherDataTypes); + } + } + + public static string SchemaHierarchy_SystemOtherFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemOtherFunctions); + } + } + + public static string SchemaHierarchy_SystemRowsetFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemRowsetFunctions); + } + } + + public static string SchemaHierarchy_SystemSecurityFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemSecurityFunctions); + } + } + + public static string SchemaHierarchy_SystemSpatialDataTypes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemSpatialDataTypes); + } + } + + public static string SchemaHierarchy_SystemStringFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemStringFunctions); + } + } + + public static string SchemaHierarchy_SystemSystemStatisticalFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemSystemStatisticalFunctions); + } + } + + public static string SchemaHierarchy_SystemTextAndImageFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemTextAndImageFunctions); + } + } + + public static string SchemaHierarchy_SystemUnicodeCharacterStrings + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemUnicodeCharacterStrings); + } + } + + public static string SchemaHierarchy_AggregateFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_AggregateFunctions); + } + } + + public static string SchemaHierarchy_ScalarValuedFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ScalarValuedFunctions); + } + } + + public static string SchemaHierarchy_TableValuedFunctions + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_TableValuedFunctions); + } + } + + public static string SchemaHierarchy_SystemExtendedStoredProcedures + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SystemExtendedStoredProcedures); + } + } + + public static string SchemaHierarchy_BuiltInType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_BuiltInType); + } + } + + public static string SchemaHierarchy_BuiltInServerRole + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_BuiltInServerRole); + } + } + + public static string SchemaHierarchy_UserWithPassword + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UserWithPassword); + } + } + + public static string SchemaHierarchy_SearchPropertyList + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SearchPropertyList); + } + } + + public static string SchemaHierarchy_SecurityPolicies + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SecurityPolicies); + } + } + + public static string SchemaHierarchy_SecurityPredicates + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SecurityPredicates); + } + } + + public static string SchemaHierarchy_ServerRole + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ServerRole); + } + } + + public static string SchemaHierarchy_SearchPropertyLists + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SearchPropertyLists); + } + } + + public static string SchemaHierarchy_ColumnStoreIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnStoreIndexes); + } + } + + public static string SchemaHierarchy_TableTypeIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_TableTypeIndexes); + } + } + + public static string SchemaHierarchy_Server + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_Server); + } + } + + public static string SchemaHierarchy_SelectiveXmlIndexes + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SelectiveXmlIndexes); + } + } + + public static string SchemaHierarchy_XmlNamespaces + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_XmlNamespaces); + } + } + + public static string SchemaHierarchy_XmlTypedPromotedPaths + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_XmlTypedPromotedPaths); + } + } + + public static string SchemaHierarchy_SqlTypedPromotedPaths + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SqlTypedPromotedPaths); + } + } + + public static string SchemaHierarchy_DatabaseScopedCredentials + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_DatabaseScopedCredentials); + } + } + + public static string SchemaHierarchy_ExternalDataSources + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExternalDataSources); + } + } + + public static string SchemaHierarchy_ExternalFileFormats + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExternalFileFormats); + } + } + + public static string SchemaHierarchy_ExternalResources + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExternalResources); + } + } + + public static string SchemaHierarchy_ExternalTables + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ExternalTables); + } + } + + public static string SchemaHierarchy_AlwaysEncryptedKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_AlwaysEncryptedKeys); + } + } + + public static string SchemaHierarchy_ColumnMasterKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnMasterKeys); + } + } + + public static string SchemaHierarchy_ColumnEncryptionKeys + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnEncryptionKeys); + } + } + + public static string SchemaHierarchy_SubroutineParameterLabelFormatString + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterLabelFormatString); + } + } + + public static string SchemaHierarchy_SubroutineParameterNoDefaultLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterNoDefaultLabel); + } + } + + public static string SchemaHierarchy_SubroutineParameterInputLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterInputLabel); + } + } + + public static string SchemaHierarchy_SubroutineParameterInputOutputLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterInputOutputLabel); + } + } + + public static string SchemaHierarchy_SubroutineParameterInputReadOnlyLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterInputReadOnlyLabel); + } + } + + public static string SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel); + } + } + + public static string SchemaHierarchy_SubroutineParameterDefaultLabel + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_SubroutineParameterDefaultLabel); + } + } + + public static string SchemaHierarchy_NullColumn_Label + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_NullColumn_Label); + } + } + + public static string SchemaHierarchy_NotNullColumn_Label + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_NotNullColumn_Label); + } + } + + public static string SchemaHierarchy_UDDTLabelWithType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UDDTLabelWithType); + } + } + + public static string SchemaHierarchy_UDDTLabelWithoutType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_UDDTLabelWithoutType); + } + } + + public static string SchemaHierarchy_ComputedColumnLabelWithType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ComputedColumnLabelWithType); + } + } + + public static string SchemaHierarchy_ComputedColumnLabelWithoutType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ComputedColumnLabelWithoutType); + } + } + + public static string SchemaHierarchy_ColumnSetLabelWithoutType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnSetLabelWithoutType); + } + } + + public static string SchemaHierarchy_ColumnSetLabelWithType + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnSetLabelWithType); + } + } + + public static string SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString + { + get + { + return Keys.GetString(Keys.SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString); + } + } + + public static string UniqueIndex_LabelPart + { + get + { + return Keys.GetString(Keys.UniqueIndex_LabelPart); + } + } + + public static string NonUniqueIndex_LabelPart + { + get + { + return Keys.GetString(Keys.NonUniqueIndex_LabelPart); + } + } + + public static string ClusteredIndex_LabelPart + { + get + { + return Keys.GetString(Keys.ClusteredIndex_LabelPart); + } + } + + public static string NonClusteredIndex_LabelPart + { + get + { + return Keys.GetString(Keys.NonClusteredIndex_LabelPart); + } + } + + public static string History_LabelPart + { + get + { + return Keys.GetString(Keys.History_LabelPart); + } + } + + public static string SystemVersioned_LabelPart + { + get + { + return Keys.GetString(Keys.SystemVersioned_LabelPart); + } + } + + public static string External_LabelPart + { + get + { + return Keys.GetString(Keys.External_LabelPart); + } + } + + public static string FileTable_LabelPart + { + get + { + return Keys.GetString(Keys.FileTable_LabelPart); + } + } + + public static string DatabaseNotAccessible + { + get + { + return Keys.GetString(Keys.DatabaseNotAccessible); + } + } + + public static string ScriptingParams_ConnectionString_Property_Invalid + { + get + { + return Keys.GetString(Keys.ScriptingParams_ConnectionString_Property_Invalid); + } + } + + public static string ScriptingParams_FilePath_Property_Invalid + { + get + { + return Keys.GetString(Keys.ScriptingParams_FilePath_Property_Invalid); + } + } + + public static string ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid + { + get + { + return Keys.GetString(Keys.ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid); + } + } + + public static string StoredProcedureScriptParameterComment + { + get + { + return Keys.GetString(Keys.StoredProcedureScriptParameterComment); + } + } + + public static string ScriptingGeneralError + { + get + { + return Keys.GetString(Keys.ScriptingGeneralError); + } + } + + public static string ScriptingExecuteNotSupportedError + { + get + { + return Keys.GetString(Keys.ScriptingExecuteNotSupportedError); + } + } + + public static string BackupTaskName + { + get + { + return Keys.GetString(Keys.BackupTaskName); + } + } + + public static string BackupPathIsFolderError + { + get + { + return Keys.GetString(Keys.BackupPathIsFolderError); + } + } + + public static string InvalidBackupPathError + { + get + { + return Keys.GetString(Keys.InvalidBackupPathError); + } + } + + public static string TaskInProgress + { + get + { + return Keys.GetString(Keys.TaskInProgress); + } + } + + public static string TaskCompleted + { + get + { + return Keys.GetString(Keys.TaskCompleted); + } + } + + public static string ConflictWithNoRecovery + { + get + { + return Keys.GetString(Keys.ConflictWithNoRecovery); + } + } + + public static string InvalidPathForDatabaseFile + { + get + { + return Keys.GetString(Keys.InvalidPathForDatabaseFile); + } + } + + public static string Log + { + get + { + return Keys.GetString(Keys.Log); + } + } + + public static string RestorePlanFailed + { + get + { + return Keys.GetString(Keys.RestorePlanFailed); + } + } + + public static string RestoreNotSupported + { + get + { + return Keys.GetString(Keys.RestoreNotSupported); + } + } + + public static string RestoreTaskName + { + get + { + return Keys.GetString(Keys.RestoreTaskName); + } + } + + public static string RestoreCopyOnly + { + get + { + return Keys.GetString(Keys.RestoreCopyOnly); + } + } + + public static string RestoreBackupSetComponent + { + get + { + return Keys.GetString(Keys.RestoreBackupSetComponent); + } + } + + public static string RestoreBackupSetName + { + get + { + return Keys.GetString(Keys.RestoreBackupSetName); + } + } + + public static string RestoreBackupSetType + { + get + { + return Keys.GetString(Keys.RestoreBackupSetType); + } + } + + public static string RestoreBackupSetServer + { + get + { + return Keys.GetString(Keys.RestoreBackupSetServer); + } + } + + public static string RestoreBackupSetDatabase + { + get + { + return Keys.GetString(Keys.RestoreBackupSetDatabase); + } + } + + public static string RestoreBackupSetPosition + { + get + { + return Keys.GetString(Keys.RestoreBackupSetPosition); + } + } + + public static string RestoreBackupSetFirstLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFirstLsn); + } + } + + public static string RestoreBackupSetLastLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetLastLsn); + } + } + + public static string RestoreBackupSetCheckpointLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetCheckpointLsn); + } + } + + public static string RestoreBackupSetFullLsn + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFullLsn); + } + } + + public static string RestoreBackupSetStartDate + { + get + { + return Keys.GetString(Keys.RestoreBackupSetStartDate); + } + } + + public static string RestoreBackupSetFinishDate + { + get + { + return Keys.GetString(Keys.RestoreBackupSetFinishDate); + } + } + + public static string RestoreBackupSetSize + { + get + { + return Keys.GetString(Keys.RestoreBackupSetSize); + } + } + + public static string RestoreBackupSetUserName + { + get + { + return Keys.GetString(Keys.RestoreBackupSetUserName); + } + } + + public static string RestoreBackupSetExpiration + { + get + { + return Keys.GetString(Keys.RestoreBackupSetExpiration); + } + } + + public static string TheLastBackupTaken + { + get + { + return Keys.GetString(Keys.TheLastBackupTaken); + } + } + + public static string NoBackupsetsToRestore + { + get + { + return Keys.GetString(Keys.NoBackupsetsToRestore); + } + } + + public static string ScriptTaskName + { + get + { + return Keys.GetString(Keys.ScriptTaskName); + } + } + + public static string InvalidPathError + { + get + { + return Keys.GetString(Keys.InvalidPathError); + } + } + + public static string ProfilerConnectionNotFound + { + get + { + return Keys.GetString(Keys.ProfilerConnectionNotFound); + } + } + + public static string AzureSystemDbProfilingError + { + get + { + return Keys.GetString(Keys.AzureSystemDbProfilingError); + } + } + + public static string SessionNotFound + { + get + { + return Keys.GetString(Keys.SessionNotFound); + } + } + + public static string CategoryLocal + { + get + { + return Keys.GetString(Keys.CategoryLocal); + } + } + + public static string CategoryFromMsx + { + get + { + return Keys.GetString(Keys.CategoryFromMsx); + } + } + + public static string CategoryMultiServer + { + get + { + return Keys.GetString(Keys.CategoryMultiServer); + } + } + + public static string CategoryDBMaint + { + get + { + return Keys.GetString(Keys.CategoryDBMaint); + } + } + + public static string CategoryWebAssistant + { + get + { + return Keys.GetString(Keys.CategoryWebAssistant); + } + } + + public static string CategoryFullText + { + get + { + return Keys.GetString(Keys.CategoryFullText); + } + } + + public static string CategoryReplDistribution + { + get + { + return Keys.GetString(Keys.CategoryReplDistribution); + } + } + + public static string CategoryReplDistributionCleanup + { + get + { + return Keys.GetString(Keys.CategoryReplDistributionCleanup); + } + } + + public static string CategoryReplHistoryCleanup + { + get + { + return Keys.GetString(Keys.CategoryReplHistoryCleanup); + } + } + + public static string CategoryReplLogReader + { + get + { + return Keys.GetString(Keys.CategoryReplLogReader); + } + } + + public static string CategoryReplMerge + { + get + { + return Keys.GetString(Keys.CategoryReplMerge); + } + } + + public static string CategoryReplSnapShot + { + get + { + return Keys.GetString(Keys.CategoryReplSnapShot); + } + } + + public static string CategoryReplCheckup + { + get + { + return Keys.GetString(Keys.CategoryReplCheckup); + } + } + + public static string CategoryReplCleanup + { + get + { + return Keys.GetString(Keys.CategoryReplCleanup); + } + } + + public static string CategoryReplAlert + { + get + { + return Keys.GetString(Keys.CategoryReplAlert); + } + } + + public static string CategoryReplQReader + { + get + { + return Keys.GetString(Keys.CategoryReplQReader); + } + } + + public static string CategoryReplication + { + get + { + return Keys.GetString(Keys.CategoryReplication); + } + } + + public static string CategoryUncategorized + { + get + { + return Keys.GetString(Keys.CategoryUncategorized); + } + } + + public static string CategoryLogShipping + { + get + { + return Keys.GetString(Keys.CategoryLogShipping); + } + } + + public static string CategoryDBEngineTuningAdvisor + { + get + { + return Keys.GetString(Keys.CategoryDBEngineTuningAdvisor); + } + } + + public static string CategoryDataCollector + { + get + { + return Keys.GetString(Keys.CategoryDataCollector); + } + } + + public static string UnexpectedRunType + { + get + { + return Keys.GetString(Keys.UnexpectedRunType); + } + } + + public static string CredentialNoLongerExists + { + get + { + return Keys.GetString(Keys.CredentialNoLongerExists); + } + } + + public static string TargetServerNotSelected + { + get + { + return Keys.GetString(Keys.TargetServerNotSelected); + } + } + + public static string SysadminAccount + { + get + { + return Keys.GetString(Keys.SysadminAccount); + } + } + + public static string JobStepNameCannotBeBlank + { + get + { + return Keys.GetString(Keys.JobStepNameCannotBeBlank); + } + } + + public static string AlertNameCannotBeBlank + { + get + { + return Keys.GetString(Keys.AlertNameCannotBeBlank); + } + } + + public static string CannotCreateNewAlert + { + get + { + return Keys.GetString(Keys.CannotCreateNewAlert); + } + } + + public static string CannotAlterAlert + { + get + { + return Keys.GetString(Keys.CannotAlterAlert); + } + } + + public static string InvalidScheduleTitle + { + get + { + return Keys.GetString(Keys.InvalidScheduleTitle); + } + } + + public static string InvalidWeeklySchedule + { + get + { + return Keys.GetString(Keys.InvalidWeeklySchedule); + } + } + + public static string StartDateGreaterThanEndDate + { + get + { + return Keys.GetString(Keys.StartDateGreaterThanEndDate); + } + } + + public static string StartTimeGreaterThanEndTime + { + get + { + return Keys.GetString(Keys.StartTimeGreaterThanEndTime); + } + } + + public static string EndTimeEqualToStartTime + { + get + { + return Keys.GetString(Keys.EndTimeEqualToStartTime); + } + } + + public static string InvalidStartDate + { + get + { + return Keys.GetString(Keys.InvalidStartDate); + } + } + + public static string JobServerIsNotAvailable + { + get + { + return Keys.GetString(Keys.JobServerIsNotAvailable); + } + } + + public static string NeverBackedUp + { + get + { + return Keys.GetString(Keys.NeverBackedUp); + } + } + + public static string Error_InvalidDirectoryName + { + get + { + return Keys.GetString(Keys.Error_InvalidDirectoryName); + } + } + + public static string Error_ExistingDirectoryName + { + get + { + return Keys.GetString(Keys.Error_ExistingDirectoryName); + } + } + + public static string ExportBacpacTaskName + { + get + { + return Keys.GetString(Keys.ExportBacpacTaskName); + } + } + + public static string ImportBacpacTaskName + { + get + { + return Keys.GetString(Keys.ImportBacpacTaskName); + } + } + + public static string ExtractDacpacTaskName + { + get + { + return Keys.GetString(Keys.ExtractDacpacTaskName); + } + } + + public static string DeployDacpacTaskName + { + get + { + return Keys.GetString(Keys.DeployDacpacTaskName); + } + } + + public static string GenerateScriptTaskName + { + get + { + return Keys.GetString(Keys.GenerateScriptTaskName); + } + } + + public static string ExtractInvalidVersion + { + get + { + return Keys.GetString(Keys.ExtractInvalidVersion); + } + } + + public static string PublishChangesTaskName + { + get + { + return Keys.GetString(Keys.PublishChangesTaskName); + } + } + + public static string SchemaCompareExcludeIncludeNodeNotFound + { + get + { + return Keys.GetString(Keys.SchemaCompareExcludeIncludeNodeNotFound); + } + } + + public static string OpenScmpConnectionBasedModelParsingError + { + get + { + return Keys.GetString(Keys.OpenScmpConnectionBasedModelParsingError); + } + } + + public static string SchemaCompareSessionNotFound + { + get + { + return Keys.GetString(Keys.SchemaCompareSessionNotFound); + } + } + + public static string ConnectionServiceListDbErrorNotConnected(string uri) + { + return Keys.GetString(Keys.ConnectionServiceListDbErrorNotConnected, uri); + } + + public static string ConnectionServiceDbErrorDefaultNotConnected(string uri) + { + return Keys.GetString(Keys.ConnectionServiceDbErrorDefaultNotConnected, uri); + } + + public static string ConnectionServiceConnStringInvalidAuthType(string authType) + { + return Keys.GetString(Keys.ConnectionServiceConnStringInvalidAuthType, authType); + } + + public static string ConnectionServiceConnStringInvalidIntent(string intent) + { + return Keys.GetString(Keys.ConnectionServiceConnStringInvalidIntent, intent); + } + + public static string ConnectionParamsValidateNullSqlAuth(string component) + { + return Keys.GetString(Keys.ConnectionParamsValidateNullSqlAuth, component); + } + + public static string QueryServiceAffectedRows(long rows) + { + return Keys.GetString(Keys.QueryServiceAffectedRows, rows); + } + + public static string QueryServiceErrorFormat(int msg, int lvl, int state, int line, string newLine, string message) + { + return Keys.GetString(Keys.QueryServiceErrorFormat, msg, lvl, state, line, newLine, message); + } + + public static string QueryServiceQueryFailed(string message) + { + return Keys.GetString(Keys.QueryServiceQueryFailed, message); + } + + public static string QueryServiceSaveAsFail(string fileName, string message) + { + return Keys.GetString(Keys.QueryServiceSaveAsFail, fileName, message); + } + + public static string SerializationServiceUnsupportedFormat(string formatName) + { + return Keys.GetString(Keys.SerializationServiceUnsupportedFormat, formatName); + } + + public static string SerializationServiceRequestInProgress(string filePath) + { + return Keys.GetString(Keys.SerializationServiceRequestInProgress, filePath); + } + + public static string SerializationServiceRequestNotFound(string filePath) + { + return Keys.GetString(Keys.SerializationServiceRequestNotFound, filePath); + } + + public static string PeekDefinitionAzureError(string errorMessage) + { + return Keys.GetString(Keys.PeekDefinitionAzureError, errorMessage); + } + + public static string PeekDefinitionError(string errorMessage) + { + return Keys.GetString(Keys.PeekDefinitionError, errorMessage); + } + + public static string WorkspaceServicePositionColumnOutOfRange(int line) + { + return Keys.GetString(Keys.WorkspaceServicePositionColumnOutOfRange, line); + } + + public static string WorkspaceServiceBufferPositionOutOfOrder(int sLine, int sCol, int eLine, int eCol) + { + return Keys.GetString(Keys.WorkspaceServiceBufferPositionOutOfOrder, sLine, sCol, eLine, eCol); + } + + public static string EditDataUnsupportedObjectType(string typeName) + { + return Keys.GetString(Keys.EditDataUnsupportedObjectType, typeName); + } + + public static string EditDataInvalidFormat(string colName, string colType) + { + return Keys.GetString(Keys.EditDataInvalidFormat, colName, colType); + } + + public static string EditDataCreateScriptMissingValue(string colName) + { + return Keys.GetString(Keys.EditDataCreateScriptMissingValue, colName); + } + + public static string EditDataValueTooLarge(string value, string columnType) + { + return Keys.GetString(Keys.EditDataValueTooLarge, value, columnType); + } + + public static string EditDataIncorrectTable(string tableName) + { + return Keys.GetString(Keys.EditDataIncorrectTable, tableName); + } + + public static string CreateSessionFailed(String error) + { + return Keys.GetString(Keys.CreateSessionFailed, error); + } + + public static string StartSessionFailed(String error) + { + return Keys.GetString(Keys.StartSessionFailed, error); + } + + public static string PauseSessionFailed(String error) + { + return Keys.GetString(Keys.PauseSessionFailed, error); + } + + public static string StopSessionFailed(String error) + { + return Keys.GetString(Keys.StopSessionFailed, error); + } + + public static string SessionAlreadyExists(String sessionName) + { + return Keys.GetString(Keys.SessionAlreadyExists, sessionName); + } + + public static string UnknownSizeUnit(string unit) + { + return Keys.GetString(Keys.UnknownSizeUnit, unit); + } + + public static string UnknownServerType(string serverTypeName) + { + return Keys.GetString(Keys.UnknownServerType, serverTypeName); + } + + public static string SetOwnerFailed(string ownerName) + { + return Keys.GetString(Keys.SetOwnerFailed, ownerName); + } + + public static string ProxyAccountNotFound(string proxyName) + { + return Keys.GetString(Keys.ProxyAccountNotFound, proxyName); + } + + public static string JobAlreadyExists(string jobName) + { + return Keys.GetString(Keys.JobAlreadyExists, jobName); + } + + public static string JobStepNameAlreadyExists(string jobName) + { + return Keys.GetString(Keys.JobStepNameAlreadyExists, jobName); + } + + public static string ScheduleNameAlreadyExists(string scheduleName) + { + return Keys.GetString(Keys.ScheduleNameAlreadyExists, scheduleName); + } + + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Keys + { + static ResourceManager resourceManager = new ResourceManager("Microsoft.Kusto.ServiceLayer.Localization.SR", typeof(SR).GetTypeInfo().Assembly); + + static CultureInfo _culture = null; + + + public const string ConnectionServiceConnectErrorNullParams = "ConnectionServiceConnectErrorNullParams"; + + + public const string ConnectionServiceListDbErrorNullOwnerUri = "ConnectionServiceListDbErrorNullOwnerUri"; + + + public const string ConnectionServiceListDbErrorNotConnected = "ConnectionServiceListDbErrorNotConnected"; + + + public const string ConnectionServiceDbErrorDefaultNotConnected = "ConnectionServiceDbErrorDefaultNotConnected"; + + + public const string ConnectionServiceConnStringInvalidAuthType = "ConnectionServiceConnStringInvalidAuthType"; + + + public const string ConnectionServiceConnStringInvalidIntent = "ConnectionServiceConnStringInvalidIntent"; + + + public const string ConnectionServiceConnectionCanceled = "ConnectionServiceConnectionCanceled"; + + + public const string ConnectionParamsValidateNullOwnerUri = "ConnectionParamsValidateNullOwnerUri"; + + + public const string ConnectionParamsValidateNullConnection = "ConnectionParamsValidateNullConnection"; + + + public const string ConnectionParamsValidateNullServerName = "ConnectionParamsValidateNullServerName"; + + + public const string ConnectionParamsValidateNullSqlAuth = "ConnectionParamsValidateNullSqlAuth"; + + + public const string AzureSqlDbEdition = "AzureSqlDbEdition"; + + + public const string AzureSqlDwEdition = "AzureSqlDwEdition"; + + + public const string AzureSqlStretchEdition = "AzureSqlStretchEdition"; + + + public const string QueryServiceCancelAlreadyCompleted = "QueryServiceCancelAlreadyCompleted"; + + + public const string QueryServiceCancelDisposeFailed = "QueryServiceCancelDisposeFailed"; + + + public const string QueryServiceQueryCancelled = "QueryServiceQueryCancelled"; + + + public const string QueryServiceSubsetBatchNotCompleted = "QueryServiceSubsetBatchNotCompleted"; + + + public const string QueryServiceSubsetBatchOutOfRange = "QueryServiceSubsetBatchOutOfRange"; + + + public const string QueryServiceSubsetResultSetOutOfRange = "QueryServiceSubsetResultSetOutOfRange"; + + + public const string QueryServiceDataReaderByteCountInvalid = "QueryServiceDataReaderByteCountInvalid"; + + + public const string QueryServiceDataReaderCharCountInvalid = "QueryServiceDataReaderCharCountInvalid"; + + + public const string QueryServiceDataReaderXmlCountInvalid = "QueryServiceDataReaderXmlCountInvalid"; + + + public const string QueryServiceFileWrapperWriteOnly = "QueryServiceFileWrapperWriteOnly"; + + + public const string QueryServiceFileWrapperNotInitialized = "QueryServiceFileWrapperNotInitialized"; + + + public const string QueryServiceFileWrapperReadOnly = "QueryServiceFileWrapperReadOnly"; + + + public const string QueryServiceAffectedOneRow = "QueryServiceAffectedOneRow"; + + + public const string QueryServiceAffectedRows = "QueryServiceAffectedRows"; + + + public const string QueryServiceCompletedSuccessfully = "QueryServiceCompletedSuccessfully"; + + + public const string QueryServiceErrorFormat = "QueryServiceErrorFormat"; + + + public const string QueryServiceQueryFailed = "QueryServiceQueryFailed"; + + + public const string QueryServiceColumnNull = "QueryServiceColumnNull"; + + + public const string QueryServiceCellNull = "QueryServiceCellNull"; + + + public const string QueryServiceRequestsNoQuery = "QueryServiceRequestsNoQuery"; + + + public const string QueryServiceQueryInvalidOwnerUri = "QueryServiceQueryInvalidOwnerUri"; + + + public const string QueryServiceQueryInProgress = "QueryServiceQueryInProgress"; + + + public const string QueryServiceMessageSenderNotSql = "QueryServiceMessageSenderNotSql"; + + + public const string QueryServiceResultSetAddNoRows = "QueryServiceResultSetAddNoRows"; + + + public const string QueryServiceResultSetHasNoResults = "QueryServiceResultSetHasNoResults"; + + + public const string QueryServiceResultSetTooLarge = "QueryServiceResultSetTooLarge"; + + + public const string QueryServiceSaveAsResultSetNotComplete = "QueryServiceSaveAsResultSetNotComplete"; + + + public const string QueryServiceSaveAsMiscStartingError = "QueryServiceSaveAsMiscStartingError"; + + + public const string QueryServiceSaveAsInProgress = "QueryServiceSaveAsInProgress"; + + + public const string QueryServiceSaveAsFail = "QueryServiceSaveAsFail"; + + + public const string QueryServiceResultSetNotRead = "QueryServiceResultSetNotRead"; + + + public const string QueryServiceResultSetStartRowOutOfRange = "QueryServiceResultSetStartRowOutOfRange"; + + + public const string QueryServiceResultSetRowCountOutOfRange = "QueryServiceResultSetRowCountOutOfRange"; + + + public const string QueryServiceResultSetNoColumnSchema = "QueryServiceResultSetNoColumnSchema"; + + + public const string QueryServiceExecutionPlanNotFound = "QueryServiceExecutionPlanNotFound"; + + + public const string SerializationServiceUnsupportedFormat = "SerializationServiceUnsupportedFormat"; + + + public const string SerializationServiceRequestInProgress = "SerializationServiceRequestInProgress"; + + + public const string SerializationServiceRequestNotFound = "SerializationServiceRequestNotFound"; + + + public const string PeekDefinitionAzureError = "PeekDefinitionAzureError"; + + + public const string PeekDefinitionError = "PeekDefinitionError"; + + + public const string PeekDefinitionNoResultsError = "PeekDefinitionNoResultsError"; + + + public const string PeekDefinitionDatabaseError = "PeekDefinitionDatabaseError"; + + + public const string PeekDefinitionNotConnectedError = "PeekDefinitionNotConnectedError"; + + + public const string PeekDefinitionTimedoutError = "PeekDefinitionTimedoutError"; + + + public const string PeekDefinitionTypeNotSupportedError = "PeekDefinitionTypeNotSupportedError"; + + + public const string ErrorEmptyStringReplacement = "ErrorEmptyStringReplacement"; + + + public const string WorkspaceServicePositionLineOutOfRange = "WorkspaceServicePositionLineOutOfRange"; + + + public const string WorkspaceServicePositionColumnOutOfRange = "WorkspaceServicePositionColumnOutOfRange"; + + + public const string WorkspaceServiceBufferPositionOutOfOrder = "WorkspaceServiceBufferPositionOutOfOrder"; + + + public const string EditDataObjectNotFound = "EditDataObjectNotFound"; + + + public const string EditDataSessionNotFound = "EditDataSessionNotFound"; + + + public const string EditDataSessionAlreadyExists = "EditDataSessionAlreadyExists"; + + + public const string EditDataSessionNotInitialized = "EditDataSessionNotInitialized"; + + + public const string EditDataSessionAlreadyInitialized = "EditDataSessionAlreadyInitialized"; + + + public const string EditDataSessionAlreadyInitializing = "EditDataSessionAlreadyInitializing"; + + + public const string EditDataMetadataNotExtended = "EditDataMetadataNotExtended"; + + + public const string EditDataMetadataObjectNameRequired = "EditDataMetadataObjectNameRequired"; + + + public const string EditDataMetadataTooManyIdentifiers = "EditDataMetadataTooManyIdentifiers"; + + + public const string EditDataFilteringNegativeLimit = "EditDataFilteringNegativeLimit"; + + + public const string EditDataUnsupportedObjectType = "EditDataUnsupportedObjectType"; + + + public const string EditDataQueryFailed = "EditDataQueryFailed"; + + + public const string EditDataQueryNotCompleted = "EditDataQueryNotCompleted"; + + + public const string EditDataQueryImproperResultSets = "EditDataQueryImproperResultSets"; + + + public const string EditDataFailedAddRow = "EditDataFailedAddRow"; + + + public const string EditDataRowOutOfRange = "EditDataRowOutOfRange"; + + + public const string EditDataUpdatePending = "EditDataUpdatePending"; + + + public const string EditDataUpdateNotPending = "EditDataUpdateNotPending"; + + + public const string EditDataObjectMetadataNotFound = "EditDataObjectMetadataNotFound"; + + + public const string EditDataInvalidFormat = "EditDataInvalidFormat"; + + + public const string EditDataInvalidFormatBinary = "EditDataInvalidFormatBinary"; + + + public const string EditDataInvalidFormatBoolean = "EditDataInvalidFormatBoolean"; + + + public const string EditDataCreateScriptMissingValue = "EditDataCreateScriptMissingValue"; + + + public const string EditDataDeleteSetCell = "EditDataDeleteSetCell"; + + + public const string EditDataColumnIdOutOfRange = "EditDataColumnIdOutOfRange"; + + + public const string EditDataColumnCannotBeEdited = "EditDataColumnCannotBeEdited"; + + + public const string EditDataColumnNoKeyColumns = "EditDataColumnNoKeyColumns"; + + + public const string EditDataScriptFilePathNull = "EditDataScriptFilePathNull"; + + + public const string EditDataCommitInProgress = "EditDataCommitInProgress"; + + + public const string EditDataComputedColumnPlaceholder = "EditDataComputedColumnPlaceholder"; + + + public const string EditDataTimeOver24Hrs = "EditDataTimeOver24Hrs"; + + + public const string EditDataNullNotAllowed = "EditDataNullNotAllowed"; + + + public const string EditDataValueTooLarge = "EditDataValueTooLarge"; + + + public const string EditDataMultiTableNotSupported = "EditDataMultiTableNotSupported"; + + + public const string EditDataAliasesNotSupported = "EditDataAliasesNotSupported"; + + + public const string EditDataExpressionsNotSupported = "EditDataExpressionsNotSupported"; + + + public const string EditDataDuplicateColumnsNotSupported = "EditDataDuplicateColumnsNotSupported"; + + + public const string EditDataIncorrectTable = "EditDataIncorrectTable"; + + + public const string EE_ExecutionInfo_InitializingLoop = "EE_ExecutionInfo_InitializingLoop"; + + + public const string EE_BatchExecutionError_Ignoring = "EE_BatchExecutionError_Ignoring"; + + + public const string EE_ExecutionInfo_FinalizingLoop = "EE_ExecutionInfo_FinalizingLoop"; + + + public const string BatchParserWrapperExecutionError = "BatchParserWrapperExecutionError"; + + + public const string TestLocalizationConstant = "TestLocalizationConstant"; + + + public const string SqlScriptFormatterDecimalMissingPrecision = "SqlScriptFormatterDecimalMissingPrecision"; + + + public const string SqlScriptFormatterLengthTypeMissingSize = "SqlScriptFormatterLengthTypeMissingSize"; + + + public const string SqlScriptFormatterScalarTypeMissingScale = "SqlScriptFormatterScalarTypeMissingScale"; + + + public const string TreeNodeError = "TreeNodeError"; + + + public const string ServerNodeConnectionError = "ServerNodeConnectionError"; + + + public const string SchemaHierarchy_Aggregates = "SchemaHierarchy_Aggregates"; + + + public const string SchemaHierarchy_ServerRoles = "SchemaHierarchy_ServerRoles"; + + + public const string SchemaHierarchy_ApplicationRoles = "SchemaHierarchy_ApplicationRoles"; + + + public const string SchemaHierarchy_Assemblies = "SchemaHierarchy_Assemblies"; + + + public const string SchemaHierarchy_AssemblyFiles = "SchemaHierarchy_AssemblyFiles"; + + + public const string SchemaHierarchy_AsymmetricKeys = "SchemaHierarchy_AsymmetricKeys"; + + + public const string SchemaHierarchy_DatabaseAsymmetricKeys = "SchemaHierarchy_DatabaseAsymmetricKeys"; + + + public const string SchemaHierarchy_DataCompressionOptions = "SchemaHierarchy_DataCompressionOptions"; + + + public const string SchemaHierarchy_Certificates = "SchemaHierarchy_Certificates"; + + + public const string SchemaHierarchy_FileTables = "SchemaHierarchy_FileTables"; + + + public const string SchemaHierarchy_DatabaseCertificates = "SchemaHierarchy_DatabaseCertificates"; + + + public const string SchemaHierarchy_CheckConstraints = "SchemaHierarchy_CheckConstraints"; + + + public const string SchemaHierarchy_Columns = "SchemaHierarchy_Columns"; + + + public const string SchemaHierarchy_Constraints = "SchemaHierarchy_Constraints"; + + + public const string SchemaHierarchy_Contracts = "SchemaHierarchy_Contracts"; + + + public const string SchemaHierarchy_Credentials = "SchemaHierarchy_Credentials"; + + + public const string SchemaHierarchy_ErrorMessages = "SchemaHierarchy_ErrorMessages"; + + + public const string SchemaHierarchy_ServerRoleMembership = "SchemaHierarchy_ServerRoleMembership"; + + + public const string SchemaHierarchy_DatabaseOptions = "SchemaHierarchy_DatabaseOptions"; + + + public const string SchemaHierarchy_DatabaseRoles = "SchemaHierarchy_DatabaseRoles"; + + + public const string SchemaHierarchy_RoleMemberships = "SchemaHierarchy_RoleMemberships"; + + + public const string SchemaHierarchy_DatabaseTriggers = "SchemaHierarchy_DatabaseTriggers"; + + + public const string SchemaHierarchy_DefaultConstraints = "SchemaHierarchy_DefaultConstraints"; + + + public const string SchemaHierarchy_Defaults = "SchemaHierarchy_Defaults"; + + + public const string SchemaHierarchy_Sequences = "SchemaHierarchy_Sequences"; + + + public const string SchemaHierarchy_Endpoints = "SchemaHierarchy_Endpoints"; + + + public const string SchemaHierarchy_EventNotifications = "SchemaHierarchy_EventNotifications"; + + + public const string SchemaHierarchy_ServerEventNotifications = "SchemaHierarchy_ServerEventNotifications"; + + + public const string SchemaHierarchy_ExtendedProperties = "SchemaHierarchy_ExtendedProperties"; + + + public const string SchemaHierarchy_FileGroups = "SchemaHierarchy_FileGroups"; + + + public const string SchemaHierarchy_ForeignKeys = "SchemaHierarchy_ForeignKeys"; + + + public const string SchemaHierarchy_FullTextCatalogs = "SchemaHierarchy_FullTextCatalogs"; + + + public const string SchemaHierarchy_FullTextIndexes = "SchemaHierarchy_FullTextIndexes"; + + + public const string SchemaHierarchy_Functions = "SchemaHierarchy_Functions"; + + + public const string SchemaHierarchy_Indexes = "SchemaHierarchy_Indexes"; + + + public const string SchemaHierarchy_InlineFunctions = "SchemaHierarchy_InlineFunctions"; + + + public const string SchemaHierarchy_Keys = "SchemaHierarchy_Keys"; + + + public const string SchemaHierarchy_LinkedServers = "SchemaHierarchy_LinkedServers"; + + + public const string SchemaHierarchy_LinkedServerLogins = "SchemaHierarchy_LinkedServerLogins"; + + + public const string SchemaHierarchy_Logins = "SchemaHierarchy_Logins"; + + + public const string SchemaHierarchy_MasterKey = "SchemaHierarchy_MasterKey"; + + + public const string SchemaHierarchy_MasterKeys = "SchemaHierarchy_MasterKeys"; + + + public const string SchemaHierarchy_MessageTypes = "SchemaHierarchy_MessageTypes"; + + + public const string SchemaHierarchy_MultiSelectFunctions = "SchemaHierarchy_MultiSelectFunctions"; + + + public const string SchemaHierarchy_Parameters = "SchemaHierarchy_Parameters"; + + + public const string SchemaHierarchy_PartitionFunctions = "SchemaHierarchy_PartitionFunctions"; + + + public const string SchemaHierarchy_PartitionSchemes = "SchemaHierarchy_PartitionSchemes"; + + + public const string SchemaHierarchy_Permissions = "SchemaHierarchy_Permissions"; + + + public const string SchemaHierarchy_PrimaryKeys = "SchemaHierarchy_PrimaryKeys"; + + + public const string SchemaHierarchy_Programmability = "SchemaHierarchy_Programmability"; + + + public const string SchemaHierarchy_Queues = "SchemaHierarchy_Queues"; + + + public const string SchemaHierarchy_RemoteServiceBindings = "SchemaHierarchy_RemoteServiceBindings"; + + + public const string SchemaHierarchy_ReturnedColumns = "SchemaHierarchy_ReturnedColumns"; + + + public const string SchemaHierarchy_Roles = "SchemaHierarchy_Roles"; + + + public const string SchemaHierarchy_Routes = "SchemaHierarchy_Routes"; + + + public const string SchemaHierarchy_Rules = "SchemaHierarchy_Rules"; + + + public const string SchemaHierarchy_Schemas = "SchemaHierarchy_Schemas"; + + + public const string SchemaHierarchy_Security = "SchemaHierarchy_Security"; + + + public const string SchemaHierarchy_ServerObjects = "SchemaHierarchy_ServerObjects"; + + + public const string SchemaHierarchy_Management = "SchemaHierarchy_Management"; + + + public const string SchemaHierarchy_ServerTriggers = "SchemaHierarchy_ServerTriggers"; + + + public const string SchemaHierarchy_ServiceBroker = "SchemaHierarchy_ServiceBroker"; + + + public const string SchemaHierarchy_Services = "SchemaHierarchy_Services"; + + + public const string SchemaHierarchy_Signatures = "SchemaHierarchy_Signatures"; + + + public const string SchemaHierarchy_LogFiles = "SchemaHierarchy_LogFiles"; + + + public const string SchemaHierarchy_Statistics = "SchemaHierarchy_Statistics"; + + + public const string SchemaHierarchy_Storage = "SchemaHierarchy_Storage"; + + + public const string SchemaHierarchy_StoredProcedures = "SchemaHierarchy_StoredProcedures"; + + + public const string SchemaHierarchy_SymmetricKeys = "SchemaHierarchy_SymmetricKeys"; + + + public const string SchemaHierarchy_Synonyms = "SchemaHierarchy_Synonyms"; + + + public const string SchemaHierarchy_Tables = "SchemaHierarchy_Tables"; + + + public const string SchemaHierarchy_Triggers = "SchemaHierarchy_Triggers"; + + + public const string SchemaHierarchy_Types = "SchemaHierarchy_Types"; + + + public const string SchemaHierarchy_UniqueKeys = "SchemaHierarchy_UniqueKeys"; + + + public const string SchemaHierarchy_UserDefinedDataTypes = "SchemaHierarchy_UserDefinedDataTypes"; + + + public const string SchemaHierarchy_UserDefinedTypes = "SchemaHierarchy_UserDefinedTypes"; + + + public const string SchemaHierarchy_Users = "SchemaHierarchy_Users"; + + + public const string SchemaHierarchy_Views = "SchemaHierarchy_Views"; + + + public const string SchemaHierarchy_XmlIndexes = "SchemaHierarchy_XmlIndexes"; + + + public const string SchemaHierarchy_XMLSchemaCollections = "SchemaHierarchy_XMLSchemaCollections"; + + + public const string SchemaHierarchy_UserDefinedTableTypes = "SchemaHierarchy_UserDefinedTableTypes"; + + + public const string SchemaHierarchy_FilegroupFiles = "SchemaHierarchy_FilegroupFiles"; + + + public const string MissingCaption = "MissingCaption"; + + + public const string SchemaHierarchy_BrokerPriorities = "SchemaHierarchy_BrokerPriorities"; + + + public const string SchemaHierarchy_CryptographicProviders = "SchemaHierarchy_CryptographicProviders"; + + + public const string SchemaHierarchy_DatabaseAuditSpecifications = "SchemaHierarchy_DatabaseAuditSpecifications"; + + + public const string SchemaHierarchy_DatabaseEncryptionKeys = "SchemaHierarchy_DatabaseEncryptionKeys"; + + + public const string SchemaHierarchy_EventSessions = "SchemaHierarchy_EventSessions"; + + + public const string SchemaHierarchy_FullTextStopLists = "SchemaHierarchy_FullTextStopLists"; + + + public const string SchemaHierarchy_ResourcePools = "SchemaHierarchy_ResourcePools"; + + + public const string SchemaHierarchy_ServerAudits = "SchemaHierarchy_ServerAudits"; + + + public const string SchemaHierarchy_ServerAuditSpecifications = "SchemaHierarchy_ServerAuditSpecifications"; + + + public const string SchemaHierarchy_SpatialIndexes = "SchemaHierarchy_SpatialIndexes"; + + + public const string SchemaHierarchy_WorkloadGroups = "SchemaHierarchy_WorkloadGroups"; + + + public const string SchemaHierarchy_SqlFiles = "SchemaHierarchy_SqlFiles"; + + + public const string SchemaHierarchy_ServerFunctions = "SchemaHierarchy_ServerFunctions"; + + + public const string SchemaHierarchy_SqlType = "SchemaHierarchy_SqlType"; + + + public const string SchemaHierarchy_ServerOptions = "SchemaHierarchy_ServerOptions"; + + + public const string SchemaHierarchy_DatabaseDiagrams = "SchemaHierarchy_DatabaseDiagrams"; + + + public const string SchemaHierarchy_SystemTables = "SchemaHierarchy_SystemTables"; + + + public const string SchemaHierarchy_Databases = "SchemaHierarchy_Databases"; + + + public const string SchemaHierarchy_SystemContracts = "SchemaHierarchy_SystemContracts"; + + + public const string SchemaHierarchy_SystemDatabases = "SchemaHierarchy_SystemDatabases"; + + + public const string SchemaHierarchy_SystemMessageTypes = "SchemaHierarchy_SystemMessageTypes"; + + + public const string SchemaHierarchy_SystemQueues = "SchemaHierarchy_SystemQueues"; + + + public const string SchemaHierarchy_SystemServices = "SchemaHierarchy_SystemServices"; + + + public const string SchemaHierarchy_SystemStoredProcedures = "SchemaHierarchy_SystemStoredProcedures"; + + + public const string SchemaHierarchy_SystemViews = "SchemaHierarchy_SystemViews"; + + + public const string SchemaHierarchy_DataTierApplications = "SchemaHierarchy_DataTierApplications"; + + + public const string SchemaHierarchy_ExtendedStoredProcedures = "SchemaHierarchy_ExtendedStoredProcedures"; + + + public const string SchemaHierarchy_SystemAggregateFunctions = "SchemaHierarchy_SystemAggregateFunctions"; + + + public const string SchemaHierarchy_SystemApproximateNumerics = "SchemaHierarchy_SystemApproximateNumerics"; + + + public const string SchemaHierarchy_SystemBinaryStrings = "SchemaHierarchy_SystemBinaryStrings"; + + + public const string SchemaHierarchy_SystemCharacterStrings = "SchemaHierarchy_SystemCharacterStrings"; + + + public const string SchemaHierarchy_SystemCLRDataTypes = "SchemaHierarchy_SystemCLRDataTypes"; + + + public const string SchemaHierarchy_SystemConfigurationFunctions = "SchemaHierarchy_SystemConfigurationFunctions"; + + + public const string SchemaHierarchy_SystemCursorFunctions = "SchemaHierarchy_SystemCursorFunctions"; + + + public const string SchemaHierarchy_SystemDataTypes = "SchemaHierarchy_SystemDataTypes"; + + + public const string SchemaHierarchy_SystemDateAndTime = "SchemaHierarchy_SystemDateAndTime"; + + + public const string SchemaHierarchy_SystemDateAndTimeFunctions = "SchemaHierarchy_SystemDateAndTimeFunctions"; + + + public const string SchemaHierarchy_SystemExactNumerics = "SchemaHierarchy_SystemExactNumerics"; + + + public const string SchemaHierarchy_SystemFunctions = "SchemaHierarchy_SystemFunctions"; + + + public const string SchemaHierarchy_SystemHierarchyIdFunctions = "SchemaHierarchy_SystemHierarchyIdFunctions"; + + + public const string SchemaHierarchy_SystemMathematicalFunctions = "SchemaHierarchy_SystemMathematicalFunctions"; + + + public const string SchemaHierarchy_SystemMetadataFunctions = "SchemaHierarchy_SystemMetadataFunctions"; + + + public const string SchemaHierarchy_SystemOtherDataTypes = "SchemaHierarchy_SystemOtherDataTypes"; + + + public const string SchemaHierarchy_SystemOtherFunctions = "SchemaHierarchy_SystemOtherFunctions"; + + + public const string SchemaHierarchy_SystemRowsetFunctions = "SchemaHierarchy_SystemRowsetFunctions"; + + + public const string SchemaHierarchy_SystemSecurityFunctions = "SchemaHierarchy_SystemSecurityFunctions"; + + + public const string SchemaHierarchy_SystemSpatialDataTypes = "SchemaHierarchy_SystemSpatialDataTypes"; + + + public const string SchemaHierarchy_SystemStringFunctions = "SchemaHierarchy_SystemStringFunctions"; + + + public const string SchemaHierarchy_SystemSystemStatisticalFunctions = "SchemaHierarchy_SystemSystemStatisticalFunctions"; + + + public const string SchemaHierarchy_SystemTextAndImageFunctions = "SchemaHierarchy_SystemTextAndImageFunctions"; + + + public const string SchemaHierarchy_SystemUnicodeCharacterStrings = "SchemaHierarchy_SystemUnicodeCharacterStrings"; + + + public const string SchemaHierarchy_AggregateFunctions = "SchemaHierarchy_AggregateFunctions"; + + + public const string SchemaHierarchy_ScalarValuedFunctions = "SchemaHierarchy_ScalarValuedFunctions"; + + + public const string SchemaHierarchy_TableValuedFunctions = "SchemaHierarchy_TableValuedFunctions"; + + + public const string SchemaHierarchy_SystemExtendedStoredProcedures = "SchemaHierarchy_SystemExtendedStoredProcedures"; + + + public const string SchemaHierarchy_BuiltInType = "SchemaHierarchy_BuiltInType"; + + + public const string SchemaHierarchy_BuiltInServerRole = "SchemaHierarchy_BuiltInServerRole"; + + + public const string SchemaHierarchy_UserWithPassword = "SchemaHierarchy_UserWithPassword"; + + + public const string SchemaHierarchy_SearchPropertyList = "SchemaHierarchy_SearchPropertyList"; + + + public const string SchemaHierarchy_SecurityPolicies = "SchemaHierarchy_SecurityPolicies"; + + + public const string SchemaHierarchy_SecurityPredicates = "SchemaHierarchy_SecurityPredicates"; + + + public const string SchemaHierarchy_ServerRole = "SchemaHierarchy_ServerRole"; + + + public const string SchemaHierarchy_SearchPropertyLists = "SchemaHierarchy_SearchPropertyLists"; + + + public const string SchemaHierarchy_ColumnStoreIndexes = "SchemaHierarchy_ColumnStoreIndexes"; + + + public const string SchemaHierarchy_TableTypeIndexes = "SchemaHierarchy_TableTypeIndexes"; + + + public const string SchemaHierarchy_Server = "SchemaHierarchy_Server"; + + + public const string SchemaHierarchy_SelectiveXmlIndexes = "SchemaHierarchy_SelectiveXmlIndexes"; + + + public const string SchemaHierarchy_XmlNamespaces = "SchemaHierarchy_XmlNamespaces"; + + + public const string SchemaHierarchy_XmlTypedPromotedPaths = "SchemaHierarchy_XmlTypedPromotedPaths"; + + + public const string SchemaHierarchy_SqlTypedPromotedPaths = "SchemaHierarchy_SqlTypedPromotedPaths"; + + + public const string SchemaHierarchy_DatabaseScopedCredentials = "SchemaHierarchy_DatabaseScopedCredentials"; + + + public const string SchemaHierarchy_ExternalDataSources = "SchemaHierarchy_ExternalDataSources"; + + + public const string SchemaHierarchy_ExternalFileFormats = "SchemaHierarchy_ExternalFileFormats"; + + + public const string SchemaHierarchy_ExternalResources = "SchemaHierarchy_ExternalResources"; + + + public const string SchemaHierarchy_ExternalTables = "SchemaHierarchy_ExternalTables"; + + + public const string SchemaHierarchy_AlwaysEncryptedKeys = "SchemaHierarchy_AlwaysEncryptedKeys"; + + + public const string SchemaHierarchy_ColumnMasterKeys = "SchemaHierarchy_ColumnMasterKeys"; + + + public const string SchemaHierarchy_ColumnEncryptionKeys = "SchemaHierarchy_ColumnEncryptionKeys"; + + + public const string SchemaHierarchy_SubroutineParameterLabelFormatString = "SchemaHierarchy_SubroutineParameterLabelFormatString"; + + + public const string SchemaHierarchy_SubroutineParameterNoDefaultLabel = "SchemaHierarchy_SubroutineParameterNoDefaultLabel"; + + + public const string SchemaHierarchy_SubroutineParameterInputLabel = "SchemaHierarchy_SubroutineParameterInputLabel"; + + + public const string SchemaHierarchy_SubroutineParameterInputOutputLabel = "SchemaHierarchy_SubroutineParameterInputOutputLabel"; + + + public const string SchemaHierarchy_SubroutineParameterInputReadOnlyLabel = "SchemaHierarchy_SubroutineParameterInputReadOnlyLabel"; + + + public const string SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel = "SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel"; + + + public const string SchemaHierarchy_SubroutineParameterDefaultLabel = "SchemaHierarchy_SubroutineParameterDefaultLabel"; + + + public const string SchemaHierarchy_NullColumn_Label = "SchemaHierarchy_NullColumn_Label"; + + + public const string SchemaHierarchy_NotNullColumn_Label = "SchemaHierarchy_NotNullColumn_Label"; + + + public const string SchemaHierarchy_UDDTLabelWithType = "SchemaHierarchy_UDDTLabelWithType"; + + + public const string SchemaHierarchy_UDDTLabelWithoutType = "SchemaHierarchy_UDDTLabelWithoutType"; + + + public const string SchemaHierarchy_ComputedColumnLabelWithType = "SchemaHierarchy_ComputedColumnLabelWithType"; + + + public const string SchemaHierarchy_ComputedColumnLabelWithoutType = "SchemaHierarchy_ComputedColumnLabelWithoutType"; + + + public const string SchemaHierarchy_ColumnSetLabelWithoutType = "SchemaHierarchy_ColumnSetLabelWithoutType"; + + + public const string SchemaHierarchy_ColumnSetLabelWithType = "SchemaHierarchy_ColumnSetLabelWithType"; + + + public const string SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString = "SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString"; + + + public const string UniqueIndex_LabelPart = "UniqueIndex_LabelPart"; + + + public const string NonUniqueIndex_LabelPart = "NonUniqueIndex_LabelPart"; + + + public const string ClusteredIndex_LabelPart = "ClusteredIndex_LabelPart"; + + + public const string NonClusteredIndex_LabelPart = "NonClusteredIndex_LabelPart"; + + + public const string History_LabelPart = "History_LabelPart"; + + + public const string SystemVersioned_LabelPart = "SystemVersioned_LabelPart"; + + + public const string External_LabelPart = "External_LabelPart"; + + + public const string FileTable_LabelPart = "FileTable_LabelPart"; + + + public const string DatabaseNotAccessible = "DatabaseNotAccessible"; + + + public const string ScriptingParams_ConnectionString_Property_Invalid = "ScriptingParams_ConnectionString_Property_Invalid"; + + + public const string ScriptingParams_FilePath_Property_Invalid = "ScriptingParams_FilePath_Property_Invalid"; + + + public const string ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid = "ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid"; + + + public const string StoredProcedureScriptParameterComment = "StoredProcedureScriptParameterComment"; + + + public const string ScriptingGeneralError = "ScriptingGeneralError"; + + + public const string ScriptingExecuteNotSupportedError = "ScriptingExecuteNotSupportedError"; + + + public const string BackupTaskName = "BackupTaskName"; + + + public const string BackupPathIsFolderError = "BackupPathIsFolderError"; + + + public const string InvalidBackupPathError = "InvalidBackupPathError"; + + + public const string TaskInProgress = "TaskInProgress"; + + + public const string TaskCompleted = "TaskCompleted"; + + + public const string ConflictWithNoRecovery = "ConflictWithNoRecovery"; + + + public const string InvalidPathForDatabaseFile = "InvalidPathForDatabaseFile"; + + + public const string Log = "Log"; + + + public const string RestorePlanFailed = "RestorePlanFailed"; + + + public const string RestoreNotSupported = "RestoreNotSupported"; + + + public const string RestoreTaskName = "RestoreTaskName"; + + + public const string RestoreCopyOnly = "RestoreCopyOnly"; + + + public const string RestoreBackupSetComponent = "RestoreBackupSetComponent"; + + + public const string RestoreBackupSetName = "RestoreBackupSetName"; + + + public const string RestoreBackupSetType = "RestoreBackupSetType"; + + + public const string RestoreBackupSetServer = "RestoreBackupSetServer"; + + + public const string RestoreBackupSetDatabase = "RestoreBackupSetDatabase"; + + + public const string RestoreBackupSetPosition = "RestoreBackupSetPosition"; + + + public const string RestoreBackupSetFirstLsn = "RestoreBackupSetFirstLsn"; + + + public const string RestoreBackupSetLastLsn = "RestoreBackupSetLastLsn"; + + + public const string RestoreBackupSetCheckpointLsn = "RestoreBackupSetCheckpointLsn"; + + + public const string RestoreBackupSetFullLsn = "RestoreBackupSetFullLsn"; + + + public const string RestoreBackupSetStartDate = "RestoreBackupSetStartDate"; + + + public const string RestoreBackupSetFinishDate = "RestoreBackupSetFinishDate"; + + + public const string RestoreBackupSetSize = "RestoreBackupSetSize"; + + + public const string RestoreBackupSetUserName = "RestoreBackupSetUserName"; + + + public const string RestoreBackupSetExpiration = "RestoreBackupSetExpiration"; + + + public const string TheLastBackupTaken = "TheLastBackupTaken"; + + + public const string NoBackupsetsToRestore = "NoBackupsetsToRestore"; + + + public const string ScriptTaskName = "ScriptTaskName"; + + + public const string InvalidPathError = "InvalidPathError"; + + + public const string ProfilerConnectionNotFound = "ProfilerConnectionNotFound"; + + + public const string AzureSystemDbProfilingError = "AzureSystemDbProfilingError"; + + + public const string CreateSessionFailed = "CreateSessionFailed"; + + + public const string StartSessionFailed = "StartSessionFailed"; + + + public const string PauseSessionFailed = "PauseSessionFailed"; + + + public const string StopSessionFailed = "StopSessionFailed"; + + + public const string SessionNotFound = "SessionNotFound"; + + + public const string SessionAlreadyExists = "SessionAlreadyExists"; + + + public const string CategoryLocal = "CategoryLocal"; + + + public const string CategoryFromMsx = "CategoryFromMsx"; + + + public const string CategoryMultiServer = "CategoryMultiServer"; + + + public const string CategoryDBMaint = "CategoryDBMaint"; + + + public const string CategoryWebAssistant = "CategoryWebAssistant"; + + + public const string CategoryFullText = "CategoryFullText"; + + + public const string CategoryReplDistribution = "CategoryReplDistribution"; + + + public const string CategoryReplDistributionCleanup = "CategoryReplDistributionCleanup"; + + + public const string CategoryReplHistoryCleanup = "CategoryReplHistoryCleanup"; + + + public const string CategoryReplLogReader = "CategoryReplLogReader"; + + + public const string CategoryReplMerge = "CategoryReplMerge"; + + + public const string CategoryReplSnapShot = "CategoryReplSnapShot"; + + + public const string CategoryReplCheckup = "CategoryReplCheckup"; + + + public const string CategoryReplCleanup = "CategoryReplCleanup"; + + + public const string CategoryReplAlert = "CategoryReplAlert"; + + + public const string CategoryReplQReader = "CategoryReplQReader"; + + + public const string CategoryReplication = "CategoryReplication"; + + + public const string CategoryUncategorized = "CategoryUncategorized"; + + + public const string CategoryLogShipping = "CategoryLogShipping"; + + + public const string CategoryDBEngineTuningAdvisor = "CategoryDBEngineTuningAdvisor"; + + + public const string CategoryDataCollector = "CategoryDataCollector"; + + + public const string UnknownSizeUnit = "UnknownSizeUnit"; + + + public const string UnexpectedRunType = "UnexpectedRunType"; + + + public const string CredentialNoLongerExists = "CredentialNoLongerExists"; + + + public const string UnknownServerType = "UnknownServerType"; + + + public const string SetOwnerFailed = "SetOwnerFailed"; + + + public const string TargetServerNotSelected = "TargetServerNotSelected"; + + + public const string ProxyAccountNotFound = "ProxyAccountNotFound"; + + + public const string SysadminAccount = "SysadminAccount"; + + + public const string JobAlreadyExists = "JobAlreadyExists"; + + + public const string JobStepNameCannotBeBlank = "JobStepNameCannotBeBlank"; + + + public const string JobStepNameAlreadyExists = "JobStepNameAlreadyExists"; + + + public const string AlertNameCannotBeBlank = "AlertNameCannotBeBlank"; + + + public const string CannotCreateNewAlert = "CannotCreateNewAlert"; + + + public const string CannotAlterAlert = "CannotAlterAlert"; + + + public const string InvalidScheduleTitle = "InvalidScheduleTitle"; + + + public const string InvalidWeeklySchedule = "InvalidWeeklySchedule"; + + + public const string StartDateGreaterThanEndDate = "StartDateGreaterThanEndDate"; + + + public const string StartTimeGreaterThanEndTime = "StartTimeGreaterThanEndTime"; + + + public const string EndTimeEqualToStartTime = "EndTimeEqualToStartTime"; + + + public const string InvalidStartDate = "InvalidStartDate"; + + + public const string ScheduleNameAlreadyExists = "ScheduleNameAlreadyExists"; + + + public const string JobServerIsNotAvailable = "JobServerIsNotAvailable"; + + + public const string NeverBackedUp = "NeverBackedUp"; + + + public const string Error_InvalidDirectoryName = "Error_InvalidDirectoryName"; + + + public const string Error_ExistingDirectoryName = "Error_ExistingDirectoryName"; + + + public const string ExportBacpacTaskName = "ExportBacpacTaskName"; + + + public const string ImportBacpacTaskName = "ImportBacpacTaskName"; + + + public const string ExtractDacpacTaskName = "ExtractDacpacTaskName"; + + + public const string DeployDacpacTaskName = "DeployDacpacTaskName"; + + + public const string GenerateScriptTaskName = "GenerateScriptTaskName"; + + + public const string ExtractInvalidVersion = "ExtractInvalidVersion"; + + + public const string PublishChangesTaskName = "PublishChangesTaskName"; + + + public const string SchemaCompareExcludeIncludeNodeNotFound = "SchemaCompareExcludeIncludeNodeNotFound"; + + + public const string OpenScmpConnectionBasedModelParsingError = "OpenScmpConnectionBasedModelParsingError"; + + + public const string SchemaCompareSessionNotFound = "SchemaCompareSessionNotFound"; + + + private Keys() + { } + + public static CultureInfo Culture + { + get + { + return _culture; + } + set + { + _culture = value; + } + } + + public static string GetString(string key) + { + return resourceManager.GetString(key, _culture); + } + + + public static string GetString(string key, object arg0) + { + return string.Format(global::System.Globalization.CultureInfo.CurrentCulture, resourceManager.GetString(key, _culture), arg0); + } + + + public static string GetString(string key, object arg0, object arg1) + { + return string.Format(global::System.Globalization.CultureInfo.CurrentCulture, resourceManager.GetString(key, _culture), arg0, arg1); + } + + + public static string GetString(string key, object arg0, object arg1, object arg2, object arg3) + { + return string.Format(global::System.Globalization.CultureInfo.CurrentCulture, resourceManager.GetString(key, _culture), arg0, arg1, arg2, arg3); + } + + + public static string GetString(string key, object arg0, object arg1, object arg2, object arg3, object arg4, object arg5) + { + return string.Format(global::System.Globalization.CultureInfo.CurrentCulture, resourceManager.GetString(key, _culture), arg0, arg1, arg2, arg3, arg4, arg5); + } + + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.de.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.de.resx new file mode 100644 index 0000000000..2ef7a4fea1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.de.resx @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Verbindungsparameter dürfen nicht null sein. + OwnerUri darf nicht null oder leer sein. + SpecifiedUri '{0}' hat keine gültige Verbindung + Ungültiger Wert '{0}' für AuthenticationType. Gültige Werte sind 'Integrated' und 'SqlLogin'. + Ungültiger Wert '{0}' für ApplicationIntent. Gültige Werte sind 'ReadWrite' und 'ReadOnly'. + Verbindung wurde abgebrochen. + OwnerUri darf nicht null oder leer sein. + Verbindungsdetails-Objekt darf nicht null sein. + ServerName darf nicht null oder leer sein. + {0} darf bei Verwendung der SqlLogin-Authentifizierung nicht null oder leer sein + Die Abfrage wurde bereits abgeschlossen und kann nicht abgebrochen werden + Abfrage wurde erfolgreich abgebrochen, Fehler beim Abfrage verfügen. Benutzer-URI nicht gefunden. + Die Abfrage wurde vom Benutzer abgebrochen. + Die Stapelverarbeitung ist noch nicht abgeschlossen + Batch-Index darf nicht kleiner als 0 oder größer als die Anzahl der Batches sein. + Der Index der Ergebnismenge darf nicht kleiner als 0 oder größer als die Anzahl der Ergebnismengen sein + Die maximale Anzahl an Bytes die zurückgeben wird, muss größer als 0 sein. + Die maximale Anzahl an Zeichen die zurückgeben werden, muss größer als 0 sein. + Die maximale Anzahl an XML Bytes die zurückgeben wird, muss größer als 0 sein. + Die Zugriffsmethode kann nicht write-only sein. + FileStreamWrapper muss initialisiert werden, bevor Operationen ausführt werden können + Diese FileStreamWrapper kann nicht zum Schreiben verwendet werden + (1 Zeile betroffen) + ({0} Zeilen betroffen) + Die Befehle wurden erfolgreich ausgeführt. + Zeile MSG {0} auf {1} Status {2}, {3} {4} {5} + Fehler bei Abfrage: {0} + (Kein Spaltenname) + Die angeforderte Abfrage ist nicht vorhanden. + Dieser Editor ist nicht mit einer Datenbank verbunden. + Eine Abfrage wird für diese Sitzung bereits ausgeführt. Brechen Sie diese Abfrage ab, oder warten Sie auf Beendigung. + Das sender Objekt für OnInfoMessage muss vom Typ SqlConnection sein + Das Ergebnis kann nicht gespeichert werden, solange die Abfrageausführung nicht abgeschlossen ist. + Beim Speichern ist ein interner Fehler aufgetreten + Eine Speicheranforderung mit demselben Pfad wird bereits ausgeführt. + Fehler beim Speichern von {0}: {1} + Der Teil kann nicht gelesen werden solange die Ergebnisse nicht vom Server gelesen wurden + Index der Startzeile kann nicht kleiner als 0 oder größer als die Anzahl der Zeilen der Ergebnismenge sein + Zeilenanzahl muss eine positive ganze Zahl sein. + Es konnten keine Schemainformationen der Spalte abgerufen werden + Es konnten kein Ausführungsplan für die Ergebnismenge abgerufen werden + Diese Funktionalität wird derzeit nicht in Azure SQL DB ud Data Warehouse unterstützt: {0} + Ein unerwarteter Fehler trat beim Einsehen der Definitionen auf: {0} + Es wurden keine Ergebnisse gefunden. + Es wurde kein Datenbankobjekt abgerufen + Verbinden Sie Sich mit einem Server. + Zeitüberschreitung bei der Ausführung + Dieser Objekttyp wird aktuell von dieser Funktionalität nicht unterstützt + Die Position befindet sich außerhalb der Zeile + Die Position befindet sich außerhalb der Spalte in Zeile {0} + Startposition ({0}, {1}) muss vor oder gleich der Endposition ({2}, {3}) sein + Meldung {0}, Ebene {1}, Status {2}, Zeile {3} + Meldung {0}, Ebene {1}, Status {2}, Prozedur {3}, Zeile {4} + Meldung {0}, Ebene {1}, Status {2} + Fehler beim Ausführen des Batches. Fehlermeldung: {0} + ({0} Zeile(n) betroffen) + Die vorherige Ausführung ist noch nicht abgeschlossen. + Ein Skriptfehler ist aufgetreten. + Ein Syntaxfehler ist aufgetreten der bei Analyse von {0} + Ein schwerwiegender Fehler ist aufgetreten. + {0}-mal ausgeführt... + Sie haben die Abfrage abgebrochen. + Fehler während der Batchausführung. + Fehler während der Batchausführung, aber des Fehlers wurde ignoriert. + Beginning execution loop + Befehl {0} wird nicht unterstützt. + Die Variable {0} konnte nicht gefunden werden. + Fehler bei der SQL-Ausführung: {0} + Batch-Ausführung des Batchanalysewrappers: {0} in Zeile {1} gefunden...: {2} Beschreibung: {3} + Batch Parser Wrapper Execution Engine Meldung empfangen: Meldung: {0} Ausführliche Meldung: {1} + Stapelverarbeitung Parser Wrapper Execution Engine Stapel ResultSet: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Batch-Parser Wrapper Execution Engine wurde beendet ResultSet. + Ausführung des Batchanalysewrappers Batch abgebrochen. + Scripting-Warnung. + Weitere Informationen zu diesem Fehler finden Sie in den entsprechenden Abschnitten der Produktdokumentation. + Die Datei '{0}' ist rekursiv eingeschlossen. + Fehlender End Kommentarzeichen "* /". + Fehlendes schließendes Anführungszeichen nach der Zeichenfolge + Syntaxfehler aufgetreten beim Analysieren von '{0}'. + Variable {0} ist nicht definiert. + Test + Ersatz einer leeren Zeichenfolge durch eine leere Zeichenfolge. + Die Sitzung "{0}" ist nicht vorhanden. + Die Abfrage wurde nicht abgeschlossen + Die Abfrage erzeugte mehr als eine Ergebnismenge + Fehler beim Hinzufügen einer neuen Zeile zum Aktualisierungscache + Die angegebene Zeilen-ID ist außerhalb des Bereiches des Bearbeitungscaches + Für diese Zeile steht eine Aktualisierung an, die erst zurückgenommen werden muß + Die angegebene Zeilen-ID hat keine ausstehenden Aktualisierungen + Tabellen oder Sicht Metadaten konnten nicht gefunden werden + Ungültiges Format für eine binäre Spalte + Spalten vom Typ Boolean müssen entweder der Zahl 0 oder 1 oder der Zeichenkette true oder false entsprechen + Ein Pflichtfeld hat keinen Wert. + Für diese Zeile steht ein Löschbefehl aus, die Aktualisierung von Feldern kann nicht durchgeführt werden. + Die ID der Spalte muss innerhalb des Bereichs der Spalten der Abfrage sein + Die Spalte kann nicht editiert werden + Keine Schlüsselspalten gefunden + Der Name der Ausgabedatei muss angegeben werden + Das Datenbankobjekt {0} kan nicht editiert werden + Spezifizierte URI '{0}' hat keine Standardverbindung + Eine Commit-Anweisung wird ausgeführt. Bitte warten Sie bis zur Fertigstellung + Für die Decimal-Spalte fehlt die Angabe der Genauigkeit und Dezimalstellenanzahl + <TBD> + Kann Zeile nicht an Ergebnisbuffer anhängen, da keine Zeilen im Datareader enthalten sind. + Der Wert für eine Spalte vom Typ TIME muss zwischen 00:00:00.0000000 und 23:59:59.9999999 liegen + NULL ist für diese Spalte nicht erlaubt + Es gibt bereits eine Session + Eine Session wurde nocht nicht initialisiert + Eine Session wurde bereits initialisiert + Eine Session wurde bereits initialisiert oder befindet sich im Prozess der Initialisierung. + Fehler beim Ausführen der Abfrage. Weitere Informationen finden SIe in der Ausgabe + Die Ergebnismengengrenze darf nicht negativ sein + NULL + Der Name des Objekts muss angegeben werden + Einen bestimmten Server oder Datenbank auszuwählen wird nicht unterstützt. + Die Metadaten der Tabelle enthält keine erweiterten EIgenschaften. + Tabelle oder Sicht zur Bearbeitung konnte nicht gefunden werden + Fehler beim Erweitern von: {0} + Fehler bei der Verbindung zu {0} + Aggregate + Serverrollen + Anwendungsrollen + Assemblys + Assemblydateien + Asymmetrische Schlüssel + Asymmetrische Schlüssel + Datenkomprimierungsoptionen + Zertifikate + FileTables + Zertifikate + Einschränkungen überprüfen + Spalten + Einschränkungen + Verträge + Anmeldeinformationen + Fehlermeldungen + Serverrollenmitgliedschaft + Datenbankoptionen + Datenbankrollen + Rollenmitgliedschaften + Datenbanktrigger + DEFAULT-Einschränkungen + Standardwerte + Sequenzen + Endpunkte + Ereignisbenachrichtigungen + Serverbenachrichtigungsereignisse + Erweiterte Eigenschaften + Dateigruppen + Fremdschlüssel + Volltextkataloge + Volltextindizes + Funktionen + Indizes + Inlinefunktionen + Schlüssel + Verbindungsserver + Anmeldungen für Verbindungsserver + Anmeldungen + Hauptschlüssel + Hauptschlüssel + Meldungstypen + Tabellenwertfunktionen + Parameter + Partitionsfunktionen + Partitionsschemas + Berechtigungen + Primärschlüssel + Programmierbarkeit + Warteschlangen + Remotedienstbindungen + Zurückgegebene Spalten + Rollen + Routen + Regeln + Schemas + Sicherheit + Serverobjekte + Verwaltung + Trigger + Service Broker + Dienste + Signaturen + Protokolldateien + Statistik + Speicher + Gespeicherte Prozeduren + Symmetrische Schlüssel + Synonyme + Tabellen + Trigger + Typen + Eindeutige Schlüssel + Benutzerdefinierte Datentypen + Benutzerdefinierte Typen (CLR) + Benutzer + Sichten + XML-Indizes + XML-Schemaauflistungen + Benutzerdefinierte Tabellentypen + Dateien + Fehlende Beschriftung + Brokerprioritäten + Kryptografieanbieter + Datenbank-Überwachungsspezifikationen + Verschlüsselungsschlüssel für Datenbank + Ereignissitzungen + Volltext-Stopplisten + Ressourcenpools + Überwachungen + Serverüberwachungsspezifikationen + Räumliche Indizes + Arbeitsauslastungsgruppen + SQL-Dateien + Serverfunktionen + SQL-Typ + Serveroptionen + Datenbankdiagramme + Systemtabellen + Datenbanken + Systemverträge + Systemdatenbanken + Systemmeldungstypen + Systemwarteschlangen + Systemdienste + Gespeicherte Systemprozeduren + Systemsichten + Datenebenenanwendungen + Erweiterte gespeicherte Prozeduren + Aggregatfunktionen + Ungefähre numerische Ausdrücke + Binärzeichenfolgen + Zeichenfolgen + CLR-Datentypen + Konfigurationsfunktionen + Cursorfunktionen + Systemdatentypen + Datum und Uhrzeit + Datums- und Uhrzeitfunktionen + Genaue numerische Ausdrücke + Systemfunktionen + Hierarchie-ID-Funktionen + Mathematische Funktionen + Metadatenfunktionen + Andere Datentypen + Andere Funktionen + Rowsetfunktionen + Sicherheitsfunktionen + Räumliche Datentypen + Zeichenfolgenfunktionen + Statistische Systemfunktionen + Text- und Bildfunktionen + Unicode-Zeichenfolgen + Aggregatfunktionen + Skalarwertfunktionen + Tabellenwertfunktionen + Erweiterte gespeicherte Systemprozeduren + Integrierte Typen + Integrierte Serverrollen + Benutzer mit Kennwort + Sucheigenschaftenliste + Sicherheitsrichtlinien + Sicherheitsprädikate + Serverrolle + Sucheigenschaftenlisten + Spaltenspeicherindizes + Tabellentypindex + Selektive XML-Indexe + XML-Namespaces + XML-typisierte höher gestufte Pfade + T-SQL-typisierte höher gestufte Pfade + Datenbankweit gültige Anmeldeinformationen + Externe Datenquellen + Externe Dateiformate + Externe Ressourcen + Externe Tabellen + Immer verschlüsselte Schlüssel + Spaltenhauptschlüssel + Spaltenverschlüsselungsschlüssel + Server + Fehler beim Analysieren der Eigenschaft ScriptingParams.ConnectionString. + Ungültiges Verzeichnis angeben in der Eigenschaft ScriptingParams.FilePath. + Fehler beim Analysieren der Eigenschaft ScriptingListObjectsCompleteParams.ConnectionString + {0} ({1}, {2}, {3}) + Kein Standard + Eingabe + Eingabe/Ausgabe + Eingabe/schreibgeschützt + Eingabe/Ausgabe/schreibgeschützt + Standard + NULL + nicht NULL + {0} ({1}, {2}) + {0} ({1}) + {0} ({1}berechnet, {2}, {3}) + {0} ({1}berechnet) + {0} (Spaltensatz, {1}) + {0} (Spaltensatz, {1} {2}, {3}) + {0} (Spaltensatz, {1}, {2}, {3}) + Eindeutig + Nicht eindeutig + Gruppiert + Nicht gruppiert + Verlauf + System-Mit Versionsangabe + Nicht verfügbar + Aktuelle Standarddateigruppe: {0} + Neue Dateigruppe für "{0}" + Standard + Dateien + Name + Schreibgeschützt + Automatische Vergrößerung/Maximale Größe + ... + <Standard> + Dateigruppe + Logischer Name + Dateityp + Anfangsgröße (MB) + <neue Dateigruppe> + Pfad + Dateiname + <unformatiertes Medium> + Massenprotokolliert + Vollständig + Einfach + Datenbankbesitzer auswählen + Kein(e) + Um {0} MB, auf {1} MB beschränkt + Um {0} Prozent, auf {1} MB beschränkt + Um {0} MB, unbegrenzt + Um {0} Prozent, unbegrenzt + Unbegrenzt + Auf {0} MB beschränkt + Automatisch + Service Broker + Sortierung + Cursor + Verschiedenes + Wiederherstellung + Status + ANSI NULL Default + ANSI NULLS aktiviert + ANSI-Auffüllung aktiviert + ANSI Warnings aktiviert + Abbruch bei arithmetischem Fehler aktiviert + Automatisch schließen + Statistik automatisch erstellen + Automatisch verkleinern + Statistiken automatisch aktualisieren + Statistik automatisch asynchron aktualisieren + Unterscheidung nach Groß-/Kleinschreibung + Schließen des Cursors nach Commit aktiviert + Sortierung + Verketten von NULL-Werten ergibt NULL + Datenbank-Kompatibilitätsgrad + Datenbankstatus + Standardcursor + Volltextindizierung aktiviert + Abbruch bei numerischem Runden + Seitenüberprüfung + Bezeichner in Anführungszeichen aktiviert + Datenbank schreibgeschützt + Rekursive Trigger aktiviert + Zugriff beschränken + Select Into/Bulk Copy + Brokerpriorität berücksichtigen + Service Broker-Bezeichner + Broker aktiviert + Protokoll bei Prüfpunkt abschneiden + Datenbankübergreifende Besitzverkettung aktiviert + Vertrauenswürdig + Optimierung der Datumskorrelation aktiviert: +prototype_db_prop_parameterization = Parameterization + Erzwungen + Einfach + ROWS (Daten) + LOG + FILESTREAM-Daten + Nicht zutreffend + <Standardpfad> + Geöffnete Verbindungen + Zum Ändern der Datenbankeigenschaften muss SQL Server alle anderen Verbindungen mit der Datenbank schließen. Möchten Sie wirklich die Eigenschaften ändern und alle anderen Verbindungen schließen? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + VarDecimal-Speicherformat aktiviert + SQL Server 2008 (100) + Verschlüsselung aktiviert + AUS + EIN + PRIMÄR + Die Anzahl führender Hashspalten ist bei der HASH-Verteilungsrichtlinie optional, sollte aber zwischen 1 und 16 Spalten liegen. + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Kein(e) + Teilweise + FILESTREAM-Dateien + Keine anwendbare Dateigruppe + Auf die Datenbank "{0}" kann nicht zugegriffen werden. + Abfrage hat keine Ergebnis zum Zurückgeben + Ergebnismenge ist zu groß, um sicher geladen zu werden + Parametrisierung + Diese Option darf nicht angegeben werden, wenn eine Sicherung mit der NORECOVERY-Option wiederhergestellt wird. + Ungültiger Pfad für Datenbankdatei: {0} + Protokoll + Fehler beim Erstellen des Wiederherstellungsplan + Wiederherstellen der Datenbank wird nicht unterstützt. + Datenbank wiederherstellen + (nur kopieren) + Komponente + Typ + Server + Datenbank + Position + Erste LSN + Letzte LSN + Prüfpunkt-LSN + Vollständige LSN + Startdatum + Beendigungsdatum + Größe + Benutzername + Ablaufdatum + Name + Letzte Sicherung ({0}) + Datenbank sichern + In Bearbeitung + Abgeschlossen + Skripterstellung + Verbindung nicht gefunden + Der angegebene Dateiname ist zugleich ein Verzeichnisname: {0} + Es kann nicht überprüft werden, ob der Speicherort der Sicherungsdatei vorhanden ist: {0} + Auf den angegebenen Pfad auf dem Server kann nicht zugegriffen werden: {0} + Kein Sicherungssatz zur Wiederherstellung ausgewählt + Nie + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL Stretch Database + Der Pfad {0} ist kein gültiges Verzeichnis + Die Datei {1} im Verzeichnis {0} existiert bereits. + Der Wert {0} ist zu groß für eine Spalte mit dem Datentyp {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.es.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.es.resx new file mode 100644 index 0000000000..eb2b138b5f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.es.resx @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Los parámetros de conexión no pueden ser nulos + OwnerUri no puede ser nulo ni estar vacío + SpecifiedUri '{0}' no tiene una conexión existente + El valor '{0}' no es válido para AuthenticationType. Los valores válidos son 'Integrated' y 'SqlLogin'. + El valor '{0}' no es válido para ApplicationIntent. Los valores válidos son 'ReadWrite' y 'ReadOnly'. + Conexión cancelada + OwnerUri no puede ser nulo ni estar vacío + El objeto de detalles de conexión no puede ser nulo + ServerName no puede ser nulo ni estar vacío + {0} no puede ser nulo ni estar vacío cuando se utiliza autenticación SqlLogin + Ya se ha completado la consulta, no se puede cancelar + La consulta fue cancelada con éxito, pero no se ha podido desechar. No se encontró el URI del propietario. + Consulta cancelada por el usuario + El lote aún no ha finalizado, + Índice de lote no puede ser menor que 0 o mayor que el número de lotes + Índice del conjunto de resultados no puede ser menor que 0 o mayor que el número de conjuntos de resultados + El número máximo de bytes a devolver debe ser mayor que cero + El número máximo de caracteres a devolver debe ser mayor que cero + El número máximo de bytes XML a devolver debe ser mayor que cero + El método de acceso no puede ser de sólo escritura + FileStreamWrapper debe inicializarse antes de realizar operaciones + Este FileStreamWrapper no se puede utilizar para escritura. + (1 fila afectada) + ({0} filas afectadas) + Comandos finalizados correctamente. + Msg {0}, nivel {1} estado {2}, línea {3} {4} {5} + Error en la consulta: {0} + (Ningún nombre de columna) + La consulta solicitada no existe + Este editor no está conectado a una base de datos + Una consulta ya está en curso para esta sesión de editor. Por favor, cancelar esta consulta o esperar su finalización. + Remitente de eventos de OnInfoMessage debe ser un objeto SqlConnection + No se puede guardar el resultado hasta que haya finalizado la ejecución de la consulta + Error interno al iniciar el guardado de la tarea + Una operacion de guardado en la misma ruta se encuentra en curso + Error al guardar {0}: {1} + No se puede leer el subconjunto, a menos que los resultados se han leído desde el servidor + Fila de inicio no puede ser menor que 0 o mayor que el número de filas en el conjunto de resultados + La cantidad de filas debe ser un entero positivo + No se pudo recuperar el esquema de columna para el conjunto de resultados + No se pudo recuperar un plan de ejecución del conjunto de resultados + Esta característica actualmente no se admite en la base de datos de SQL Azure y almacén de datos: {0} + Se ha producido un error inesperado durante la ejecución de la definición de Peek: {0} + No se encontraron resultados. + No se pudo obtener ningún objeto asociado a la base de datos. + Por favor, conéctese a un servidor + Tiempo de espera agotado para esta operación. + Esta característica no admite actualmente este tipo de objeto. + Posición está fuera del intervalo de la línea de archivo + Posición está fuera del intervalo de la columna de la línea {0} + Posición de inicio ({0}, {1}) debe preceder o ser igual a la posición final ({2}, {3}) + Msg {0}, {1}, nivel de estado {2}, línea {3} + Msj {0}, {1}, nivel de estado {2}, procedimiento {3}, línea {4} + Msg {0}, nivel {1}, {2} de estado + Se produjo un error al procesar el lote. Mensaje de error: {0} + ({0} filas afectadas) + La ejecución anterior aún no está completa. + Se ha producido un error de secuencias de comandos. + Se encontró sintaxis incorrecta mientras se estaba analizando {0}. + Se ha producido un error grave. + La ejecución se completó {0} veces... + Se canceló la consulta. + Se produjo un error mientras se ejecutaba el lote. + Se produjo un error mientras se ejecutaba el lote, pero se ha omitido el error. + Beginning execution loop + No se admite el comando {0}. + La variable {0} no se encontró. + Error de ejecución de SQL: {0} + Ejecución de contenedor del analizador por lotes: {0} se encuentra... en la línea {1}: {2} Descripción: {3} + Lote analizador contenedor ejecución motor lote mensaje recibido: mensaje: {0} mensaje detallado: {1} + Motor de ejecución de analizador contenedor lote ResultSet procesamiento por lotes: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Finalizó el elemento ResultSet analizador contenedor ejecución motor los lotes. + Cancelando la ejecución por lotes del contenedor del analizador por lotes. + Advertencia de scripting. + Para obtener más información acerca de este error, vea los temas de solución de problemas en la documentación del producto. + El archivo '{0}' se incluyó recursivamente. + Falta la marca de final de comentario ' * /'. + Sin comilla de cierre después de la cadena de caracteres. + Se encontró sintaxis incorrecta al analizar '{0}'. + La variable {0} no está definida. + prueba + Sustitución de una cadena vacía por una cadena vacía. + Sesión de edición no existe, + La consulta no ha finalizado. + La consulta no generó un único set de resultados + Falló al agregar una nueva fila a la caché de actualización + El ID de la fila ingresado, se encuentra fuera del rango de filas de la caché de edición + Una actualización está pendiente para esta fila y debe de revertirse primero + El ID de la fila ingresado no tiene actualizaciones pendientes + La metadata de la tabla o vista no pudo ser encontrada + Formato inválido para columna binaria + Columnas del tipo boolean deben de ser numéricos 1 o 0, o tipo string true o false + Falta un valor requerido de la celda + Existe una eliminación pendiente para esta fila, una actualización de celda no puede ser realizada. + El ID de la columna debe de estar en el rango de columnas de la consulta. + La columna no puede ser editada + No se encontró ninguna columna clave + Proporcione un nombre de archivo de salida + Objeto de base de datos {0} no puede ser usado para modificación. + SpecifiedUri '{0}' no tiene alguna conexión por defecto + Una tarea de confirmación se encuentra en progreso. Por favor espere que la operación termine. + Columna del tipo decimal no tiene precisión o escala numérica + <TBD> + No se pueden agregar filas al buffer de resultados, el lector de datos no contiene filas + Los valores en la columna TIME deben estar incluidos en el rango desde 00:00:00:000000 hasta 23:59:59.999999 + No se permite un valor NULL en esta columna + La sesión de edición ya existe. + La sesión de edición no se inicializó + La sesión de edición ya se inicializó + La sesión de edición ya se inicializo o se encuentra en proceso de inicialización + La ejecución de la consulta falló, ver los mensajes para obtener mas detalle + El límite del resultado no puede ser negativo + NULL + Se debe proveer un nombre de objeto + No se permite especificar explícitamente el servidor o la base de datos + Los metadatos de la tabla no tienen propiedades extendidas + La tabla o vista solicitada para edición no se encuentra + Error en expansión: {0} + Error conectando a {0} + Agregados + Roles de servidor + Roles de aplicación + Ensamblados + Archivos de ensamblado + Claves asimétricas + Claves asimétricas + Opciones de compresión de datos + Certificados + Tablas de archivos + Certificados + Restricciones CHECK + Columnas + Restricciones + Contratos + Credenciales + Mensajes de error + Pertenencia a roles de servidor + Opciones de base de datos + Roles de base de datos + Pertenencias a roles + Desencadenadores de base de datos + Restricciones DEFAULT + Valores predeterminados + Secuencias + Extremos + Notificaciones de eventos + Notificaciones de eventos de servidor + Propiedades extendidas + Grupos de archivos + Claves externas + Catálogos de texto completo + Índices de texto completo + Funciones + Índices + Funciones Inline + Claves + Servidores vinculados + Inicios de sesión de servidor vinculado + Inicios de sesión + Clave maestra + Claves maestras + Tipos de mensaje + Funciones con valores de tabla + Parámetros + Funciones de partición + Esquemas de partición + Permisos + Claves principales + Programación + Colas + Enlaces de servicio remoto + Columnas devueltos + Roles + Rutas + Reglas + Esquemas + Seguridad + Objetos de servidor + Administración + Desencadenadores + Service Broker + Servicios + Firmas + Archivos de registro + Estadísticas + Almacenamiento + Procedimientos almacenados + Claves simétricas + Sinónimos + Tablas + Desencadenadores + Tipos + Claves únicas + Tipos de datos definidos por el usuario + Tipos definidos por el usuario (CLR) + Usuarios + Vistas + Índices XML + Colecciones de esquemas XML + Tipos de tablas definidos por el usuario + Archivos + Falta el título + Prioridades de Broker + Proveedores de servicios criptográficos + Especificaciones de auditoría de base de datos + Claves de cifrado de base de datos + Sesiones de eventos + Listas de palabras irrelevantes de texto completo + Grupos de recursos de servidor + Auditorías + Especificaciones de auditoría de servidor + Índices espaciales + Grupos de cargas de trabajo + Archivos SQL + Funciones de servidor + Tipo SQL + Opciones de servidor + Diagramas de base de datos + Tablas del sistema + Bases de datos + Contratos del sistema + Bases de datos del sistema + Tipos de mensaje del sistema + Colas del sistema + Servicios del sistema + Procedimientos almacenados del sistema + Vistas del sistema + Aplicaciones de capa de datos + Procedimientos almacenados extendidos + Funciones de agregado + Valores numéricos aproximados + Cadenas binarias + Cadenas de caracteres + Tipos de datos CLR + Funciones de configuración + Funciones del cursor + Tipos de datos del sistema + Fecha y hora + Funciones de fecha y hora + Valores numéricos exactos + Funciones del sistema + Funciones de id. de jerarquía + Funciones matemáticas + Funciones de metadatos + Otros tipos de datos + Otras funciones + Funciones de conjunto de filas + Funciones de seguridad + Tipos de datos espaciales + Funciones de cadena + Funciones estadísticas del sistema + Funciones de texto y de imagen + Cadenas de caracteres Unicode + Funciones de agregado + Funciones escalares + Funciones con valores de tabla + Procedimientos almacenados extendidos del sistema + Tipos integrados + Roles de servidor integrados + Usuario con contraseña + Lista de propiedades de búsqueda + Directivas de seguridad + Predicados de seguridad + Rol de servidor + Listas de propiedades de búsqueda + Índices de almacenamiento de columnas + Índices de tipo de tabla + Índices XML selectivos + Espacios de nombres XML + Rutas de acceso promovidas de tipo XML + Rutas de acceso promovidas de tipo T-SQL + Credenciales de ámbito de base de datos + Orígenes de datos externos + Formatos de archivo externo + Recursos externos + Tablas externas + Siempre claves cifradas + Claves maestras de columna + Claves de cifrado de columna + Servidor + Error interpretando la propiedad ScriptingParams.ConnectionString + El directorio especificado en la propiedad ScriptingParams.FilePath no es válido + Error interpretando la propiedad ScriptingListObjectsCompleteParams.ConnectionString + {0} ({1}, {2}, {3}) + Sin valores predeterminados + Entrada + Entrada/salida + Entrada/solo lectura + Entrada/salida/solo lectura + Predeterminado + NULL + no es NULL + {0} ({1}, {2}) + {0} ({1}) + {0} ({1}calculado, {2}, {3}) + {0} ({1}calculado) + {0} (Conjunto de columnas, {1}) + {0} (Conjunto de columnas, {1}{2}, {3}) + {0} (Conjunto de columnas, {1}, {2}, {3}) + Único + No único + Clúster + No en clúster + Historial + Con versión del sistema + No disponible + Grupo de archivos predeterminado: {0} + Grupo de archivos nuevo para: {0} + Predeterminado + Archivos + Nombre + Solo lectura + Crecimiento automático / tamaño máximo + ... + <predeterminado> + Grupo de archivos + Nombre lógico + Tipo de archivo + Tamaño inicial (MB) + <nuevo grupo de archivos> + Ruta de acceso + Nombre de archivo + <dispositivo sin formato> + Registro masivo + Completo + Simple + Seleccionar propietario de base de datos + Ninguno + Por {0} MB, limitado a {1} MB + Por {0} porciento, limitado a {1} MB + Por {0} MB, sin límite + Por {0} porciento, sin límite + Sin límite + Limitado a {0} MB + Automático + Service Broker + Intercalación + Cursor + Varios + Recuperación + Estado + ANSI NULL predeterminado + ANSI NULLS habilitados + Relleno ANSI habilitado + Advertencias ANSI habilitadas + Anulación aritmética habilitada + Cierre automático + Crear estadísticas automáticamente + Reducir automáticamente + Actualizar estadísticas automáticamente + Actualizar estadísticas automáticamente de forma asincrónica + Sensible a mayúsculas y minúsculas + Cierre del cursor al confirmar habilitado + Intercalación + Concatenar valores NULL produce NULL + Nivel de compatibilidad de base de datos + Estado de la base de datos + Cursor predeterminado + Índice de texto completo habilitado + Anular redondeo numérico + Comprobación de página + Identificadores entre comillas habilitados + Base de datos de solo lectura + Desencadenadores recursivos habilitados + Restringir acceso + Select Into/Bulk Copy + Asignar prioridad de agente + Identificador de Service Broker + Broker habilitado + Truncar registro en el punto de control + Encadenamiento de propiedad entre bases de datos habilitado + De confianza + Optimización de correlación de fechas Enabledprototype_db_prop_parameterization = Parameterization + Forzado + Simple + Datos de ROWS + LOG + Datos de FILESTREAM + No aplicable + <ruta predeterminada> + Conexiones abiertas + Para cambiar las propiedades de la base de datos, SQL Server debe cerrar todas las otras conexiones a la base de datos. ¿Seguro que desea cambiar las propiedades y cerrar todas las otras conexiones? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + Formato de almacenamiento VarDecimal habilitado + SQL Server 2008 (100) + Cifrado habilitado + OFF + ON + PRIMARY + Para la directiva de distribución HASH, el número de columnas iniciales hash es opcional pero debe de ser entre 1 y 16 columnas + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Ninguno + Parcial + Archivos FILESTREAM + Grupo de archivos no aplicable + La base de datos {0} no es accesible. + La consulta no devolvió resultados + El conjunto de resultados contiene demasiada filas para cargarlo de forma segura + Parametrización + No se permite restaurar una copia de seguridad con la opción NORECOVERY + Ruta de archivo no válida: '{0}' + Registro + No se pudo crear un plan de restauraciones + No se admite restaurar la base de datos + Restaurar base de datos + (Copiar solamente) + Componente + Tipo + Servidor + Base de datos + Posición + Primer LSN + Último LSN + Checkpoint LSN + LSN completo + Fecha de inicio + Fecha de finalización + Tamaño + Nombre del usuario + Expiración + Nombre + La última copia de seguridad tomada ({0}) + Copia de seguridad de la base de datos + En curso + Completado + scripting + Conexión no encontrada + El nombre del archivo especificado es un nombre de directorio: {0} + No se puede verificar la existencia de la ubicación del archivo de copia de seguridad: {0} + No se puede acceder a la ruta de acceso especificada en el servidor: {0} + Ningún backupset seleccionado para ser restaurado + Nunca + Azure SQL Database + Azure SQL Data Warehouse + Azure SQL Stretch Database + La ruta de acceso [{0}] no es un directorio válido + Ya existe un archivo {1} en el directorio '{0}' + El valor {0} es muy grande para el tipo de columna {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.fr.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.fr.resx new file mode 100644 index 0000000000..adc2950a56 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.fr.resx @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Les paramètres de connexion ne peuvent pas être null + OwnerUri ne peut pas être null ou vide. + SpecifiedUri '{0}' n’a pas de connexion existante + Valeur '{0}' non valide pour AuthenticationType. Les valeurs valides sont 'Integrated' et 'SqlLogin'. + Valeur '{0}' non valide pour ApplicationIntent. Les valeurs valides sont 'ReadWrite' et 'ReadOnly'. + Connexion annulée + OwnerUri ne peut pas être null ou vide. + L'objet "détails de connexion" ne peut pas être null + ServerName ne peut pas être null ou vide + {0} ne peut pas être nul ou vide quand l'authentification SqlLogin est utilisée + La requête est déjà terminée, elle ne peut pas être annulée. + Requête annulée avec succès, échec de la libération de la requête. L'URI propriétaire n'a pas été trouvée. + La requête a été annulée par l’utilisateur + Le lot n’a pas terminé encore + Index de lot ne peut pas être inférieur à 0 ou supérieur au nombre de lots + L'index de résultats ne peut pas être inférieur à 0 ou supérieur au nombre de résultats + Le nombre maximal d'octets à renvoyer doit être supérieur à zéro + Le nombre maximal de caractères à renvoyer doit être supérieur à zéro + Le nombre maximal d’octets XML à renvoyer doit être supérieur à zéro + Méthode d’accès ne peut pas être en écriture seule + FileStreamWrapper doit être initialisée avant d’effectuer des opérations + Ce FileStreamWrapper ne peut pas être utilisé pour l’écriture + (1 ligne affectée) + ({0} lignes affectées) + Commandes terminées avec succès. + Msg {0}, au niveau état {2}, {1}, ligne {3} {4} {5} + La requête a échoué : {0} + (Aucun nom de colonne) + La requête demandée n’existe pas + Cet éditeur n’est pas connecté à une base de données + Une requête est déjà en cours pour cette session d’éditeur. Veuillez annuler cette requête, ou attendre son achèvement. + L’expéditeur de l’événement de OnInfoMessage doit être un objet SqlConnection + Impossible d’enregistrer les résultats jusqu'à ce que l’exécution de la requête est terminée. + Une erreur interne s'est produite lors du démarrage de la tâche de sauvegarde. + Une requête de sauvegarde vers le même chemin est en cours + Impossible d’enregistrer {0} : {1} + Impossible de lire le sous-élément à moins que les résultats aient été lus depuis le serveur + La ligne de début ne peut pas être inférieure à 0 ou supérieure au nombre de lignes de résultats + Le nombre de lignes doit être un entier positif + Impossible de récupérer le schéma des colonnes pour le jeu de résultats + Impossible de récupérer un plan d’exécution pour le jeu de résultats + Cette fonctionnalité n'est actuellement pas supportée sur Azure SQL DB et Data Warehouse : {0} + Une erreur inattendue s'est produite lors de l'exécution du coup d'oeil à la définition: {0}. + Aucun résultat trouvé. + Aucun objet de base de données n'a été récupéré. + Veuillez vous connecter à un serveur. + Opération a expiré. + Ce type d'objet n'est actuellement pas supporté par cette fonctionnalité + La position est en dehors de la plage de lignes du fichier + La position est en dehors de la plage de colonnes pour la ligne {0} + Position de début ({0}, {1}) doit précéder ou être égale à la position de fin ({2}, {3}) + Msg {0}, Niveau {1}, État {2}, Ligne {3} + Msg {0}, Niveau {1}, État {2}, Procédure {3}, Ligne {4} + Msg {0}, Niveau {1}, État {2} + Une erreur s'est produite lors du traitement du lot. Le message d'erreur est : {0} + ({0} lignes affectées) + L'exécution précédente n'est pas encore terminée. + Une erreur de script s'est produite. + Une syntaxe incorrecte a été trouvée lors de l'analyse de {0}. + Une erreur irrécupérable s'est produite. + L'exécution a été effectuée {0} fois... + Vous avez annulé la requête. + Une erreur s'est produite lors de l'exécution du lot. + Une erreur s'est produite lors de l'exécution du lot, mais elle a été ignorée. + Beginning execution loop + La commande {0} n'est pas prise en charge. + Impossible de trouver la variable {0}. + Erreur d’exécution de SQL : {0} + Exécution du wrapper de l'analyseur du lot : {0} trouvé... à la ligne {1} : {2} Description : {3} + Message reçu du lot du moteur d'exécution du wrapper de l'analyseur du lot : Message : {0} Message détaillé : {1} + Traitement du ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot : DataReader.FieldCount : {0} DataReader.RecordsAffected : {1} + ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot terminé. + Annulation de l'exécution du lot du wrapper de l'analyseur du lot. + Avertissement de script. + Pour plus d'informations sur cette erreur, consultez les rubriques de dépannage dans la documentation du produit. + Le fichier '{0}' a été inclus de manière récursive. + La marque de commentaire de fin '*/' est manquante. + Guillemets non fermés après la chaîne de caractères. + Détection d'une syntaxe incorrecte pendant l'analyse de '{0}'. + La variable {0} n'est pas définie. + test + Remplacement d’une chaîne vide à une chaîne vide. + La session d'édition n’existe pas. + La requête n’a pas terminé l’exécution + La requête n’a pas généré exactement un jeu de résultats + Impossible d’ajouter la nouvelle ligne pour mettre à jour le cache + L'identifiant de ligne spécifié est en dehors de la plage de lignes dans le cache d’édition + Une mise à jour est déjà en attente pour cette ligne et doit être d’abord annulée + L'identifiant de la ligne n'a pas de mise à jour en attente + Les métadonnées de la table ou de la vue n’ont pas pu être trouvées + Format invalide pour une colonne binary + Les colonnes booléennes doivent être un numérique 1 ou 0, ou une chaîne true ou false + Une valeur de cellule requise est manquante. + Une suppression est en attente pour cette ligne, une mise à jour de cellule ne peut pas être appliquée. + La colonne Id doit être dans la plage des colonnes de la requête + La colonne ne peut pas être éditée + Aucune colonne clé n'a été trouvée + Un nom de fichier de sortie doit être fourni + L'objet de base de données {0} ne peut pas être utilisé pour éditer + L'Uri spécifiée '{0}' n’a pas de connexion par défaut + Une tâche commit est en cours. Veuillez, s'il vous plaît, attendre la fin. + La colonne decimal manque d'une précision numérique + <TBD> + Impossible d'ajouter une ligne au tampon de résultats, le data reader ne contient aucune ligne + Les valeurs de colonne TIME doivent être contenues entre 00:00:00.0000000 et 23:59:59.9999999 + NULL n'est pas autorisé pour cette colonne + La session d'édition existe déjà. + La session d'édition n'a pas été initialisée + La session d'édition a déjà été initialisée + La session d'édition a déjà été initialisée ou est en cours d'initialisation + L'exécution de la requête a échoué, voir les messages pour plus de détails + La limite de résultat ne peut pas être négative + NULL + Un nom d'objet doit être fourni + La spécification explicite du serveur ou de la base de données n'est pas pris en charge + Les métadonnées de tables n'ont pas de propriétés étendues + La table ou la vue demandée pour édition n'a pas pu être trouvée + Erreur en développant : {0} + Erreur en se connectant à {0} + Agrégats + Rôles serveur + Rôles d'application + Assemblys + Fichiers d'assembly + Clés asymétriques + Clés asymétriques + Options de compression de données + Certificats + FileTables + Certificats + Contraintes de validation + Colonnes + Contraintes + Contrats + Informations d'identification + Messages d'erreur + Appartenance au rôle de serveur + Options de la base de données + Rôles de base de données + Appartenances aux rôles + Déclencheurs de base de données + Contraintes par défaut + Par défaut + Séquences + Points de terminaison + Notifications d'événements + Notifications d'événements du serveur + Propriétés étendues + Groupes de fichiers + Clés étrangères + Catalogues de recherche en texte intégral + Index de recherche en texte intégral + Fonctions + Index + Fonctions incluses + Clés + Serveurs liés + Connexions de serveur lié + Connexions + Clé principale + Clés principales + Types de messages + Fonctions table + Paramètres + Fonctions de partition + Schémas de partition + Autorisations + Clés primaires + Programmabilité + Files d'attente + Liaisons de service distant + Colonnes retournées + Rôles + Itinéraires  + Règles + Schémas + Sécurité + Objets serveur + Gestion + Déclencheurs + Service Broker + Services + Signatures + Fichiers journaux + Statistiques + Stockage + Procédures stockées + Clés symétriques + Synonymes + Tables + Déclencheurs + Types + Clés uniques + Types de données définis par l'utilisateur + Types définis par l'utilisateur (CLR) + Utilisateurs + Vues + Index XML + Collections de schémas XML + Types de tables définis par l'utilisateur + Fichiers + Légende manquante + Priorités de Service Broker + Fournisseurs de chiffrement + Spécifications de l'audit de la base de données + Clés de chiffrement de la base de données + Sessions d'événements + Listes de mots vides de texte intégral + Pools de ressources + Audits + Spécifications de l'audit du serveur + Index spatiaux + Groupes de charges de travail + Fichiers SQL + Fonctions du serveur + Type SQL + Options de serveur + Schémas de base de données + Tables système + Bases de données + Contrats système + Bases de données système + Types de messages système + Files d'attente système + Services système + Procédures stockées système + Vues système + Applications de la couche Données + Procédures stockées étendues + Fonctions d'agrégation + Valeurs numériques approximatives + Chaînes binaires + Chaînes de caractères + Types de données CLR + Fonctions de configuration + Fonctions du curseur + Types de données système + Date et heure + Fonctions de date et d'heure + Valeurs numériques exactes + Fonctions système + Fonctions de l'ID de hiérarchie + Fonctions mathématiques + Fonctions de métadonnées + Autres types de données + Autres fonctions + Fonctions d'ensemble de lignes + Fonctions de sécurité + Types de données spatiales + Fonctions de chaîne + Fonctions statistiques système + Fonctions de texte et d'image + Chaînes de caractères Unicode + Fonctions d'agrégation + Fonctions scalaires + Fonctions table + Procédures stockées étendues système + Types intégrés + Rôles serveur intégrés + Utilisateur avec mot de passe + Liste des propriétés de recherche + Stratégies de sécurité + Prédicats de sécurité + Rôle de serveur + Listes des propriétés de recherche + Index de stockage de colonnes + Index de types de tables + Index XML sélectifs + Espaces de noms XML + Chemins d'accès promus typés XML + Chemins d'accès promus typés T-SQL + Informations d'identification incluses dans l'étendue de la base de données + Sources de données externes + Formats de fichier externes + Ressources externes + Tables externes + Clés Always Encrypted + Clés principales de la colonne + Clés de chiffrement de la colonne + Serveur + Erreur en analysant la propriété ScriptingParams.ConnectionString. + Répertoire invalide spécifié pour la propriété ScriptingParams.FilePath. + Erreur en analysant la propriété ScriptingListObjectsCompleteParams.ConnectionString. + {0} ({1}, {2}, {3}) + Pas de valeur par défaut + Entrée + Entrée/sortie + Entrée/ReadOnly + Entrée/sortie/ReadOnly + Par défaut + Null + Non Null + {0} ({1}, {2}) + {0} ({1}) + {0} ({1}Calculé, {2}, {3}) + {0} ({1}Calculé) + {0} (Jeu de colonnes, {1}) + {0} (Jeu de colonnes, {1}{2}, {3}) + {0} (Jeu de colonnes, {1}, {2}, {3}) + Unique + Non unique + Ordonné en clusters + Non-Clustere + Historique + System-Versioned + Indisponible + Groupe de fichiers par défaut actuel : {0} + Nouveau groupe de fichiers pour {0} + Par défaut + Fichiers + Nom + Lecture seule + Redimensionnement automatique / Taille max + ... + <par défaut> + Groupe de fichiers + Nom logique + Type de fichier + Taille initiale (Mo) + <new filegroup> + Chemin d'accès + Nom de fichier  + <raw device> + Bulk-logged + Full + Simple + Sélectionner le propriétaire de base de données + Aucune + Par {0} Mo, Limité à {1} Mo + Par {0} %, Limité à {1} Mo + Par {0} Mo, Illimité + Par {0} %, Illimité + Illimité + Limité à {0} Mo + Automatique + Service Broker + Classement + Curseur + Divers + Restauration + État + Paramètre par défaut ANSI NULL + Valeurs ANSI NULLS activées + Padding ANSI activé + ANSI Warnings activés + Annulation arithmétique (Arithmetic Abort) activée + Fermeture automatique + Création automatique des statistiques + Réduction automatique + Mise à jour automatique des statistiques + Mise à jour automatique des statistiques en mode asynchrone + Sensible à la casse + Fermeture du curseur lors de la validation activée + Classement + La concaténation de la valeur Null donne Null + Niveau de compatibilité de la base de données + État de la base de données + Curseur par défaut + Indexation de texte intégral activée + Abandon en cas d'arrondi numérique + Vérification de la page : + Identificateurs entre guillemets activés + Base de données en lecture seule + Déclencheurs récursifs activés + Restreindre l'accès + Select Into / Bulk Copy + Priorité du service Broker respectée + Identifant de Service Broker + Broker activé + Truncate Log on Checkpoint + Chaînage des propriétés des bases de données croisées activé + Digne de confiance + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + Forcé + Simple + Données ROWS + LOG + Données FILESTREAM + Non applicable + <default path> + Ouvrir les connexions + Pour changer les propriétés de la base de données, SQL Server doit fermer toutes les autres connexions à la base de données. Etes-vous sûr de vouloir changer les propriétés et fermer toutes les autres connexions ? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + Format de stockage VarDecimal activé + SQL Server 2008 (100) + Chiffrement activé + OFF + ON + PRIMARY + Pour la politique de distribution HASH, le nombre de colonnes hash qui débutent est optionnel mais devrait être entre 1 et 16 colonnes. + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Aucun + Partiel + Fichiers FILESTREAM + Aucun groupe de fichiers applicable + La base de données {0} est inaccessible. + La requête n'a aucun résultat à retourner + Le jeu de résultats a trop de lignes pour être chargé en toute sécurité + Paramétrage + La spécification de cette option lors de la restauration d'une sauvegarde avec l'option NORECOVERY n'est pas permise. + Chemin d'accès non valide pour le fichier de base de données : « {0} » + Journal + Échec de la création du plan de restauration + La restauration de la base de données n'est pas supportée + Restaurer la base de données + (Copie seule) + Composant + Type + Serveur  + Base de données  + Position + Premier NSE + Dernier NSE + NSE du point de contrôle + Tous les NSE + Date de début + Date de fin + Taille + Nom d'utilisateur  + Expiration  + Nom  + La dernière sauvegarde effectuée ({0}) + Sauvegarder la base de données + Opération en cours + Terminé + script + Connexion introuvable + Le nom de fichier spécifié est également un nom de répertoire: {0} + Impossible de vérifier l'existence de l'emplacement du fichier de sauvegarde: {0} + Impossible d'accéder au chemin d'accès spécifié sur le serveur: {0} + Aucun jeu de sauvegarde n'a été sélectionné pour être restauré. + Jamais + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL Stretch Database + Le chemin {0} n'est pas un répertoire valide. + Pour le répertoire {0} un fichier avec le nom {1} existe déjà + La valeur {0} est trop grande pour tenir dans la colonne de type {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.it.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.it.resx new file mode 100644 index 0000000000..bbe62882dc --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.it.resx @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Parametri di connessione non possono essere null + OwnerUri non può essere null o vuoto + SpecifiedUri: '{0}' non dispone di connessione esistente + Valore non valido: '{0}' per AuthenticationType. I valori validi sono 'Integrated' e 'SqlLogin'. + Valore '{0}' non valido per ApplicationIntent. I valori validi sono 'ReadWrite' e 'ReadOnly'. + Connessione annullata + OwnerUri non può essere null o vuoto + L'oggetto Dettagli di connessione non può essere null + ServerName non può essere null o vuoto + {0} non può essere null o vuoto quando si utilizza l'autenticazione SqlLogin + La query è già stata completata e non può essere annullata + Query annullata correttamente, impossibile eliminare query. URI proprietario non trovato. + Query annullata dall'utente + Il batch non è ancora stato completato + Indice di batch non può essere minore di 0 o maggiore del numero di batch + Indice di set di risultati non può essere minore di 0 o maggiore del numero di set di risultati + Numero massimo di byte da restituire deve essere maggiore di zero + Numero massimo di caratteri da restituire deve essere maggiore di zero + Numero massimo di byte XML da restituire deve essere maggiore di zero + Il metodo di accesso non può essere in sola scrittura + FileStreamWrapper deve essere inizializzato prima di eseguire operazioni + Questo FileStreamWrapper non può essere utilizzato per la scrittura + (1 riga interessata) + ({0} righe interessate) + Comandi completati correttamente. + Msg {0}, Livello {1}, Stato {2}, Riga {3} {4} {5} + Query non riuscita: {0} + (Nessun nome di colonna) + La query richiesta non esiste + Questo editor non è connesso a un database + Una query è già in corso per questa sessione dell'editor. Annullare la query o attendere il completamento. + Mittente per l'evento OnInfoMessage deve essere un oggetto SqlConnection + Non è possibile salvare il risultato finché non viene completata l'esecuzione della query + Errore interno durante l'avvio del task di salvataggio + È in corso una richiesta di salvataggio sullo stesso percorso + Impossibile salvare {0}: {1} + Impossibile leggere sottoinsieme a meno che i risultati sono stati letti dal server + Riga di inizio non può essere minore di 0 o maggiore del numero di righe nel set di risultati + Il numero di righe deve essere un numero intero positivo + Impossibile recuperare schema di colonne per set di risultati + Impossibile recuperare un piano di esecuzione dal set di risultati + Questa funzionalità non è supportata su DB SQL Azure e Data Warehouse: {0} + Si è verificato un errore imprevisto durante l'esecuzione di definizione Peek: {0} + Nessun risultato trovato. + Non è stato recuperato alcun oggetto di database. + Connettersi a un server. + Timeout dell'operazione. + Questo tipo di oggetto non è supportato da questa funzionalità. + La posizione non rientra nell'intervallo di righe del file + Posizione non rientra nell'intervallo di colonne per riga {0} + Posizione iniziale ({0}, {1}) deve essere precedente o uguale alla posizione finale ({2}, {3}) + Msg. {0}, Livello {1}, Stato {2}, Riga {3} + Msg. {0}, Livello {1}, Stato {2}, Procedura {3}, Riga {4} + Msg. {0}, Livello {1}, Stato {2} + Si è verificato un errore durante l'elaborazione batch. Messaggio di errore: {0} + ({0} righe interessate dall'operazione) + L'esecuzione precedente non è ancora completa. + Si è verificato un errore di scripting. + Sintassi errata rilevata durante l'analisi di '{0}'. + Si è verificato un errore irreversibile. + Esecuzione completata {0} volte... + È stata annullata la query. + Si è verificato un errore durante l'esecuzione del batch. + Si è verificato un errore durante l'esecuzione del batch, ma l'errore è stato ignorato. + Beginning execution loop + Il comando {0} non è supportato. + Impossibile trovare la variabile {0}. + Errore di esecuzione di SQL: {0} + Esecuzione del wrapper parser batch: trovati {0}... alla riga {1}: {2} Descrizione: {3} + Motore di esecuzione wrapper parser di batch, ricevuto messaggio batch: messaggio: {0} messaggio dettagliato: {1} + Motore di esecuzione wrapper parser di batch, elaborazione batch di ResultSet: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Motore di esecuzione wrapper parser di batch, batch di ResultSet completato. + Annullamento dell'esecuzione batch del wrapper parser batch. + Avviso di script. + Per ulteriori informazioni su questo errore, vedere gli argomenti sulla risoluzione dei problemi nella documentazione del prodotto. + File '{0}' incluso ricorsivamente. + Marker ' * /' di fine commento mancante. + Virgolette mancanti alla fine della stringa di caratteri. + Sintassi errata rilevata durante l'analisi di '{0}'. + Variabile {0} non è definita. + test + Sostituzione di una stringa vuota con una stringa vuota. + La sessione di editing non esiste. + Esecuzione query non completata + La query non ha generato esattamente un insieme di risultati + Errore nell'aggiunta di una riga durante l'aggiornamento della cache + L'ID riga specificato è fuori dal range di righe della cache della modifica + Un aggiornamento di questa riga è già in corso e dev'essere annullato prima di procedere + Questo ID di riga non ha aggiornamenti in corso + Metadati della tabella o della vista non trovati + Formato non valido per una colonna binaria + Colonne booleane devono contenere valori numerici 0 o 1, o stringhe true o false + Il valore di cella richiesto è mancante + La cancellazione di questa riga è in corso, impossibile aggiornare la cella. + L'ID della colonna dev'essere incluso nel range delle colonne della query + Impossibile modificare la colonna + Impossibile trovare colonne chiave + Occorre fornire un nome di file di output + L'oggetto {0} del database non può essere usato per la modifica. + L'URI specificato '{0}' non ha una connessione di default + Azione commit in corso - attenderne il completamento. + Precisione o scala mancante nella colonna Decimal + <TBD> + Impossibile aggiungere una riga al buffer risultati - il datareader non contiene righe + I valori della colonna Time devono essere compresi tra 00:00:00.0000000 e 23:59:59.9999999 + NULL non è consentito per questa colonna + La sessione di editing esiste già. + La sessione di editing non è stata inizializzata. + La sessione di editing è già stata inizializzata. + La sessione di editing è già stata inizializzata o è in fase di inizializzazione + Esecuzione della query fallita - vedere i messaggi per ulteriori dettagli + Il limite del risultato non può essere negativo + NULL + Il nome dell'oggetto è obbligatorio + Non è possibile specificare in modo esplicito il nome di un server o di un database + Nessuna proprietà estesa per la tabella + Impossibile trovare la Tabella o la Vista necessarie alla modifica + Errore durante l'espansione dell'oggetto: {0} + Errore durante la connessione a {0}' + Aggregazioni + Ruoli del server + Ruoli applicazione + Assembly + File di assembly + Chiavi asimmetriche + Chiavi asimmetriche + Opzioni di compressione dati + Certificati + Tabelle file + Certificati + Vincoli CHECK + Colonne + Vincoli + Contratti + Credenziali + Messaggi di errore + Appartenenze al ruolo del server + Opzioni database + Ruoli database + Appartenenze a ruoli + Trigger database + Vincoli predefiniti + Impostazioni predefinite + Sequenze + Endpoint + Notifiche degli eventi + Notifiche degli eventi server + Proprietà estese + Filegroup + Chiavi esterne + Cataloghi full-text + Indici full-text + Funzioni + Indici + Funzioni inline + Chiavi + Server collegati + Accessi server collegato + Accessi + Chiave master + Chiavi master + Tipi di messaggio + Funzioni con valori di tabella + Parametri + Funzioni di partizione + Schemi di partizione + Autorizzazioni + Chiavi primarie + Programmazione + Code + Associazioni a servizi remoti + Colonne restituite + Ruoli + Route + Regole + Schemi + Sicurezza + Oggetti server + Gestione + Trigger + Service Broker + Servizi + Firme + File di log + Statistiche + Archiviazione + Stored procedure + Chiavi simmetriche + Sinonimi + Tabelle + Trigger + Tipi + Chiavi univoche + Tipi di dati definiti dall'utente + Tipi definiti dall'utente (UDT) (CLR) + Utenti + Viste + Indici XML + Raccolte XML Schema + Tipi di tabella definiti dall'utente + File + Didascalia mancante + Priorità di Service Broker + Provider del servizio di crittografia + Specifiche di controllo database + Chiavi di crittografia database + Sessioni eventi + Elenchi di parole non significative full-text + Pool di risorse + Controlli + Specifiche controllo server + Indici spaziali + Gruppi del carico di lavoro + File SQL + Funzioni server + Tipo SQL + Opzioni server + Diagrammi di database + Tabelle di sistema + Database + Contratti di sistema + Database di sistema + Tipi di messaggi di sistema + Code di sistema + Servizi di sistema + Stored procedure di sistema + Viste di sistema + Applicazioni livello dati + Stored procedure estese + Funzioni di aggregazione + Valori numerici approssimati + Stringhe binarie + Stringhe di caratteri + Tipi di dati CLR + Funzioni di configurazione + Funzioni per i cursori + Tipi di dati di sistema + Data e ora + Funzioni di data e ora + Valori numerici esatti + Funzioni di sistema + Funzioni di ID di gerarchia + Funzioni matematiche + Funzioni per i metadati + Altri tipi di dati + Altre funzioni + Funzioni per i set di righe + Funzioni di sicurezza + Tipi di dati spaziali + Funzioni per i valori stringa + Funzioni statistiche di sistema + Funzioni per i valori text e image + Stringhe di caratteri Unicode + Funzioni di aggregazione + Funzioni a valori scalari + Funzioni con valori di tabella + Stored procedure estese di sistema + Tipi predefiniti + Ruoli del server predefiniti + Utente con password + Elenco delle proprietà di ricerca + Criteri di sicurezza + Predicati di sicurezza + Ruolo del server + Elenchi delle proprietà di ricerca + Indici dell'archivio colonne + Indici del tipo di tabella + Indici XML selettivi + Spazi dei nomi XML + Percorsi promossi con tipizzazione XML + Percorsi promossi con tipizzazione T-SQL + Credenziali con ambito database + Origini dati esterne + Formati di file esterni + Risorse esterne + Tabelle esterne + Chiavi Always Encrypted + Chiavi master della colonna + Chiavi di crittografia della colonna + Server + Errore durante l'analisi della proprietà ScriptingParams.ConnectionString. + La Directory specificata dalla proprietà ScriptingParams.FilePath non è valida. + Errore durante l'analisi della proprietà ScriptingListObjectsCompleteParams.ConnectionString. + {0} ({1}, {2}, {3}) + Nessun valore predefinito + Input + Input/Output + Input/ReadOnly + Input/Output/ReadOnly + Predefinito + Null + non Null + {0} ({1}, {2}) + {0} ({1}) + {0} ({1} calcolato, {2}, {3}) + {0} ({1} calcolato) + {0} (Set di colonne: {1}) + {0} (Set di colonne: {1} {2}, {3}) + {0} (Set di colonne: {1}, {2}, {3}) + Univoco + Non univoco + Cluster + Non cluster + Cronologia + Con controllo delle versioni di sistema + Non disponibile + Filegroup predefinito corrente: {0} + Nuovo Filegroup per {0} + Predefinito + File + Nome + Sola lettura + Aumento automatico / Maxsize + ... + <predefinito> + Filegroup + Nome logico + Tipo di file + Dimensioni iniziali (MB) + <nuovo Filegroup> + Percorso + Nome file + <dispositivo RAW> + Registrazione delle operazioni bulk + Completo + Semplice + Seleziona il proprietario del Database + Nessuno + Di {0} MB, limitato a {1} MB + Di {0} percento, limitato a {1} MB + Di {0} MB, illimitato + Di {0} percento, illimitato + Senza limiti + Limitato a {0} MB + Automatico + Service Broker + Regole di confronto + Cursore + Varie + Recupero + Stato + Impostazione predefinita ANSI NULL + ANSI NULLS abilitati + ANSI Padding abilitato + Avvisi ANSI abilitati + Arithmetic Abort abilitata + Chiusura automatica + Creazione statistiche automatica + Compattazione automatica + Aggiornamento statistiche automatico + Aggiornamento statistiche asincrono automatico + Distinzione maiuscole/minuscole + Chiusura cursore in caso di commit abilitata + Regole di confronto + La concatenazione di valori Null restituisce valori Null + Livello di compatibilità del database + Stato database + Cursore predefinito + Indicizzazione full-text + Interruzione per perdita di precisione numerica + Verifica pagina + Identificatori delimitati abilitati + Database di sola lettura + Trigger ricorsivi abilitati + Limitazione accesso + Select Into/Bulk Copy + Rispetta priorità di Service Broker + Identificatore Service Broker + Broker abilitato + Tronca Log al Checkpoint + Concatenamento della proprietà tra database abilitato + Trustworthy + Ottimizzazione correlazione date Enabledprototype_db_prop_parameterization = parametrizzazione + Forzato + Semplice + Dati RIGHE + LOG + Dati FILESTREAM + Non applicabile + <percorso predefinito> + Connessioni aperte + Per modificare le proprietà del database, SQL Server deve chiudere tutte le altre connessioni al database_ Sei sicuro di voler modificare le proprietà e chiudere tutte le altre connessioni? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + Formato di archiviazione VarDecimal abilitato + SQL Server 2008 (100) + Crittografia abilitata + OFF + ON + PRIMARY + Per il criterio di distribuzione HASH, il numero di colonne iniziali di hash è facoltativo, ma dovrebbe essere da 1 a 16 colonne + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Nessuno + Parziale + File FILESTREAM + Nessun Filegroup applicabile + Il database {0} non è accessibile. + La query non ha risultati da restituire + L'insieme di risultati ha troppe righe per essere caricato in modo sicuro + Parametrizzazione + Non è consentito specificare questa opzione quando si ripristina un backup con NORECOVERY. + Percorso non valido per il file di database: '{0}' + Log + Impossibile creare un piano di ripristino. + Ripristino del database non supportato. + Ripristina Database + (Sola Copia) + Componente + Tipo + Server + Database + Posizione + Primo LSN + Ultimo LSN + LSN di checkpoint + LSN completo + Data di inizio + Data di fine + Dimensione + Nome utente + Scadenza + Nome + L'ultimo backup effettuato ({0}) + Backup database + In corso + Completato + scripting + Connessione non trovata + Il nome file specificato è anche un nome di cartella: {0} + Impossibile verificare l'esistenza della posizione del file di backup: {0} + Impossibile accedere al percorso specificato sul server: {0} + Nessun insieme di backup selezionato per il ripristino + Mai + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL Stretch Database + Il percorso [{0}] non è una directory valida. + Nella directory '{0}' esiste già il file {1} + Il valore {0} è troppo grande per essere contenuto in una colonna di tipo {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ja.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ja.resx new file mode 100644 index 0000000000..8464e2a40a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ja.resx @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089接続パラメーターを null にすることはできません。 + OwnerUri を null または空にすることはできません。 + SpecifiedUri '{0}' には、既存の接続はありません。 + AuthenticationType の値 '{0}' が無効です。有効な値は 'Integrated' または 'SqlLogin' です。 + ApplicationIntent の値 '{0}' が無効です。有効な値は 'ReadWrite' または 'ReadOnly' です。 + 接続がキャンセルされました。 + OwnerUri を null または空にすることはできません。 + 接続の詳細オブジェクトを null にすることはできません。 + ServerName を null または空にすることはできません。 + SqlLogin 認証を使用する場合に、{0} を null または空にすることはできません。 + クエリは既に完了して、取り消すことができません。 + クエリのキャンセルに成功しましたが、クエリの処理に失敗しました。OwnerURIが見つかりません。 + クエリは、ユーザーによってキャンセルされました + バッチがまだ完了していません、 + バッチのインデックスは、0 未満あるいは、バッチの数より大きい値にすることはできません。 + 結果セットのインデックスは、0 未満あるいは、結果セットの数より大きい値にすることはできません + 戻り値の最大バイト数は 0 より大きくする必要があります。 + 戻り値の最大文字数は 0 より大きくする必要があります。 + 戻り値の最大のXMLバイト数は 0 より大きくする必要があります。 + アクセス メソッドを書き込み専用にすることはできません。 + FileStreamWrapper は、操作を実行する前に初期化されなければなりません。 + この FileStreamWrapper は、書き込みには利用できません。 + (1 件処理されました) + ({0} 行処理されました) + コマンドが正常に完了しました。 + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + クエリに失敗しました: {0} + (列名なし) + 要求されたクエリは存在しません + このエディターは、データベースに接続されていません。 + このエディターのクエリは既に実行中です。クエリをキャンセルするか完了まで待って下さい。 + OnInfoMessage イベントのSenderは、SqlConnectionである必要があります。 + クエリの実行が完了するまで、結果を保存することはできません。 + 保存タスクの開始中に内部エラーが発生しました。 + 同一のパスへの保存リクエストを実行中です。 + {0} を保存できませんでした: {1} + サーバーから結果が受信されていないため、サブセットを読み取ることができません。 + 開始行は 0 未満か、結果セット内の行数より大きい値にすることはできません。 + 行数は正の整数でなければなりません。 + 結果セットの列のスキーマを取得できませんでした。 + 結果セットから実行プランを取得できませんでした。 + この機能はAzure SQL DBとData Warehouseでは、現在サポートされていません: {0} + Peek Definitionの実行中に予期しないエラーが発生しました: {0} + 結果は見つかりませんでした。 + データベース オブジェクトを取得できませんでした。 + サーバーに接続してください。 + 操作がタイムアウトになりました。 + このオブジェクトの種類は現在この機能ではサポートされていません。 + 位置がファイルの行の範囲外です。 + 位置が行 {0} の列の範囲外です。 + 開始位置 ({0}, {1}) は、終了位置 ({2}, {3}) より前、または同じでなければなりません。 + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0}, Level {1}, State {2} + バッチを処理中にエラーが発生しました。エラー メッセージ: {0} + ({0} 件処理されました) + 前回の実行がまだ完了していません。 + スクリプト エラーが発生しました。 + {0} の解析中に不正な構文が見つかりました。 + 致命的なエラーが発生しました。 + 実行を {0} 回完了しました... + クエリをキャンセルしました。 + バッチの実行中にエラーが発生しました。 + バッチの実行中にエラーが発生しましたが、エラーを無視しました。 + Beginning execution loop + コマンド {0} はサポートされていません。 + 変数 {0} が見つかりませんでした。 + SQL の実行エラー: {0} + バッチ パーサー ラッパーの実行: 行 {1}: {2} で {0} を検出... 説明: {3} + バッチ パーサー ラッパー実行エンジンのバッチ メッセージを受信しました: メッセージ: {0} 詳細メッセージ: {1} + バッチ パーサー ラッパー実行エンジンのバッチ ResultSet 処理: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + バッチ パーサー ラッパー実行エンジンのバッチ ResultSet が終了しました。 + バッチ パーサー ラッパーのバッチ実行をキャンセルしています。 + スクリプトの警告。 + このエラーの詳細については、製品ドキュメントのトラブルシューティングに関するトピックを参照してください。 + ファイル '{0}' が再帰的に含まれています。 + '*/' でマークされたコメントの終端がありません。 + 文字列の引用符が閉じていません。 + '{0}' の解析中に無効な構文が見つかりました。 + 変数 {0} が定義されていません。 + テスト + 空の文字列で空の文字列を置換しています。 + 編集セッションは存在しません。 + クエリの実行が完了していません。 + クエリは 1 つの結果セットを生成できませんでした。 + キャッシュを更新する新しい行を追加できませんでした。 + 与えられた行IDは、編集キャッシュに存在する行の範囲外です。 + この行に対する更新がすでに保留されています。まず更新を戻す必要があります。 + 与えられた行IDには保留中の更新はありません。 + テーブルまたはビューのメタデータが見つかりませんでした。 + バイナリ列の形式が無効です。 + ブール列の型は1もしくは0の数値、または true もしくは false の文字列でなければいけません。 + 必須なセルの値が入力されていません。 + この行の削除が保留中であるため、セルの更新は適用できません。 + 列 ID がクエリの列の範囲である必要があります。 + 列を編集できません。 + キー列が見つかりませんでした。 + 出力ファイル名を指定する必要があります。 + データベース オブジェクト {0} は、編集のため使用できません。 + 指定された URI '{0}' には既定の接続はありません。 + コミット処理は実行中です。完了するまで待機してください。 + Decimal 型の列に有効桁数もしくは小数点以下桁数のどちらかが存在していません。 + <TBD> + 結果バッファーへ行を追加できません。データリーダーは行を含んでいません。 + time 型の値は 00:00:00.0000000 と 23:59:59.9999999 の範囲内になければなりません。 + この列では NULL は許可されていません。 + 編集セッションがすでに存在します。 + 編集セッションが初期化されていません。 + 編集セッションはすでに初期化されました。 + 編集セッションはすでに初期化されたか、初期化中です。 + クエリーの実行が失敗しました。詳細メッセージを確認してください。 + 結果の上限は負の値にできません。 + NULL + オブジェクトの名前を指定する必要があります。 + 明示的なサーバーもしくはデータベースの指定はサポートされていません。 + テーブルメタデータは拡張プロパティを持っていません。 + 編集を要求したテーブルもしくはビューが見つかりませんでした。 + '{0}' の拡張中にエラーが発生しました。 + {0} への接続中にエラーが発生しました + 集約 + サーバー ロール + アプリケーション ロール + アセンブリ + アセンブリ ファイル + 非対称キー + 非対称キー + データ圧縮オプション + 証明書 + ファイルテーブル + 証明書 + CHECK 制約 + + 制約 + コントラクト + 資格情報 + エラー メッセージ + サーバー ロール メンバーシップ + データベース オプション + データベース ロール + ロール メンバーシップ + データベース トリガー + 既定の制約 + 既定値 + シーケンス + エンドポイント + イベント通知 + サーバー イベント通知 + 拡張プロパティ + ファイル グループ + 外部キー + フルテキスト カタログ + フルテキスト インデックス + 関数 + インデックス + インライン関数 + キー + リンク サーバー + リンク サーバー ログイン + ログイン + マスター キー + マスター キー + メッセージ型 + テーブル値関数 + パラメーター + パーティション関数 + パーティション構成 + アクセス許可 + 主キー + プログラミング + キュー + リモート サービスのバインド + 返された列 + ロール + ルート + ルール + スキーマ + セキュリティ + サーバー オブジェクト + 管理 + トリガー + Service Broker + サービス + 署名 + ログ ファイル + 統計 + ストレージ + ストアド プロシージャ + 対称キー + シノニム + テーブル + トリガー + + 一意キー + ユーザー定義データ型 + ユーザー定義型 (CLR) + ユーザー + ビュー + XML インデックス + XML スキーマ コレクション + ユーザー定義テーブル型 + ファイル + キャプションが見つかりません + Broker の優先度 + 暗号化プロバイダー + データベース監査の仕様 + データベース暗号化キー + イベント セッション + フルテキスト ストップリスト + リソース プール + 監査 + サーバー監査の仕様 + 空間インデックス + ワークロード グループ + SQL ファイル + サーバー関数 + SQL 型 + サーバー オプション + データベース ダイアグラム + システム テーブル + データベース + システム コントラクト + システム データベース + システム メッセージの種類 + システム キュー + システム サービス + システム ストアド プロシージャ + システム ビュー + データ層アプリケーション + 拡張ストアド プロシージャ + 集計関数 + 概数 + バイナリ文字列 + 文字列 + CLR データ型 + 構成関数 + カーソル関数 + システム データ型 + 日付と時刻 + 日付と時刻関数 + 真数 + システム関数 + 階層 ID 関数 + 数学関数 + メタデータ関数 + その他のデータ型 + その他の関数 + 行セット関数 + セキュリティ関数 + 空間データ型 + 文字列関数 + システム統計関数 + テキストとイメージ関数 + Unicode 文字列 + 集計関数 + スカラー値関数 + テーブル値関数 + システム拡張ストアド プロシージャ + ビルトイン型 + 組み込みのサーバー ロール + ユーザーとパスワード + 検索プロパティ リスト + セキュリティ ポリシー + セキュリティ述語 + サーバー ロール + 検索プロパティ リスト + 列のストア インデックス + テーブル型インデックス + 選択的 XML インデックス + XML 名前空間 + XML の型指定された昇格パス + T-SQL の型指定された昇格パス + データベース スコープ資格情報 + 外部データ ソース + 外部ファイル形式 + 外部リソース + 外部テーブル + Always Encrypted キー + 列マスター キー + 列暗号化キー + サーバー + ScriptingParams.ConnectionString プロパティの解析エラーです。 + ScriptingParams.FilePath プロパティで指定されたディレクトリが無効です。 + ScriptingListObjectsCompleteParams.ConnectionString プロパティの解析エラーです。 + {0} ({1}、{2}、{3}) + 既定値以外 + 入力 + 入力/出力 + 入力/読み取り専用 + 入力/出力/読み取り専用 + 既定値 + NULL + NULL 以外 + {0} ({1}、{2}) + {0} ({1}) + {0} ({1} 計算値、{2}、{3}) + {0} ({1} 計算値) + {0} (列セット、{1}) + {0} (列セット、{1}{2}、{3}) + {0} (列セット、{1}、{2}、{3}) + 一意 + 一意でない + クラスター化 + 非クラスター + 履歴 + システムバージョン管理 + 使用不可 + 現在の既定のファイル グループ: {0} + 新しいファイルグループ {0} + 既定値 + ファイル + 名前 + 読み取り専用 + 自動拡張 / 最大容量 + ... + <既定> + ファイル グループ + 論理名 + ファイルタイプ + 初期サイズ (MB) + <新しいファイルグループ> + パス + ファイル名 + <RAWデバイス> + 一括ログ + 完全 + 単純 + データベース 所有者の選択 + なし + {0} MBごと、{1} MBを上限 + {0} パーセントごと、{1} MBまで + {0} MBごと、無制限 + {0} パーセントごと、無制限 + 無制限 + {0} MBまで + 自動 + Service Broker + 照合順序 + カーソル + その他 + 復旧 + 状態 + ANSI NULL 既定値 + ANSI NULLS 有効 + ANSI Padding 有効 + ANSI 警告有効 + 算術アボート有効 + 自動クローズ + 統計の自動作成 + 自動圧縮 + 統計の自動更新 + 統計の非同期的自動更新 + 大文字と小文字を区別する + コミットでカーソルを閉じる + 照合順序 + Nullとの連結をNullとして取り扱う + データベース互換性レベル + データベース状態 + 既定のカーソル + フルテキスト インデックス 有効化 + 数値丸め処理アボート + ページ確認 + 引用符で囲まれた識別子が有効 + 読み取り専用データベース + 再帰トリガー有効 + アクセスの制限 + Select Into/ バルクコピー + Broker の優先度の許可 + Service Broker 識別子 + ブローカー有効化 + チェックポイントでのログの切り捨て + 複数データベースの組み合わせ所有権有効 + 信頼可能 + データ相関性の最適化 +Enabledprototype_db_prop_parameterization = Parameterization + 強制 + 単純 + 列データ + ログ + FILESTREAM データ + 適用不可 + <既定のパス> + コネクションを開く + データベースのプロパティを変更するには、SQL Server はデータベースへの他のすべての接続を閉じる必要があります。プロパティを変更して、他のすべての接続を閉じてよろしいですか? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + VarDecimal ストレージ形式有効 + SQL Server 2008 (100) + 暗号化有効 + OFF + ON + PRIMARY + 配布ポリシーのハッシュでは、ハッシュの先頭列の番号は任意ですが、1 から 16 個の列にする必要があります + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + なし + 部分的 + FILESTREAM ファイル + 適用不可なファイルグループ + データベース {0} にアクセスできません。 + クエリーは結果を返しませんでした + 結果セットの行数が多すぎるため安全にロードすることはできません + パラメーター化 + NORECOVERY オプションを使用してバックアップを復元するときにこのオプションを指定することはできません。 + データベース ファイルのパスが無効です: '{0}' + ログ + リストア プランの作成に失敗しました。 + データベースのリストアはサポートされていません。 + データベースのリストア + (コピーのみ) + コンポーネント + 種類 + サーバー + データベース + 位置 + 最初の LSN + 最後の LSN + チェックポイントの LSN + 全 LSN + 開始日 + 完了日 + サイズ + ユーザー名 + 有効期限 + 名前 + 最後に作成されたバックアップ ({0}) + データベースをバックアップする + 実行中 + 完了 + スクリプト + 接続が見つかりません。 + 指定されたファイル名がディレクトリ名と同じです: {0} + バックアップ ファイルの場所が存在するかどうか確認できません: {0} + サーバーで指定されたパスにアクセスできません: {0} + リストアするバックアップセットが選択されていません + 行わない + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL Stretch Database + パス {0} は有効なディレクトリではありません + ディレクトリ {0} 内に {1} という名前のファイルは既に存在します + 値 {0} は大きすぎるため、型 {1} の列に収まりません + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ko.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ko.resx new file mode 100644 index 0000000000..7d4e551fb9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ko.resx @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089연결 매개 변수는 null 일 수 없습니다. + OwnerUri은 null 이거나 비어 있을 수 없습니다. + SpecifiedUrl '{0}'는 기존 연결이 없습니다. + AuthenticationType 값으로 ' {0} '이 (가) 잘못 되었습니다. 유효한 값은 'Integrated'나 'SqlLogin' 입니다. + ApplicationIntent 값으로 ' {0} '이 (가) 잘못 되었습니다. 유효한 값은 'ReadWrite'나 'ReadOnly' 입니다. + 연결이 취소되었습니다. + OwnerUri는 null 이나 빈값일 수 없습니다 + 연결 세부 정보 개체는 null이 될 수 없습니다. + 서버 이름은 null이거나 비어 있을 수 없습니다. + SqlLogin 인증 사용 시 {0}은(는) null이나 빈값일 수 없습니다. + 쿼리가 이미 완료되어 취소할 수 없습니다. + 쿼리 취소가 완료되었으나 쿼리를 삭제하는데 실패했습니다. Owner URI를 찾을 수 없습니다. + 사용자가 쿼리를 취소 했습니다. + 일괄 처리가 아직 완료되지 않았습니다. + 일괄 처리 인덱스는 0 미만 이거나 일괄 처리 갯수 보다 클 수 없습니다. + 결과 집합 인덱스는 0 미만 이거나 결과 집합의 갯수보다 클 수 없습니다. + 반환되는 최대 바이트 수는 0보다 커야 합니다. + 반환되는 최대 문자 수는 0보다 커야 합니다. + 반환되는 최대 XML 바이트 수는 0보다 커야 합니다. + 액세스 방법은 쓰기 전용이 될 수 없습니다. + FileStreamWrapper 는 작업을 수행 하기 전에 초기화 해야 합니다. + FileStreamWrapper 는 쓰기용으로 사용할 수 없습니다. + (1 개 행이 영향을 받음) + ({0} 개 행이 영향을 받음) + 명령이 성공적으로 완료 되었습니다. + 메시지 {0}, 수준 {1}, 상태 {2}, 줄 {3} {4} {5}. + 쿼리 실패: {0} + (열 이름 없음) + 요청한 쿼리가 존재하지 않습니다. + 편집기가 데이터베이스에 연결되지 않았습니다. + 쿼리가 현재 편집기 세션에서 이미 실행 중입니다. 쿼리를 취소하거나 완료 될 때까지 대기 하십시오. + OnInfoMessage 이벤트 발신자는 SqlConnection 이어야 합니다. + 결과는 쿼리 실행이 완료 될 때까지 저장할 수 없습니다. + 저장 작업을 시작 하는 동안 내부 오류가 발생 했습니다. + 동일한 경로로 저장 요청이 진행 중입니다. + 저장 실패 {0}:{1} + 서버로부터 결과를 모두 읽기 전에는 일부 결과를 읽을 수 없습니다. + 시작 행은 0 미만이거나 결과 집합의 행의 갯수보다 클 수 없습니다. + 행 수는 양수여야 합니다. + 결과 집합의 열 스키마를 검색할 수 없습니다. + 결과 집합에서 실행 계획을 검색할 수 없습니다. + 현재 이 기능은 Azure SQL DB와 데이터 웨어하우스에서 지원 되지 않습니다: {0} + 정의 피킹을 실행하는 동안 예상치 못한 오류가 발생했습니다: {0} + 결과가 없습니다. + 검색된 데이터베이스 개체가 없습니다. + 서버에 연결 하십시오. + 작업 제한 시간이 초과 되었습니다. + 현재 이 개체 형식은 지원되지 않습니다. + 위치가 파일 줄 범위를 벗어났습니다. + 위치가 줄 {0} 의 열 범위를 벗어났습니다. + 시작 위치 ({0}, {1})은(는) 반드시 끝 위치 ({2}, {3}) 과 같거나 이전이어야 합니다. + 메시지 {0}, 수준{1}, 상태 {2}, 줄 {3} + 메시지 {0}, 수준 {1}, 상태 {2}, 프로시저 {3}, 줄 {4} + 메시지 {0}, 수준 {1}, 상태 {2} + 일괄 처리를 처리 하는 동안 하는 동안 오류가 발생 합니다. 오류 메시지: {0} + ({0} 개 행이 영향을 받음) + 이전 실행이 아직 완료 되지 않았습니다. + 스크립팅 오류가 발생 했습니다. + {0}에 잘못된 구문이 발견되었습니다. + 치명적인 오류가 발생 했습니다. + {0}회 실행 완료... + 쿼리를 취소 했습니다. + 일괄 처리를 실행 하는 동안 오류가 발생 합니다. + 일괄 처리를 실행 하는 동안 오류가 발생했으나 그 오류는 무시되었습니다. + Beginning execution loop + {0} 명령은 지원되지 않습니다. + {0} 변수를 찾을 수 없습니다. + SQL 실행 오류: {0} + 일괄처리 구문분석 래퍼 실행: {0} 발견... 줄 {1}: {2} 설명: {3} + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 메시지를 받았습니다. 메시지: {0} 자세한 메시지: {1} + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 ResultSet을 처리하고 있습니다. DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 ResultSet을 완료했습니다. + 일괄 처리 파서 래퍼 일괄 처리 실행을 취소하고 있습니다. + 스크립팅 경고. + 이 오류에 대한 추가 정보는 제품 설명서의 문제 해결 항목을 참조하십시오. + ' {0} '이 (가) 재귀적으로 포함 된 파일입니다. + 주석 끝 표시 ' * /' 누락 . + 문자열에 닫히지 않은 인용 부호. + '{0}'을(를) 구문 분석하는 동안 잘못된 구문을 발견했습니다. + {0} 변수가 정의되지 않았습니다. + 테스트 + +votes +빈 문자열을 빈 문자열로 대체. + 편집 세션이 존재하지 않습니다. + 쿼리 실행이 완료되지 않았습니다. + 쿼리가 정확히 하나의 결과 집합을 생성하지 않았습니다. + 업데이트 캐시에 새로운 행 추가를 실패했습니다. + 지정된 row ID가 수정 중인 캐시의 행 범위 밖에 있습니다. + 이 행에 대한 업데이트가 이미 보류 중이므로 먼저 되돌려야 합니다. + 주어진 row ID에 보류 중인 업데이트가 없습니다. + 테이블이나 뷰 메타 데이터를 찾을 수 없습니다. + 이진 열에 형식이 잘못되었습니다. + Boolean 열은 반드시 숫자 1이나 0 혹은 문자 true나 false여야 합니다. + 필수 셀 값이 누락되었습니다. + 행 삭제가 보류 중이므로, 셀을 업데이트할 수 없습니다. + 열 ID는 쿼리의 열 범위 내에 있어야 합니다. + 열을 편집할 수 없습니다. + 키 열이 없습니다. + 출력 파일명이 필요합니다. + 데이터베이스 개체 {0} 는 편집할 수 없습니다. + 지정된 Uri ' {0} '에 기본 연결이 지정되지 않았습니다. + 커밋 작업이 진행 중입니다. 완료될 때까지 기다리세요. + Decimal 형식 열에 전체 자릿수 또는 소수 자릿수가 없습니다. + <TBD> + 결과 버퍼에 새로운 행을 추가할 수 없거나 데이터 리더에 행이 없습니다. + TIME 열의 값은 00:00:00.0000000과 23:59:59.9999999 사이의 값만 허용됩니다. + 이 열은 NULL을 허용하지 않습니다. + 편집 세션이 이미 존재합니다. + 편집 세션이 초기화 되지 않았습니다. + 편집 세션이 이미 초기화 되었습니다. + 편집 세션이 이미 초기화 되었거나 초기화 중입니다. + 쿼리 실행에 실패했습니다. 자세한 정보는 메시지를 참조하세요. + 결과 제한은 음수가 될 수 없습니다. + NULL + 개체 이름이 필요합니다. + 서버와 데이터베이스를 명시적으로 지정할 수 없습니다. + 테이블 메타데이터에 확장 속성이 없습니다. + 편집하려는 테이블이나 뷰를 찾을 수 없습니다 + 오류 확장: {0} + {0}에 연결하는 동안 오류가 발생했습니다. + 집계 + 서버 역할 + 응용 프로그램 역할 + 어셈블리 + 어셈블리 파일 + 비대칭 키 + 비대칭 키 + 데이터 압축 옵션 + 인증서 + FileTables + 인증서 + Check 제약 조건 + + 제약 조건 + 계약 + 자격 증명 + 오류 메시지 + 서버 역할 멤버 자격 + 데이터베이스 옵션 + 데이터베이스 역할 + 역할 멤버 자격 + 데이터베이스 트리거 + 기본 제약 조건 + 기본값 + 시퀀스 + 끝점 + 이벤트 알림 + 서버 이벤트 알림 + 확장 속성 + 파일 그룹 + 외래 키 + 전체 텍스트 카탈로그 + 전체 텍스트 인덱스 + 함수 + 인덱스 + 인라인 함수 + + 연결된 서버 + 연결된 서버 로그인 + 로그인 + 마스터 키 + 마스터 키 + 메시지 유형 + 테이블 반환 함수 + 매개 변수 + 파티션 함수 + 파티션 구성표 + 사용 권한 + 기본 키 + 프로그래밍 기능 + + 원격 서비스 바인딩 + 반환 열 + 역할 + 경로 + 규칙 + 스키마 + 보안 + 서버 개체 + 관리 + 트리거 + Service Broker + 서비스 + 서명 + 로그 파일 + 통계 + 저장소 + 저장 프로시저 + 대칭 키 + 동의어 + 테이블 + 트리거 + 유형 + 고유 키 + 사용자 정의 데이터 형식 + 사용자 정의 형식 (CLR) + 사용자 + + XML 인덱스 + XML 스키마 컬렉션 + 사용자 정의 테이블 형식 + 파일 + 캡션 누락 + 브로커 우선 순위 + 암호화 공급자 + 데이터베이스 감사 사양 + 데이터베이스 암호화 키 + 이벤트 세션 + 전체 텍스트 중지 목록 + 리소스 풀 + 감사 + 서버 감사 사양 + 공간 인덱스 + 작업 그룹 + SQL 파일 + 서버 함수 + SQL 유형 + 서버 옵션 + 데이터베이스 다이어그램 + 시스템 테이블 + 데이터베이스 + 시스템 계약 + 시스템 데이터베이스 + 시스템 메시지 유형 + 시스템 큐 + 시스템 서비스 + 시스템 저장 프로시저 + 시스템 뷰 + 데이터 계층 응용 프로그램 + 확장 저장 프로시저 + 집계 함수 + 근사치 + 이진 문자열 + 문자열 + CLR 데이터 형식 + 구성 함수 + 커서 함수 + 시스템 데이터 형식 + 날짜 및 시간 + 날짜 및 시간 함수 + 정확한 수치 + 시스템 함수 + 계층 구조 ID 함수 + 수학 함수 + 메타데이터 함수 + 기타 데이터 형식 + 기타 함수 + 행 집합 함수 + 보안 함수 + 공간 데이터 형식 + 문자열 함수 + 시스템 통계 함수 + 텍스트 및 이미지 함수 + 유니코드 문자열 + 집계 함수 + 스칼라 반환 함수 + 테이블 반환 함수 + 시스템 확장 저장 프로시저 + 기본 제공 유형 + 기본 제공 서버 역할 + 암호가 있는 사용자 + 검색 속성 목록 + 보안 정책 + 보안 조건자 + 서버 역할 + 검색 속성 목록 + 열 저장 인덱스 + 테이블 형식 인덱스 + 선택적 XML 인덱스 + XML 네임스페이스 + XML 유형의 공유된 경로 + T-SQL 유형의 공유된 경로 + 데이터베이스 범위 자격 증명 + 외부 데이터 원본 + 외부 파일 형식 + 외부 리소스 + 외부 테이블 + Always Encrypted 키 + 열 마스터 키 + 열 암호화 키 + 서버 + ScriptingParams.ConnectionString 속성 분석을 하는 동안 오류가 발생했습니다. + ScriptingParams.FilePath 속성에 잘못된 디렉터리 지정 + ScriptingListObjectsCompleteParams.ConnectionSring 속성을 분석할때 오류가 생겼습니다. + {0}({1}, {2}, {3}) + 기본값 없음 + 입력 + 입/출력 + 입력/읽기 전용 + 입/출력/읽기 전용 + 기본값 + Null + Not Null + {0}({1}, {2}) + {0}({1}) + {0}({1}계산됨, {2}, {3}) + {0}({1}계산됨) + {0}(열 집합, {1}) + {0}(열 집합, {1}{2}, {3}) + {0}(열 집합, {1}, {2}, {3}) + 고유 + 고유하지 않음 + 클러스터형 + 비클러스터형 + 기록 + 시스템 버전 관리 + 사용할 수 없음 + 현재 기본 파일 그룹: {0} + {0}에 대한 새 파일 그룹 + 기본값 + 파일 + 이름 + 읽기 전용 + 자동 증가 / 최대 크기 + ... + <기본값> + 파일 그룹 + 논리적 이름 + 파일 형식 + 처음 크기 (MB) + <새 파일 그룹> + 경로 + 파일 이름 + <원시 장치> + 대량 로그 + 전체 + 단순 + 데이터베이스 소유자 선택 + 없음 + {0} MB 단위로 {1} MB까지 제한됨 + {0} % 단위로 {1} MB까지 제한됨 + {0} MB 단위로, 제한 없음 + {0} % 단위로, 제한 없음 + 제한 없음 + {0} MB로 제한됨 + 자동 + Service Broker + 데이터 정렬 + 커서 + 기타 + 복구 + 상태 + ANSI NULL 기본값 + ANSI NULLS 사용 + ANSI 패딩 설정 + ANSI Warnings 사용 + 산술 연산 중단 설정 + 자동 닫기 + 통계 자동 작성 + 자동 축소 + 통계 자동 업데이트 + 통계를 비동기적으로 자동 업데이트 + 대/소문자 구분 + 커밋 시 커서 닫기 설정 + 데이터 정렬 + Null 연결 시 Null 생성 + 데이터베이스 호환성 수준 + 데이터베이스 상태 + 기본 커서 + 전체 텍스트 인덱싱 설정 + 숫자 반올림 시 중단 + 페이지 확인 + 따옴표 붙은 식별자 설정 + 데이터베이스 읽기 전용 + 재귀적 트리거 설정 + 액세스 제한 + SELECT INTO/대량 복사 + Broker 우선 순위 인식 + Service Broker 식별자 + Broker 활성화 + 검사점에서 로그 자름 + 데이터베이스 간 소유권 체인 사용 + 신뢰 + 날짜 상관관계 최적화 설정 + 강제 + 단순 + ROWS 데이터 + 로그 + FILESTREAM 데이터 + 해당 사항 없음 + <기본 경로> + 연결 열기 + 데이터베이스 속성을 변경하기 위해, SQL Server가 database_ 에  다른 연결을 모두 닫아야 합니다. 속성을 변경하고 다른 연결을 모두 닫으시겠습니까? + AUTO_CLOSED + 긴급 + INACCESSIBLE + NORMAL + 오프라인 + 복구 중 + 복구 보류 중 + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + VarDecimal 저장소 형식 사용 + SQL Server 2008 (100) + 암호화 사용 + OFF + ON + PRIMARY + 배포 정책이 HASH인 경우 선행 해시 열 수는 선택 사항이지만, 선택할 경우 1개에서 16개 사이의 열로 지정해야 합니다. + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + 없음 + 부분 + FILESTREAM 파일 + 해당 파일 그룹 없음 + {0} 데이터베이스에 액세스할 수 없습니다. + 쿼리 반환 결과 없음 + 결과 집합의 행 수가 너무 많아서 안전하게 불러들일 수 없습니다. + 매개 변수화 + NORECOVERY 옵션을 사용하여 백업을 복원하는 동안 이 옵션을 지정할 수 없습니다. + 데이터베이스 파일의 경로가 잘못되었습니다. '{0}' + 로그 + 복원 계획을 만들지 못했습니다 + 데이터베이스 복원은 지원되지 않습니다. + 데이터베이스 복원 + 복사 전용 + 구성 요소 + 형식 + 서버 + 데이터베이스 + 위치 + 첫 번째 LSN + 마지막 LSN + 검사점 LSN + 전체 LSN + 시작 날짜 + 완료 날짜 + 크기 + 사용자 이름 + 만료 + Name + 수행된 마지막 백업({0}) + 데이터베이스 백업 + 진행 중 + 완료됨 + 스크립팅 + 연결 없음 + 지정한 파일 이름은 디렉터리 이름이기도 합니다: {0} + 백업 파일 위치를 확인할 수 없습니다: {0} + 서버에서 지정된 경로에 액세스할 수 없습니다: {0} + 복원하려는 백업 세트를 선택하지 않았습니다 + 안 함 + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL 신축성 데이터베이스 + 경로 [{0}]은(는) 올바른 디렉터리가 아닙니다. + 디렉터리 {0}에 대한 파일{1} 이 이미 존재합니다. + 값 {0}이 너무 커서 {1} 유형의 열에 들어갈 수 없습니다. + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.pt-BR.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.pt-BR.resx new file mode 100644 index 0000000000..92765727a5 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.pt-BR.resx @@ -0,0 +1,490 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Parâmetros de Conexão não podem ser nulos + OwnerUri não pode ser nulo ou vazio + SpecifiedUri '{0}' não há uma conexão existente + Valor inválido '{0}' para AuthenticationType. Os valores válidos são 'Integrada' e 'SqlLogin'. + Valor inválido '{0}' para ApplicationIntent. Os valores válidos são 'ReadWrite' e 'Somente leitura'. + Conexão cancelada + OwnerUri não pode ser nulo ou vazio + Objeto de detalhes de Conexão não pode ser nulo + ServerName não pode ser nulo ou vazio + {0} não pode ser nulo ou vazio quando estiver usando autenticação SqlLogin + A consulta já foi concluída, ela não pode ser cancelada + Consulta cancelada com êxito, Falha ao descartar a consulta. Proprietário do URI não encontrado. + Consulta foi cancelada pelo usuário + O lote ainda não foi concluído. + Índice de lote não pode ser menor que 0 ou maior que o número de lotes + Índice do conjunto de resultados não pode ser menor que 0 ou maior que o número do conjuntos de resultados + Número máximo de bytes a serem retornados deve ser maior que zero + Número máximo de caracteres a serem retornados deve ser maior que zero + Número máximo de bytes XML a serem retornados deve ser maior que zero + Método de acesso não pode ser somente gravação + FileStreamWrapper deve ser inicializado antes de executar operações + Este FileStreamWrapper não pode ser usado para gravação + (1 linha afetada) + ({0} linhas afetadas) + Comandos concluídos com sucesso. + Msg {0}, Nível {1}, Estado {2}, Linha {3} {4} {5} + Falha na consulta: {0} + (Nenhum nome de coluna) + A consulta solicitada não existe. + Este editor não está conectado a um banco de dados + Uma consulta já está em andamento para esta sessão do editor. Favor cancelar esta consulta ou aguardar a sua conclusão + Remetente do evento OnInfoMessage deve ser um SqlConnection + Resultado não pode ser salvo até que seja concluída a execução da consulta + Ocorreu um erro interno ao iniciar tarefa de salvamento + Uma solicitação de salvamento para o mesmo caminho está em andamento + Falha ao salvar {0}: {1} + Não é possível ler o subconjunto, a menos que os resultados tenham sido lidos do servidor + Linha de início não pode ser menor que 0 ou maior que o número de linhas no conjunto de resultados + Contagem de linhas deve ser um inteiro positivo + Não foi possível recuperar o esquema de colunas para o conjunto de resultados + Não foi possível recuperar um plano de execução do conjunto de resultados + Esse recurso não é atualmente suportado no banco de dados de SQL Azure e Data Warehouse: {0} + Ocorreu um erro inesperado durante a execução da inspeção da definição: + Nenhum resultado foi encontrado. + Nenhum objeto de banco de dados foi recuperado. + Favor conectar-se a um servidor. + Tempo limite da operação esgotado. + Este tipo de objeto não é suportado atualmente por esse recurso. + Posição está fora do intervalo de linhas do arquivo + A posição está fora do intervalo de colunas para linha {0} + Posição inicial ({0}, {1}) deve vir antes ou ser igual a posição final ({2}, {3}) + Msg {0}, Nível {1}, Estado {2}, Linha {3} + Msg {0}, Nível {1}, Estado {2}, Procedimento {3}, Linha {4} + Msg {0}, Nível {1}, Estado {2} + Ocorreu um erro durante o processamento do lote. A mensagem de erro é: {0} + ({0} linhas afetadas) + Execução anterior ainda não foi concluída. + Ocorreu um erro de script. + Sintaxe incorreta foi encontrada enquanto {0} estava sendo analisado. + Ocorreu um erro fatal. + Execução concluída {0} vezes... + Você cancelou a consulta. + Ocorreu um erro enquanto o lote estava sendo executado. + Ocorreu um erro enquanto o lote estava sendo executado, mas o erro foi ignorado. + Beginning execution loop + Comando {0} não é suportado. + A variável {0} não pôde ser encontrada. + Erro de execução de SQL: {0} + Execução do pacote do analisador de lotes: {0} encontrado... na linha {1}: {2} Descrição: {3} + Mensagem recebida do motor de execução do pacote do analisador de lotes: Mensagem: {0} Mensagem detalhada: {1} + Processando o conjunto de resultados no motor de execução do pacote do analisador de lotes: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Execução do conjunto de resultados do motor de execução de pacotes do analisador de lotes terminada. + Cancelando execução do conjunto de resultados do motor de execução de pacotes do analisador de lotes. + Aviso de script. + Para obter mais informações sobre esse erro, consulte os tópicos de solução de problemas na documentação do produto. + Arquivo '{0}' incluído recursivamente. + Sem marca de comentário final ' * /'. + Aspas não fechadas depois da sequência de caracteres. + Sintaxe incorreta foi encontrada enquanto {0} estava sendo analisado. + A variável {0} não está definida. + teste + Substituição de uma sequência vazia por uma cadeia de caracteres vazia. + Sessão de edição não existe. + A consulta não completou a execução + A consulta não gerou exatamente um conjunto de resultados + Falha ao adicionar uma nova linha ao cache de atualização + ID de linha de entrada fora da faixa de linhas no cache de edição + Uma atualização está ainda pendente para esta linha e deve ser revertida antes + Não existem atualizações pendentes para o ID informado. + Tabela ou view de metadados não pode ser encontrada + Formato inválido para coluna binária + Colunas Booleanas devem possuir o número 1 ou 0 ou a string true ou false + Um valor requerido para a célula está faltando + Uma exclusão está pendente para esta linha. Uma atualização desta célula não pode ser aplicada. + Um ID de coluna deve estar no intervalo de colunas para a consulta + Coluna não pode ser editada + Não foram encontradas colunas chave + Um nome de arquivo de saída deve ser fornecido + O objecto de banco de dados {0} não pode ser usado para edição. + A URI especificada '{0}' não tem uma conexão padrão + Uma tarefa de gravação está em progresso. Favor aguardar o térnino. + Coluna decimal não tem precisão numérica ou escala numérica + <TBD> + Não é possível adicionar linha ao buffer de resultados, o datareader não contém linhas + Os valores da coluna do tipo de dados TIME devem estar entre 00:00:00.0000000 e 23:59:59.9999999 + Nulo não é permitido para esta coluna. + Sessão de edição já existe. + Sessão de edição não foi inicializada + Sessão de edição já foi inicializada + Sessão de edição já foi inicializada ou está em processo de inicialização + A execução da consulta falhou, veja as mensagens para detalhes + Limite de resultados não pode ser negativo + NULL + O nome do objeto deve ser fornecido. + O servidor ou banco de dados especificado não é suportado. + Metadados da tabela não possuem propriedades extendidas + Tabela ou view requisitada para edição não foi encontrada + Erro expandindo: {0} + Erro conectando a {0} + Agregados + Funcões de Servidor + Funções de Aplicação + Assemblies + Arquivos de Assemblies + Chaves Assimétricas + Chaves Assimétricas + Opções de Compressão de Dados + Certificados + Tabelas de Arquivos + Certificados + Verificação de Restrições + Colunas + Restrições + Contratos + Credenciais + Mensagens de Erro + Adesão às Funções de Servidor + Opções de Banco de Dados + Funções de Bancos de Dados + Adesão às Funções + Gatilhos de Bancos de Dados + + Restrições Padrão + Padrões + Sequências + Pontos finais + Notificações de Eventos + Notificações de Eventos de Servidor + Propriedades Extendidas + Grupos de Arquivos + Chaves Estrangeiras + Catálogos Full-Text + Índices Full-Text + Funções + Índices + Funções em Linha + Chaves + Servidores vinculados + Logins de servidores vinculados + Logins + Master key + Master Keys + Tipos de Mensagens + Funções de Valor de Tabelas + Parâmetros + Funções de Partição + Esquemas de Partição + Permissões + Chaves Primárias + Programabilidade + Filas + Ligações de Serviço Remoto + Colunas Retornadas + Funções + Rotas + Regras + Esquemas + Segurança + Objetos de Servidor + Gerenciamento + Gatilhos + Service Broker + Serviços + Assinaturas + Arquivos de Log + Estatísticas + Armazenamento + Stored Procedures + Chaves Simétricas + Sinônimos + Tabelas + Gatilhos + Tipos + Chaves Únicas + Tipos de Dados Definidos pelo Usuário + Tipos Definidos pelo Usuário (CLR) + Usuários + Visualizações + Índices XML + Coleções de Esquemas XML + Tipos de Tabelas Definidas pelo Usuário + Arquivos + Título Faltando + Prioridades do Agente + Provedores de Criptografia + Especificações de Auditoria de Banco de Dados + Chaves de Criptografia de Banco de Dados + Sessões de Evento + Listas de Parada Full Text + Pool de Recursos + Auditorias + Especificações de Auditoria de Servidor + Índices Espaciais + Grupos de Trabalho + Arquivos SQL + Funções de Servidor + Tipo SQL + Opções de Servidor + Diagramas de Banco de Dados + Tabelas do Sistema + Bancos de Dados + Contratos do Sistema + Bancos de Dados do Sistema + Tipos de Mensagens do Sistema + Filas do Sistema + Serviços do Sistema + Stored Procedures do Sistema + Visualizações do Sistema + Aplicações da Camada de Dados + Stored Procedures Estendidas + Funções Agregadas + Numéricos Aproximados + Cadeias de Caracteres Binárias + Cadeias de Caracteres + Tipos de Dados CLR + Funções de Configuração + Funções de Cursor + Tipos de Dados do Sistema + Data e Hora + Funções de Data e Hora + Numéricos Exatos + Funções do Sistema + Funções de ID de Hierarquia + Funções Matemáticas + Funções de Metadados + Outros tipos de Dados + Outras Funções + Funções de Conjuntos de Linhas + Funções de Segurança + Tipos de Dados Espaciais + Funções de Cadeias de Caracteres + Funções Estatísticas do Sistema + Funções de Texto e Imagem + Cadeias de Caracteres Unicode + Funções Agregadas + Funções de Valores Escalares + Funções de Valores Baseadas em Tabelas + Stored Procedures do Sistema Estendidas + Tipos Intrínsecos + Funções de Servidor Intrínsecas + Usuário com Senha + Pesquisar Lista de Propriedades + Políticas de Segurança + Predicados de Segurança + Função de Servidor + Pesquisar Listas de Propriedades + Índices de Colunas + Índices de Tipos de Tabelas + Índices XML Seletivos + Namespaces XML + Caminhos Promovidos de Tipos XML + Caminhos Promovidos de Tipos T-SQL + Credenciais de Escopo de Banco de Dados + Fontes de Dados Externas + Formatos de Arquivos Externos + Recursos Externos + Tabelas Externas + Chaves Sempre Criptografadas + Chaves Mestras de Colunas + Chaves de Criptografia de Colunas + Servidor + Erro ao analisar a propriedade ScriptingParams.ConnectionString. + Diretório inválido especificado pela propriedade ScriptingParams.FilePath. + Erro ao analisar a propriedade ScriptingListObjectsCompleteParams.ConnectionString. + {0} ({1}, {2}, {3}) + Nenhum padrão + Entrada + Entrada/Saída + Entrada/SomenteLeitura + Entrada/Saída/SomenteLeitura + Padrão + nulo + não nulo + {0} ({1}, {2}) + {0} ({1}) + {0} ({1} Computado, {2}, {3}) + {0} ({1}Computado) + {0} (Conjunto de Colunas, {1}) + {0} (Conjunto de Colunas, {1}{2}, {3}) + {0} (Conjunto de Colunas, {1}, {2}, {3}) + Exclusivo + Não Exclusivo + Clusterizado + Não Clusterizado + Histórico + Versionado pelo sistema + Indisponível + Grupo de arquivos padrão atual: {0} + Novo Grupo de Arquivos para {0} + Padrão + Arquivos + Nome + Somente Leitura + Auto crescimento / Tamanho máximo + ... + <padrão> + Grupo de Arquivos + Nome Lógico + Tipo de Arquivo + Tamanho Inicial (MB) + <novo grupo de arquivos> + Caminho + Nome do Arquivo + <dispositivo bruto> + Logado em massa + Completo + Simples + Selecionar o proprietário do banco de dados + Nenhum + Por {0} MB, limitado a {1} MB + Por {0}%, Limitado a {1} mb + Por {0} MB, Ilimitado + Por {0}%, Ilimitado + Ilimitado + Limitado a {0} MB + Automático + Service Broker + Agrupamento + Cursor + Diversos + Recuperação + Estado + Padrão ANSI NULL + ANSI NULLS Habilitado + Preenchimento ANSI habilitado + ANSI Warnings Habilitados + Arithmetic Abortar habilitado + Fechamento automático + Criar Estatísticas Automaticamente + Reduzir Automaticamente + Estatísticas Atualizadas Automaticamente + Atualizar estatísticas automaticamente de forma assíncrona + Sensível à Caixa + Fechar Cursor na Confirmação Habilitado + Agrupamento + Concatenar Nulo Produz Nulo + Nível de Compatibilidade do Banco de Dados + Estado do Banco de Dados + Cursor Padrão + Indexação Full-Text Habilitada + Anular arredondamento numérico. + Verificação de Página + Identificadores Entre Aspas Habilitados + Banco de Dados Somente Leitura + Gatilhos Recursivos Habilitados + Acesso Restrito + Selecionar Cópia Into/Em Massa + Respeitar a Prioridade do Broker + Identificador de agente de serviço + Agente habilitado + Truncar o Log no Ponto de Verificação + Encadeamento de Propriedades de Bancos de Dados Habilitado + Confiável + Otimizaçao da Correlação de Data Enabledprototype_db_prop_parameterization = Parametrização + Forçado + Simples + Dados ROWS + LOG + Dados FILESTREAM + Não aplicável + <caminho padrão> + Conexões Abertas + Para modificar as propriedades do banco de dados, o SQL Server deve fechar todas as outras conexões ao banco de dados_ Tem certeza que você quer modificar as propriedades e fechar todas as outras conexões? + AUTO_CLOSED + EMERGÊNCIA + INACESSÍVEL + NORMAL + OFF-LINE + RECUPERANDO + RECUPERAÇÃO PENDENTE + RESTAURANDO + DESLIGAMENTO + MODO DE ESPERA + SUSPEITO + GLOBAL + LOCAL + MULTI_USUÁRIO + USUÁRIO_RESTRITO + MONO_USUÁRIO + SOMA DE VERIFICAÇÃO + NENHUM + TORN_PAGE_DETECTION + Formato de Armazenamento VarDecimal Habilitado + SQL Server 2008 (100) + Criptografia Habilitada + DESLIGADO + LIGADO + PRIMÁRIO + Para a política de distribuição de HASH, o número de colunas hash principais é opcional, mas deve ser de 1 a 16 colunas + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Nenhum + Parcial + Arquivos FILESTREAM + Nenhum grupo de arquivos aplicável + O banco de dados {0} não está acessível. + A consulta não tem resultado para retornar + Conjunto de resultados tem muitas linhas para ser carregado com segurança + Parametrização + Não é permitido especificar essa opção ao restaurar um backup com a opção NORECOVERY. + Caminho inválido para o arquivo de banco de dados: '{0}' + Log + Falha ao criar o plano de restauração + Restauração de banco de dados não é suportado + Restaurar o banco de dados + (Apenas cópia) + Componente + Tipo + Servidor + Banco de dados + Posição + Primeiro LSN + Último LSN + Checkpoint LSN + LSN completo + Data de Início + Data de Término + Tamanho + Nome do usuário + Expiração + Nome + O último backup feito ({0}) + Backup do Banco de Dados + Em andamento + Concluído + Gerando script + Conexão não encontrada + O nome do arquivo especificado também é um nome de diretório: {0} + Não foi possível verificar a existência do local do arquivo de backup: {0} + Não foi possível acessar o diretório especificado no servidor: {0} + Nenhum conjunto de backup selecionado para ser restaurado + Nunca + Azure SQL DB + Azure SQL Data Warehouse + Azure SQL Stretch Database + Caminho {0} não é um diretório válido + Já existe um arquivo com nome {1} para o diretório {0} + Valor {0} é muito grande para caber em uma coluna do tipo {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.resx new file mode 100644 index 0000000000..abfd4c7bd8 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.resx @@ -0,0 +1,1745 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Connection parameters cannot be null + + + + OwnerUri cannot be null or empty + + + + SpecifiedUri '{0}' does not have existing connection + . + Parameters: 0 - uri (string) + + + Specified URI '{0}' does not have a default connection + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + . + Parameters: 0 - intent (string) + + + Connection canceled + + + + OwnerUri cannot be null or empty + + + + Connection details object cannot be null + + + + ServerName cannot be null or empty + + + + {0} cannot be null or empty when using SqlLogin authentication + . + Parameters: 0 - component (string) + + + Azure SQL DB + + + + Azure SQL Data Warehouse + + + + Azure SQL Stretch Database + + + + The query has already completed, it cannot be cancelled + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + + + + Query was canceled by user + + + + The batch has not completed, yet + + + + Batch index cannot be less than 0 or greater than the number of batches + + + + Result set index cannot be less than 0 or greater than the number of result sets + + + + Maximum number of bytes to return must be greater than zero + + + + Maximum number of chars to return must be greater than zero + + + + Maximum number of XML bytes to return must be greater than zero + + + + Access method cannot be write-only + + + + FileStreamWrapper must be initialized before performing operations + + + + This FileStreamWrapper cannot be used for writing + + + + (1 row affected) + + + + ({0} rows affected) + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + . + Parameters: 0 - message (string) + + + (No column name) + + + + NULL + + + + The requested query does not exist + + + + This editor is not connected to a database + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + + + + Sender for OnInfoMessage event must be a SqlConnection + + + + Cannot add row to result buffer, data reader does not contain rows + + + + Query has no results to return + + + + Result set has too many rows to be safely loaded + + + + Result cannot be saved until query execution has completed + + + + Internal error occurred while starting save task + + + + A save request to the same path is in progress + + + + Failed to save {0}: {1} + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + + + + Row count must be a positive integer + + + + Could not retrieve column schema for result set + + + + Could not retrieve an execution plan from the result set + + + + Unsupported Save Format: {0} + . + Parameters: 0 - formatName (string) + + + A request for file {0} is already in progress + . + Parameters: 0 - filePath (string) + + + Cannot serialize more data as no request for file {0} could be found + . + Parameters: 0 - filePath (string) + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + . + Parameters: 0 - errorMessage (string) + + + No results were found. + + + + No database object was retrieved. + + + + Please connect to a server. + + + + Operation timed out. + + + + This object type is currently not supported by this feature. + + + + Replacement of an empty string by an empty string. + + + + Position is outside of file line range + + + + Position is outside of column range for line {0} + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Table or view requested for edit could not be found + + + + Edit session does not exist. + + + + Edit session already exists. + + + + Edit session has not been initialized + + + + Edit session has already been initialized + + + + Edit session has already been initialized or is in the process of initializing + + + + Table metadata does not have extended properties + + + + A object name must be provided + + + + Explicitly specifying server or database is not supported + + + + Result limit cannot be negative + + + + Database object {0} cannot be used for editing. + . + Parameters: 0 - typeName (string) + + + Query execution failed, see messages for details + + + + Query has not completed execution + + + + Query did not generate exactly one result set + + + + Failed to add new row to update cache + + + + Given row ID is outside the range of rows in the edit cache + + + + An update is already pending for this row and must be reverted first + + + + Given row ID does not have pending update + + + + Table or view metadata could not be found + + + + Invalid format for column '{0}', column is defined as {1} + . + Parameters: 0 - colName (string), 1 - colType (string) + + + Invalid format for binary column + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + + + + The column '{0}' is defined as NOT NULL but was not given a value + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + + + + Column ID must be in the range of columns for the query + + + + Column cannot be edited + + + + No key columns were found + + + + An output filename must be provided + + + + A commit task is in progress. Please wait for completion. + + + + <TBD> + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + + + + NULL is not allowed for this column + + + + Value {0} is too large to fit in column of type {1} + . + Parameters: 0 - value (string), 1 - columnType (string) + + + EditData queries targeting multiple tables are not supported + + + + EditData queries with aliased columns are not supported + + + + EditData queries with aggregate or expression columns are not supported + + + + EditData queries with duplicate columns are not supported + + + + EditData queries must query the originally targeted table '{0}' + . + Parameters: 0 - tableName (string) + + + Beginning execution loop + + + + An error occurred while the batch was being executed, but the error has been ignored. + + + + Batch execution completed {0} times... + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + + + + test + + + + Exact numeric column is missing numeric precision or numeric scale + + + + Column with length is missing size + + + + Scalar column missing scale + + + + Error expanding: {0} + + + + Error connecting to {0} + + + + Aggregates + + + + Server Roles + + + + Application Roles + + + + Assemblies + + + + Assembly Files + + + + Asymmetric Keys + + + + Asymmetric Keys + + + + Data Compression Options + + + + Certificates + + + + FileTables + + + + Certificates + + + + Check Constraints + + + + Columns + + + + Constraints + + + + Contracts + + + + Credentials + + + + Error Messages + + + + Server Role Membership + + + + Database Options + + + + Database Roles + + + + Role Memberships + + + + Database Triggers + + + + Default Constraints + + + + Defaults + + + + Sequences + + + + Endpoints + + + + Event Notifications + + + + Server Event Notifications + + + + Extended Properties + + + + Filegroups + + + + Foreign Keys + + + + Full-Text Catalogs + + + + Full-Text Indexes + + + + Functions + + + + Indexes + + + + Inline Functions + + + + Keys + + + + Linked Servers + + + + Linked Server Logins + + + + Logins + + + + Master Key + + + + Master Keys + + + + Message Types + + + + Table-Valued Functions + + + + Parameters + + + + Partition Functions + + + + Partition Schemes + + + + Permissions + + + + Primary Keys + + + + Programmability + + + + Queues + + + + Remote Service Bindings + + + + Returned Columns + + + + Roles + + + + Routes + + + + Rules + + + + Schemas + + + + Security + + + + Server Objects + + + + Management + + + + Triggers + + + + Service Broker + + + + Services + + + + Signatures + + + + Log Files + + + + Statistics + + + + Storage + + + + Stored Procedures + + + + Symmetric Keys + + + + Synonyms + + + + Tables + + + + Triggers + + + + Types + + + + Unique Keys + + + + User-Defined Data Types + + + + User-Defined Types (CLR) + + + + Users + + + + Views + + + + XML Indexes + + + + XML Schema Collections + + + + User-Defined Table Types + + + + Files + + + + Missing Caption + + + + Broker Priorities + + + + Cryptographic Providers + + + + Database Audit Specifications + + + + Database Encryption Keys + + + + Event Sessions + + + + Full Text Stoplists + + + + Resource Pools + + + + Audits + + + + Server Audit Specifications + + + + Spatial Indexes + + + + Workload Groups + + + + SQL Files + + + + Server Functions + + + + SQL Type + + + + Server Options + + + + Database Diagrams + + + + System Tables + + + + Databases + + + + System Contracts + + + + System Databases + + + + System Message Types + + + + System Queues + + + + System Services + + + + System Stored Procedures + + + + System Views + + + + Data-tier Applications + + + + Extended Stored Procedures + + + + Aggregate Functions + + + + Approximate Numerics + + + + Binary Strings + + + + Character Strings + + + + CLR Data Types + + + + Configuration Functions + + + + Cursor Functions + + + + System Data Types + + + + Date and Time + + + + Date and Time Functions + + + + Exact Numerics + + + + System Functions + + + + Hierarchy Id Functions + + + + Mathematical Functions + + + + Metadata Functions + + + + Other Data Types + + + + Other Functions + + + + Rowset Functions + + + + Security Functions + + + + Spatial Data Types + + + + String Functions + + + + System Statistical Functions + + + + Text and Image Functions + + + + Unicode Character Strings + + + + Aggregate Functions + + + + Scalar-valued Functions + + + + Table-valued Functions + + + + System Extended Stored Procedures + + + + Built-in Types + + + + Built-in Server Roles + + + + User with Password + + + + Search Property List + + + + Security Policies + + + + Security Predicates + + + + Server Role + + + + Search Property Lists + + + + Column Store Indexes + + + + Table Type Indexes + + + + Server + + + + Selective XML Indexes + + + + XML Namespaces + + + + XML Typed Promoted Paths + + + + T-SQL Typed Promoted Paths + + + + Database Scoped Credentials + + + + External Data Sources + + + + External File Formats + + + + External Resources + + + + External Tables + + + + Always Encrypted Keys + + + + Column Master Keys + + + + Column Encryption Keys + + + + {0} ({1}, {2}, {3}) + + + + No default + + + + Input + + + + Input/Output + + + + Input/ReadOnly + + + + Input/Output/ReadOnly + + + + Default + + + + null + + + + not null + + + + {0} ({1}, {2}) + + + + {0} ({1}) + + + + {0} ({1}Computed, {2}, {3}) + + + + {0} ({1}Computed) + + + + {0} (Column Set, {1}) + + + + {0} (Column Set, {1}{2}, {3}) + + + + {0} (Column Set, {1}, {2}, {3}) + + + + Unique + + + + Non-Unique + + + + Clustered + + + + Non-Clustered + + + + History + + + + System-Versioned + + + + External + + + + File Table + + + + The database {0} is not accessible. + + + + Error parsing ScriptingParams.ConnectionString property. + + + + Invalid directory specified by the ScriptingParams.FilePath property. + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + + + + -- TODO: Set parameter values here. + + + + An error occurred while scripting the objects. + + + + Scripting as Execute is only supported for Stored Procedures + + + + Backup Database + + + + Please provide a file path instead of directory path + + + + The provided path is invalid + + + + In progress + + + + Completed + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + + + + Invalid path for database file: '{0}' + + + + Log + + + + Failed to create restore plan + + + + Restore database is not supported + + + + Restore Database + + + + (Copy Only) + + + + Component + + + + Name + + + + Type + + + + Server + + + + Database + + + + Position + + + + First LSN + + + + Last LSN + + + + Checkpoint LSN + + + + Full LSN + + + + Start Date + + + + Finish Date + + + + Size + + + + User Name + + + + Expiration + + + + The last backup taken ({0}) + + + + No backupset selected to be restored + + + + scripting + + + + Cannot access the specified path on the server: {0} + + + + Connection not found + + + + Cannot profile Azure system databases + + + + Failed to create session: {0} + . + Parameters: 0 - error (String) + + + Failed to start session: {0} + . + Parameters: 0 - error (String) + + + Failed to pause session: {0} + . + Parameters: 0 - error (String) + + + Failed to stop session: {0} + . + Parameters: 0 - error (String) + + + Cannot find requested XEvent session + + + + An XEvent session named {0} already exists + . + Parameters: 0 - sessionName (String) + + + [Uncategorized (Local)] + job categories + + + Jobs from MSX + + + + [Uncategorized (Multi-Server)] + + + + Database Maintenance + + + + Web Assistant + + + + Full-Text + + + + REPL-Distribution + + + + REPL-Distribution Cleanup + + + + REPL-History Cleanup + + + + REPL-LogReader + + + + REPL-Merge + + + + REPL-Snapshot + + + + REPL-Checkup + + + + REPL-Subscription Cleanup + + + + REPL-Alert Response + + + + REPL-QueueReader + + + + Replication + + + + [Uncategorized] + + + + Log Shipping + + + + Database Engine Tuning Advisor + + + + Data Collector + + + + Unknown size unit {0} + . + Parameters: 0 - unit (string) + + + Unexpected run type. + + + + The object does no longer exist on server. + + + + Unknown server type '{0}'. + . + Parameters: 0 - serverTypeName (string) + + + The current login does not have permissions to set the database owner to '{0}' The database was created successfully however. + . + Parameters: 0 - ownerName (string) + + + You must specify the Target Servers on which this multi server job will execute. + + + + Proxy account '{0}' does not exist on the server. + . + Parameters: 0 - proxyName (string) + + + SQL Server Agent Service Account + + + + A job named '{0}' already exists. Enter a unique name for the job. + . + Parameters: 0 - jobName (string) + + + The name of the job step cannot be blank. + + + + There is already a step named '{0}' for this job. You must specify a different name. + . + Parameters: 0 - jobName (string) + + + The name of the alert cannot be blank. + + + + Cannot create new alert. + + + + Cannot alter alert. + + + + Invalid Schedule + Schedule error message + + + Select at least one day to be part of this weekly schedule. + + + + The job schedule starting date cannot be greater than the ending date. + + + + The job schedule starting time cannot be after the ending time. + + + + The job schedule ending time must be after the starting time. + + + + Start date must be on or after January 1, 1990. + + + + There is already a schedule named '{0}' for this job. You must specify a different name. + . + Parameters: 0 - scheduleName (string) + + + Job server is not available + Exception thrown when job server is not available + + + Never + + + + Path {0} is not a valid directory + + + + For directory {0} a file with name {1} already exist + + + + Export bacpac + + + + Import bacpac + + + + Extract dacpac + + + + Deploy dacpac + + + + Generate script + + + + Invalid version '{0}' passed. Version must be in the format x.x.x.x where x is a number. + + + + Apply schema compare changes + + + + Failed to find the specified change in the model + + + + Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}' + + + + Could not find the schema compare session to cancel + + + diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ru.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ru.resx new file mode 100644 index 0000000000..9fe98a9db2 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.ru.resx @@ -0,0 +1,483 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089Параметры подключения должны быть указаны, значение не может быть неопределенным (null) + OwnerUri не может быть неопределенным или пустым + SpecifiedUri «{0}» не имеет существующего подключения + Значение «{0}» недопустимо для AuthenticationType. Ожидается значение «Integrated» или «SqlLogin». + Значение «{0}» недопустимо для ApplicationIntent. Ожидается значение «ReadWrite» или «ReadOnly». + Подключение к серверу отменено. + OwnerUri не может быть неопределенным или пустым + Параметры подключения не могут быть неопределенными + Имя сервера не может быть неопределенным или пустым + {0} не может быть неопределенным или пустым при использовании проверки подлинности SqlLogin + Запрос уже был выполнен, отмена невозможна + Запрос успешно отменен, но удалить запрос не удалось. Владелец URI не найден. + Выполнение запроса отменено пользователем + Пакет еще не завершен + Индекс пакета не может быть меньше нуля или больше числа пакетов + Индекс не может быть меньше нуля или больше количества записей в наборе + Максимальное количество возвращаемых байтов должно быть больше нуля + Максимальное количество возвращаемых символов должно быть больше нуля + Максимальное количество возвращаемых из XML байтов должно быть больше нуля + Метод доступа не может быть только для записи. + FileStreamWrapper должен быть инициализирован перед выполнением операций + Этот экземпляр FileStreamWrapper не может быть использован для записи + (одна строка затронута) + ({0} строк затронуто) + Выполнение команд успешно завершено. + Сообщение {0}, Уровень {1}, Состояние {2}, Строка {3}{4}{5} + Не удалось выполнить запрос: {0} + (Нет имени столбца) + Указанный запрос не найден + Этот редактор не подключен к базе данных + Запрос уже выполняется для данного сеанса редактора. Отмените запрос или дождитесь завершения его выполнения. + В качестве отправителя (sender) для события OnInfoMessage ожидается экземпляр SqlConnection + Результат не может быть сохранен до завершения выполнения запроса + При запуске задачи сохранения произошла внутренняя ошибка + По указанному пути уже выполняется сохранение результатов + Не удалось сохранить {0}: {1} + Невозможно прочитать подмножество, поскольку результаты еще не были получены с сервера + Индекс начальной строки не может быть меньше нуля или больше количества строк, находящихся в результирующем наборе + Число строк должно быть положительным целым числом + Не удалось получить столбец схемы для результирующего набора + Не удалось получить план выполнения из результирующего набора + В настоящее время эта функция не поддерживается Azure SQL DB и Data Warehouse: {0} + Произошла непредвиденная ошибка во время выполнения Peek Definition: {0} + Результаты не найдены. + Объект базы данных не был получен. + Подключитесь к серверу. + Истекло время ожидания операции. + В настоящее время этот тип объекта не поддерживается этим средством. + Позиция выходит за пределы диапазона строк файла + Позиция выходит за пределы диапазона столбцов строки {0} + Начальная позиция ({0}, {1}) должна быть меньше либо равна конечной ({2}, {3}) + Сообщение {0}, уровень {1}, состояние {2}, строка {3} + Сообщение {0}, уровень {1}, состояние {2}, процедура {3}, строка {4} + Сообщение {0}, уровень {1}, состояние {2} + При обработке пакета произошла ошибка: {0} + ({0} строк затронуто) + Предыдущее выполнение еще не завершено. + Произошла ошибка сценария. + Обнаружен неправильный синтаксис при обработке {0}. + Произошла неустранимая ошибка. + Выполнение завершено такое количество раз: {0}... + Пользователь отменил запрос. + При выполнении пакета произошла ошибка. + В процессе выполнения пакета произошла ошибка, но она была проигнорирована. + Beginning execution loop + Команда {0} не поддерживается. + Переменная {0} не найдена. + Ошибка выполнения SQL: {0} + BatchParserWrapper: {0} найдено; строка {1}: {2}; описание: {3} + BatchParserWrapper получено сообщение: {0}. Детали: {1} + BatchParserWrapper выполнение пакетной обработки ResultSet. DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + BatchParserWrapper: обработка завершена. + BatchParserWrapper: выполнение пакета отменено. + Сценарий содержит предупреждения. + Для получения дополнительной информации об этой ошибке, обратитесь к разделам по устранению неполадок в документации по продукту. + Обнаружена рекурсивная ссылка на файл «{0}». + Отсутствует обозначение конца комментария - «*/». + Незакрытые кавычки в конце символьной строки. + При разборе «{0}» обнаружен неправильный синтаксис. + Переменная {0} не определена. + тест + Замена пустой строки на пустую строку. + Сеанс не найден. + Выполнение запроса не завершено + Запрос должен содержать только один набор результатов + Не удалось добавить новую строку в кэш обновлений + Указанный идентификатор строки находится за пределами диапазона строк в кэше редактирования + Обновление уже отправлено для этой строки и должно быть отменено первым + Для указанной строки нет обновлений в очереди + Не удалось найти метаданные таблицы или представления + Недопустимый формат данных для двоичного столбца + Логические столбцы должны содержать число 1 или 0, либо строку true или false + Недопустимое значение ячейки + Обновление ячейки не может быть применено, поскольку для данной строки ожидается удаление. + Идентификатор столбца должен находиться в диапазоне столбцов запроса + Столбец не может быть изменен + Ключевые поля не найдены + Должно быть указано имя выходного файла + Объект базы данных {0} не может использоваться для редактирования. + Указанный URI '{0}' не имеет соединения по умолчанию + Выполняется фиксация. Пожалуйста, дождитесь завершения. + В десятичном столбце отсутствует числовая точность или масштаб + <TBD> + Невозможно добавить строку в файл буфера, поток не содержит строк + Значение столбца TIME должно находиться в диапазоне между 00:00:00.0000000 и 23:59:59.9999999 + Значение NULL недопустимо в этом столбце. + Сеанс редактирования уже существует. + Сеанс редактирования не был инициализирован. + Сеанс редактирования уже был инициализирован. + Сеанс редактирования уже был инициализирован или находится в процессе инициализации + Не удалось выполнить запрос, см. сообщения для получения подробностей + Значение, определяющее ограничение числа записей, не может быть отрицательным + NULL + Должно быть указано имя объекта + Явное указание сервера или базы данных не поддерживается + Метаданные таблицы не имеют расширенных свойств + Запрошенная таблица или представление не найдены. + Ошибка при расширении: {0} + Ошибка при подключении к {0} + Статистические выражения + Роли сервера + Роли приложения + Сборки + Файлы сборки + Асимметричные ключи + Асимметричные ключи + Параметры сжатия данных + Сертификаты + Объекты FileTable + Сертификаты + Проверочные ограничения + Столбцы + Ограничения + Контракты + Учетные данные + Сообщения об ошибках + Участие в роли сервера + Параметры базы данных + Роли базы данных + Членства в роли + Триггеры базы данных + Ограничения по умолчанию + Значения по умолчанию + Последовательности + Конечные точки + Уведомления о событиях + Уведомления о событиях сервера + Расширенные свойства + Файловые группы + Внешние ключи + Полнотекстовые каталоги + Полнотекстовые индексы + Функции + Индексы + Встроенная функции + Ключи + Связанные серверы + Имена входа на связанный сервер + Имена входа + Главный ключ + Главные ключи + Типы сообщений + Функция с табличным значением + Параметры + Функции секционирования + Схемы секционирования + Разрешения + Первичные ключи + Программируемость + Списки ожидания + Привязки удаленных служб + Возвращенные столбцы + Роли + Маршруты + Правила + Схемы + Безопасность + Объекты сервера + Управление + Триггеры + Компонент Service Broker + Службы + Сигнатуры + Файлы журнала + Статистика + Хранилище + Хранимые процедуры + Симметричные ключи + Синонимы + Таблицы + Триггеры + Типы + Уникальные ключи + Определяемые пользователем типы данных + Определяемые пользователем типы (CLR) + Пользователи + Представления + XML-индексы + Коллекция схем XML + Определяемые пользователем типы таблиц + Файлы + Отсутствует заголовок + Приоритеты брокера + Поставщики служб шифрования + Спецификации аудита базы данных + Ключи шифрования базы данных + Сеансы событий + Полнотекстовые списки стоп-слов + Пулы ресурсов + Аудит + Спецификации аудита сервера + Пространственные индексы + Группы рабочей нагрузки + Файлы SQL + Функции сервера + Тип SQL + Параметры сервера + Диаграммы базы данных + Системные таблицы + Базы данных + Системные контракты + Системные базы данных + Системные типы сообщений + Системные очереди + Системные службы + Системные хранимые процедуры + Системные представления + Приложения уровня данных + Расширенные хранимые процедуры + Агрегатные функции + Приблизительные числовые значения + Двоичные строки + Символьные строки + Типы данных CLR + Функции конфигурации + Функции работы с курсорами + Системные типы данных + Дата и время + Функции даты и времени + Точные числовые значения + Системные функции + Функции идентификаторов иерархии + Математические функции + Функции метаданных + Другие типы данных + Другие функции + Функции набора строк + Функции безопасности + Пространственные типы данных + Строковые функции + Системные статистические функции + Функции для работы с изображениями и текстом + Строки символов в Юникоде + Агрегатные функции + Скалярные функции + Функции с табличным значением + Системные расширенные хранимые процедуры + Встроенные типы + Встроенные роли сервера + Пользователь с паролем + Список свойств поиска + Политики безопасности + Предикаты безопасности + Роль сервера + Списки свойств поиска + Индексы хранилища столбцов + Индексы типов таблиц + Селективные XML-индексы + Пространства имен XML + Типизированные повышенные пути XML + Типизированные повышенные пути T-SQL + Учетные данные для базы данных + Внешние источники данных + Внешние форматы файлов + Внешние ресурсы + Внешние таблицы + Ключи Always Encrypted + Главные ключи столбца + Ключи шифрования столбца + Сервер + Ошибка при анализе свойства ScriptingParams.ConnectionString. + Недопустимый каталог указан в свойстве ScriptingParams.FilePath. + Ошибка при анализе свойства ScriptingListObjectsCompleteParams.ConnectionString. + {0} ({1}, {2}, {3}) + Нет значения по умолчанию + Входной + Входной/выходной + Входной/только для чтения + Входной/выходной/только для чтения + Значение по умолчанию + null + not null + {0} ({1}, {2}) + {0} ({1}) + {0} (вычислено {1}, {2}, {3}) + {0} (вычислено {1}) + {0} (набор столбцов, {1}) + {0} (набор столбцов, {1}{2}, {3}) + {0} (набор столбцов, {1}, {2}, {3}) + UNIQUE + Неуникальный + Кластеризованный + Некластеризованный + Журнал + Системно-версионный + Недоступно + Текущая файловая группа по умолчанию: {0} + Создание файловой группы для {0} + Значение по умолчанию + Файлы + Имя + Только для чтения + Автоувеличение/максимальный размер + ... + <по умолчанию> + Группа файлов + Логическое имя + Тип файла + Начальный размер (МБ) + <создать файловую группу> + Путь + Имя файла + <неформатированный носитель> + С неполным протоколированием + Полная + Простая + Выбор владельца базы данных + Нет + С шагом по {0} МБ до {1} МБ + С шагом по {0}% до {1} МБ + С шагом по {0} МБ, без ограничений + С шагом по {0} %, без ограничений + Без ограничений + Ограничено {0} МБ + Автоматически + Service Broker + Параметры сортировки + Курсор + Прочее + Восстановление + Состояние + По умолчанию ANSI NULL + Значения ANSI NULLS включены + Включено заполнение ANSI + Включены предупреждения ANSI + Включено прерывание при делении на ноль + Auto Close + Автоматическое создание статистики + Автоматическое сжатие + Автоматическое обновление статистики + Асинхронное автообновление статистики + Case Sensitive + Закрывать курсор при разрешении фиксации + Параметры сортировки + Объединение со значением NULL дает NULL + Уровень совместимости базы данных + Состояние базы данных + Курсор по умолчанию + Полнотекстовое индексирование включено + Автоокругление чисел + Проверка страниц + Включены заключенные в кавычки идентификаторы + База данных только для чтения + Включены рекурсивные триггеры + Ограничение доступа + Выбор/Массовое копирование + Учитывать приоритет компонента Honor Broker + Идентификатор компонента Service Broker + Включен компонент Broker + Усечение журнала на контрольной точке + Межбазовые цепочки владения включены + Заслуживает доверия + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + Принудительное + Простая + Данные СТРОК + ЖУРНАЛ + Данные FILESTREAM + Неприменимо + <default path> + Открытые соединения + Чтобы изменить свойства базы данных, SQL Server должен закрыть все остальные соединения с этой базой данных. Изменить свойства и закрыть остальные соединения? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + Нет + TORN_PAGE_DETECTION + Включен формат хранения VarDecimal + SQL Server 2008 (100) + Шифрование включено + ОТКЛ. + ВКЛ. + ПЕРВИЧНЫЙ + Для политики распространения HASH количество начальных хэш-столбцов указывать не обязательно. Оно может составлять от 1 до 16 столбцов + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + Нет + Частично + Файлы FILESTREAM + Применимая файловая группа отсутствует + База данных {0} недоступна. + запрос не имеет результатов + Pезультатов слишком много строк для безопасной загрузки + Параметризация + Не разрешается указывать этот параметр при восстановлении резервной копии с параметром NORECOVERY. + Недопустимый путь к файлу базы данных: {0}"""" + Журнал + Не удалось создать план восстановления + Восстановление базы данных не поддерживается + Восстановление базы данных + (Копировать только) + Тип копии + Тип + Сервер + База данных + Положение + Первый номер LSN + Последний номер LSN + Номер LSN для контрольной точки + Полный номер LSN + Дата начала + Дата завершения + Размер + Имя пользователя + Истечение срока + Имя + Последняя созданная резервная копия ({0}) + Создание резервной копии базы данных + Выполняется + Завершен + Скрипты + Соединение не найдено + Указанное имя файла является также именем каталога: {0} + Невозможно проверить существование расположения файла резервной копии: {0} + Указанный путь на сервере недоступен: {0} + Для восстановления не выбран резервный набор данных + Никогда + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.strings b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.strings new file mode 100644 index 0000000000..a84ef7488e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.strings @@ -0,0 +1,808 @@ +# String resource file +# +# When processed by the String Resource Tool, this file generates +# both a .CS and a .RESX file with the same name as the file. +# The .CS file contains a class which can be used to access these +# string resources, including the ability to format in +# parameters, which are identified with the .NET {x} format +# (see String.Format help). +# +# Comments below assume the file name is SR.strings. +# +# Lines starting with a semicolon ";" are also treated as comments, but +# in a future version they will be extracted and made available in LocStudio +# Put your comments to localizers _before_ the string they apply to. +# +# SMO build specific comment +# after generating the .resx file, run srgen on it and get the .resx file +# please remember to also check that .resx in, along with the +# .strings and .cs files + +[strings] + +############################################################################ +# Connection Service + +ConnectionServiceConnectErrorNullParams = Connection parameters cannot be null + +ConnectionServiceListDbErrorNullOwnerUri = OwnerUri cannot be null or empty + +ConnectionServiceListDbErrorNotConnected(string uri) = SpecifiedUri '{0}' does not have existing connection + +ConnectionServiceDbErrorDefaultNotConnected(string uri) = Specified URI '{0}' does not have a default connection + +ConnectionServiceConnStringInvalidAuthType(string authType) = Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + +ConnectionServiceConnStringInvalidIntent(string intent) = Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + +ConnectionServiceConnectionCanceled = Connection canceled + +### Connection Params Validation Errors + +ConnectionParamsValidateNullOwnerUri = OwnerUri cannot be null or empty + +ConnectionParamsValidateNullConnection = Connection details object cannot be null + +ConnectionParamsValidateNullServerName = ServerName cannot be null or empty + +ConnectionParamsValidateNullSqlAuth(string component) = {0} cannot be null or empty when using SqlLogin authentication + +### General connection service strings +AzureSqlDbEdition = Azure SQL DB +AzureSqlDwEdition = Azure SQL Data Warehouse +AzureSqlStretchEdition = Azure SQL Stretch Database + +############################################################################ +# Query Execution Service + +### Cancel Request + +QueryServiceCancelAlreadyCompleted = The query has already completed, it cannot be cancelled + +QueryServiceCancelDisposeFailed = Query successfully cancelled, failed to dispose query. Owner URI not found. + +QueryServiceQueryCancelled = Query was canceled by user + +### Subset Request + +QueryServiceSubsetBatchNotCompleted = The batch has not completed, yet + +QueryServiceSubsetBatchOutOfRange = Batch index cannot be less than 0 or greater than the number of batches + +QueryServiceSubsetResultSetOutOfRange = Result set index cannot be less than 0 or greater than the number of result sets + +### Data Reader Exceptions + +QueryServiceDataReaderByteCountInvalid = Maximum number of bytes to return must be greater than zero + +QueryServiceDataReaderCharCountInvalid = Maximum number of chars to return must be greater than zero + +QueryServiceDataReaderXmlCountInvalid = Maximum number of XML bytes to return must be greater than zero + +### File Stream Wrapper Exceptions + +QueryServiceFileWrapperWriteOnly = Access method cannot be write-only + +QueryServiceFileWrapperNotInitialized = FileStreamWrapper must be initialized before performing operations + +QueryServiceFileWrapperReadOnly = This FileStreamWrapper cannot be used for writing + +### Query Request + +QueryServiceAffectedOneRow = (1 row affected) + +QueryServiceAffectedRows(long rows) = ({0} rows affected) + +QueryServiceCompletedSuccessfully = Commands completed successfully. + +QueryServiceErrorFormat(int msg, int lvl, int state, int line, string newLine, string message) = Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + +QueryServiceQueryFailed(string message) = Query failed: {0} + +QueryServiceColumnNull = (No column name) + +QueryServiceCellNull = NULL + +QueryServiceRequestsNoQuery = The requested query does not exist + +QueryServiceQueryInvalidOwnerUri = This editor is not connected to a database + +QueryServiceQueryInProgress = A query is already in progress for this editor session. Please cancel this query or wait for its completion. + +QueryServiceMessageSenderNotSql = Sender for OnInfoMessage event must be a SqlConnection + +QueryServiceResultSetAddNoRows = Cannot add row to result buffer, data reader does not contain rows + +QueryServiceResultSetHasNoResults = Query has no results to return + +QueryServiceResultSetTooLarge = Result set has too many rows to be safely loaded + +### Save As Requests + +QueryServiceSaveAsResultSetNotComplete = Result cannot be saved until query execution has completed + +QueryServiceSaveAsMiscStartingError = Internal error occurred while starting save task + +QueryServiceSaveAsInProgress = A save request to the same path is in progress + +QueryServiceSaveAsFail(string fileName, string message) = Failed to save {0}: {1} + +### MISC + +QueryServiceResultSetNotRead = Cannot read subset unless the results have been read from the server + +QueryServiceResultSetStartRowOutOfRange = Start row cannot be less than 0 or greater than the number of rows in the result set + +QueryServiceResultSetRowCountOutOfRange = Row count must be a positive integer + +QueryServiceResultSetNoColumnSchema = Could not retrieve column schema for result set + +QueryServiceExecutionPlanNotFound = Could not retrieve an execution plan from the result set + +############################################################################ +# Serialization Service + +SerializationServiceUnsupportedFormat (string formatName) = Unsupported Save Format: {0} +SerializationServiceRequestInProgress (string filePath) = A request for file {0} is already in progress +SerializationServiceRequestNotFound (string filePath) = Cannot serialize more data as no request for file {0} could be found + +############################################################################ +# Language Service + +PeekDefinitionAzureError(string errorMessage) = This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + +PeekDefinitionError(string errorMessage) = An unexpected error occurred during Peek Definition execution: {0} + +PeekDefinitionNoResultsError = No results were found. + +PeekDefinitionDatabaseError = No database object was retrieved. + +PeekDefinitionNotConnectedError = Please connect to a server. + +PeekDefinitionTimedoutError = Operation timed out. + +PeekDefinitionTypeNotSupportedError = This object type is currently not supported by this feature. + +ErrorEmptyStringReplacement = Replacement of an empty string by an empty string. + +############################################################################ +# Workspace Service + +WorkspaceServicePositionLineOutOfRange = Position is outside of file line range + +WorkspaceServicePositionColumnOutOfRange(int line) = Position is outside of column range for line {0} + +WorkspaceServiceBufferPositionOutOfOrder(int sLine, int sCol, int eLine, int eCol) = Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + +############################################################################ +# Edit Data Service + +EditDataObjectNotFound = Table or view requested for edit could not be found + +EditDataSessionNotFound = Edit session does not exist. + +EditDataSessionAlreadyExists = Edit session already exists. + +EditDataSessionNotInitialized = Edit session has not been initialized + +EditDataSessionAlreadyInitialized = Edit session has already been initialized + +EditDataSessionAlreadyInitializing = Edit session has already been initialized or is in the process of initializing + +EditDataMetadataNotExtended = Table metadata does not have extended properties + +EditDataMetadataObjectNameRequired = A object name must be provided + +EditDataMetadataTooManyIdentifiers = Explicitly specifying server or database is not supported + +EditDataFilteringNegativeLimit = Result limit cannot be negative + +EditDataUnsupportedObjectType(string typeName) = Database object {0} cannot be used for editing. + +EditDataQueryFailed = Query execution failed, see messages for details + +EditDataQueryNotCompleted = Query has not completed execution + +EditDataQueryImproperResultSets = Query did not generate exactly one result set + +EditDataFailedAddRow = Failed to add new row to update cache + +EditDataRowOutOfRange = Given row ID is outside the range of rows in the edit cache + +EditDataUpdatePending = An update is already pending for this row and must be reverted first + +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" + +EditDataCreateScriptMissingValue(string colName) = The column '{0}' is defined as NOT NULL but was not given a value + +EditDataDeleteSetCell = A delete is pending for this row, a cell update cannot be applied. + +EditDataColumnIdOutOfRange = Column ID must be in the range of columns for the query + +EditDataColumnCannotBeEdited = Column cannot be edited + +EditDataColumnNoKeyColumns = No key columns were found + +EditDataScriptFilePathNull = An output filename must be provided + +EditDataCommitInProgress = A commit task is in progress. Please wait for completion. + +EditDataComputedColumnPlaceholder = + +EditDataTimeOver24Hrs = TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + +EditDataNullNotAllowed = NULL is not allowed for this column + +EditDataValueTooLarge(string value, string columnType) = Value {0} is too large to fit in column of type {1} + +EditDataMultiTableNotSupported = EditData queries targeting multiple tables are not supported + +EditDataAliasesNotSupported = EditData queries with aliased columns are not supported + +EditDataExpressionsNotSupported = EditData queries with aggregate or expression columns are not supported + +EditDataDuplicateColumnsNotSupported = EditData queries with duplicate columns are not supported + +EditDataIncorrectTable(string tableName) = EditData queries must query the originally targeted table '{0}' + +############################################################################ +# DacFx Resources + +EE_ExecutionInfo_InitializingLoop = Beginning execution loop + +EE_BatchExecutionError_Ignoring = An error occurred while the batch was being executed, but the error has been ignored. + +EE_ExecutionInfo_FinalizingLoop = Batch execution completed {0} times... + +BatchParserWrapperExecutionError = Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + +############################################################################ +# Workspace Service + +TestLocalizationConstant = test + +############################################################################ +# Utilities + +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 + +TreeNodeError = Error expanding: {0} + +ServerNodeConnectionError = Error connecting to {0} + +SchemaHierarchy_Aggregates = Aggregates + +SchemaHierarchy_ServerRoles = Server Roles + +SchemaHierarchy_ApplicationRoles = Application Roles + +SchemaHierarchy_Assemblies = Assemblies + +SchemaHierarchy_AssemblyFiles = Assembly Files + +SchemaHierarchy_AsymmetricKeys = Asymmetric Keys + +SchemaHierarchy_DatabaseAsymmetricKeys = Asymmetric Keys + +SchemaHierarchy_DataCompressionOptions = Data Compression Options + +SchemaHierarchy_Certificates = Certificates + +SchemaHierarchy_FileTables = FileTables + +SchemaHierarchy_DatabaseCertificates = Certificates + +SchemaHierarchy_CheckConstraints = Check Constraints + +SchemaHierarchy_Columns = Columns + +SchemaHierarchy_Constraints = Constraints + +SchemaHierarchy_Contracts = Contracts + +SchemaHierarchy_Credentials = Credentials + +SchemaHierarchy_ErrorMessages = Error Messages + +SchemaHierarchy_ServerRoleMembership = Server Role Membership + +SchemaHierarchy_DatabaseOptions = Database Options + +SchemaHierarchy_DatabaseRoles = Database Roles + +SchemaHierarchy_RoleMemberships = Role Memberships + +SchemaHierarchy_DatabaseTriggers = Database Triggers + +SchemaHierarchy_DefaultConstraints = Default Constraints + +SchemaHierarchy_Defaults = Defaults + +SchemaHierarchy_Sequences = Sequences + +SchemaHierarchy_Endpoints = Endpoints + +SchemaHierarchy_EventNotifications = Event Notifications + +SchemaHierarchy_ServerEventNotifications = Server Event Notifications + +SchemaHierarchy_ExtendedProperties = Extended Properties + +SchemaHierarchy_FileGroups = Filegroups + +SchemaHierarchy_ForeignKeys = Foreign Keys + +SchemaHierarchy_FullTextCatalogs = Full-Text Catalogs + +SchemaHierarchy_FullTextIndexes = Full-Text Indexes + +SchemaHierarchy_Functions = Functions + +SchemaHierarchy_Indexes = Indexes + +SchemaHierarchy_InlineFunctions = Inline Functions + +SchemaHierarchy_Keys = Keys + +SchemaHierarchy_LinkedServers = Linked Servers + +SchemaHierarchy_LinkedServerLogins = Linked Server Logins + +SchemaHierarchy_Logins = Logins + +SchemaHierarchy_MasterKey = Master Key + +SchemaHierarchy_MasterKeys = Master Keys + +SchemaHierarchy_MessageTypes = Message Types + +SchemaHierarchy_MultiSelectFunctions = Table-Valued Functions + +SchemaHierarchy_Parameters = Parameters + +SchemaHierarchy_PartitionFunctions = Partition Functions + +SchemaHierarchy_PartitionSchemes = Partition Schemes + +SchemaHierarchy_Permissions = Permissions + +SchemaHierarchy_PrimaryKeys = Primary Keys + +SchemaHierarchy_Programmability = Programmability + +SchemaHierarchy_Queues = Queues + +SchemaHierarchy_RemoteServiceBindings = Remote Service Bindings + +SchemaHierarchy_ReturnedColumns = Returned Columns + +SchemaHierarchy_Roles = Roles + +SchemaHierarchy_Routes = Routes + +SchemaHierarchy_Rules = Rules + +SchemaHierarchy_Schemas = Schemas + +SchemaHierarchy_Security = Security + +SchemaHierarchy_ServerObjects = Server Objects + +SchemaHierarchy_Management = Management + +SchemaHierarchy_ServerTriggers = Triggers + +SchemaHierarchy_ServiceBroker = Service Broker + +SchemaHierarchy_Services = Services + +SchemaHierarchy_Signatures = Signatures + +SchemaHierarchy_LogFiles = Log Files + +SchemaHierarchy_Statistics = Statistics + +SchemaHierarchy_Storage = Storage + +SchemaHierarchy_StoredProcedures = Stored Procedures + +SchemaHierarchy_SymmetricKeys = Symmetric Keys + +SchemaHierarchy_Synonyms = Synonyms + +SchemaHierarchy_Tables = Tables + +SchemaHierarchy_Triggers = Triggers + +SchemaHierarchy_Types = Types + +SchemaHierarchy_UniqueKeys = Unique Keys + +SchemaHierarchy_UserDefinedDataTypes = User-Defined Data Types + +SchemaHierarchy_UserDefinedTypes = User-Defined Types (CLR) + +SchemaHierarchy_Users = Users + +SchemaHierarchy_Views = Views + +SchemaHierarchy_XmlIndexes = XML Indexes + +SchemaHierarchy_XMLSchemaCollections = XML Schema Collections + +SchemaHierarchy_UserDefinedTableTypes = User-Defined Table Types + +SchemaHierarchy_FilegroupFiles = Files + +MissingCaption = Missing Caption + +SchemaHierarchy_BrokerPriorities = Broker Priorities + +SchemaHierarchy_CryptographicProviders = Cryptographic Providers + +SchemaHierarchy_DatabaseAuditSpecifications = Database Audit Specifications + +SchemaHierarchy_DatabaseEncryptionKeys = Database Encryption Keys + +SchemaHierarchy_EventSessions = Event Sessions + +SchemaHierarchy_FullTextStopLists = Full Text Stoplists + +SchemaHierarchy_ResourcePools = Resource Pools + +SchemaHierarchy_ServerAudits = Audits + +SchemaHierarchy_ServerAuditSpecifications = Server Audit Specifications + +SchemaHierarchy_SpatialIndexes = Spatial Indexes + +SchemaHierarchy_WorkloadGroups = Workload Groups + +SchemaHierarchy_SqlFiles = SQL Files + +SchemaHierarchy_ServerFunctions = Server Functions + +SchemaHierarchy_SqlType = SQL Type + +SchemaHierarchy_ServerOptions = Server Options + +SchemaHierarchy_DatabaseDiagrams = Database Diagrams + +SchemaHierarchy_SystemTables = System Tables + +SchemaHierarchy_Databases = Databases + +SchemaHierarchy_SystemContracts = System Contracts + +SchemaHierarchy_SystemDatabases = System Databases + +SchemaHierarchy_SystemMessageTypes = System Message Types + +SchemaHierarchy_SystemQueues = System Queues + +SchemaHierarchy_SystemServices = System Services + +SchemaHierarchy_SystemStoredProcedures = System Stored Procedures + +SchemaHierarchy_SystemViews = System Views + +SchemaHierarchy_DataTierApplications = Data-tier Applications + +SchemaHierarchy_ExtendedStoredProcedures = Extended Stored Procedures + +SchemaHierarchy_SystemAggregateFunctions = Aggregate Functions + +SchemaHierarchy_SystemApproximateNumerics = Approximate Numerics + +SchemaHierarchy_SystemBinaryStrings = Binary Strings + +SchemaHierarchy_SystemCharacterStrings = Character Strings + +SchemaHierarchy_SystemCLRDataTypes = CLR Data Types + +SchemaHierarchy_SystemConfigurationFunctions = Configuration Functions + +SchemaHierarchy_SystemCursorFunctions = Cursor Functions + +SchemaHierarchy_SystemDataTypes = System Data Types + +SchemaHierarchy_SystemDateAndTime = Date and Time + +SchemaHierarchy_SystemDateAndTimeFunctions = Date and Time Functions + +SchemaHierarchy_SystemExactNumerics = Exact Numerics + +SchemaHierarchy_SystemFunctions = System Functions + +SchemaHierarchy_SystemHierarchyIdFunctions = Hierarchy Id Functions + +SchemaHierarchy_SystemMathematicalFunctions = Mathematical Functions + +SchemaHierarchy_SystemMetadataFunctions = Metadata Functions + +SchemaHierarchy_SystemOtherDataTypes = Other Data Types + +SchemaHierarchy_SystemOtherFunctions = Other Functions + +SchemaHierarchy_SystemRowsetFunctions = Rowset Functions + +SchemaHierarchy_SystemSecurityFunctions = Security Functions + +SchemaHierarchy_SystemSpatialDataTypes = Spatial Data Types + +SchemaHierarchy_SystemStringFunctions = String Functions + +SchemaHierarchy_SystemSystemStatisticalFunctions = System Statistical Functions + +SchemaHierarchy_SystemTextAndImageFunctions = Text and Image Functions + +SchemaHierarchy_SystemUnicodeCharacterStrings = Unicode Character Strings + +SchemaHierarchy_AggregateFunctions = Aggregate Functions + +SchemaHierarchy_ScalarValuedFunctions = Scalar-valued Functions + +SchemaHierarchy_TableValuedFunctions = Table-valued Functions + +SchemaHierarchy_SystemExtendedStoredProcedures = System Extended Stored Procedures + +SchemaHierarchy_BuiltInType = Built-in Types + +SchemaHierarchy_BuiltInServerRole = Built-in Server Roles + +SchemaHierarchy_UserWithPassword = User with Password + +SchemaHierarchy_SearchPropertyList = Search Property List + +SchemaHierarchy_SecurityPolicies = Security Policies + +SchemaHierarchy_SecurityPredicates = Security Predicates + +SchemaHierarchy_ServerRole = Server Role + +SchemaHierarchy_SearchPropertyLists = Search Property Lists + +SchemaHierarchy_ColumnStoreIndexes = Column Store Indexes + +SchemaHierarchy_TableTypeIndexes = Table Type Indexes + +SchemaHierarchy_Server = Server + +SchemaHierarchy_SelectiveXmlIndexes = Selective XML Indexes + +SchemaHierarchy_XmlNamespaces = XML Namespaces + +SchemaHierarchy_XmlTypedPromotedPaths = XML Typed Promoted Paths + +SchemaHierarchy_SqlTypedPromotedPaths = T-SQL Typed Promoted Paths + +SchemaHierarchy_DatabaseScopedCredentials = Database Scoped Credentials + +SchemaHierarchy_ExternalDataSources = External Data Sources + +SchemaHierarchy_ExternalFileFormats = External File Formats + +SchemaHierarchy_ExternalResources = External Resources + +SchemaHierarchy_ExternalTables = External Tables + +SchemaHierarchy_AlwaysEncryptedKeys = Always Encrypted Keys + +SchemaHierarchy_ColumnMasterKeys = Column Master Keys + +SchemaHierarchy_ColumnEncryptionKeys = Column Encryption Keys + +SchemaHierarchy_SubroutineParameterLabelFormatString = {0} ({1}, {2}, {3}) + +SchemaHierarchy_SubroutineParameterNoDefaultLabel = No default + +SchemaHierarchy_SubroutineParameterInputLabel = Input + +SchemaHierarchy_SubroutineParameterInputOutputLabel = Input/Output + +SchemaHierarchy_SubroutineParameterInputReadOnlyLabel = Input/ReadOnly + +SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel = Input/Output/ReadOnly + +SchemaHierarchy_SubroutineParameterDefaultLabel = Default + +SchemaHierarchy_NullColumn_Label = null + +SchemaHierarchy_NotNullColumn_Label = not null + +SchemaHierarchy_UDDTLabelWithType = {0} ({1}, {2}) + +SchemaHierarchy_UDDTLabelWithoutType = {0} ({1}) + +SchemaHierarchy_ComputedColumnLabelWithType = {0} ({1}Computed, {2}, {3}) + +SchemaHierarchy_ComputedColumnLabelWithoutType = {0} ({1}Computed) + +SchemaHierarchy_ColumnSetLabelWithoutType = {0} (Column Set, {1}) + +SchemaHierarchy_ColumnSetLabelWithType = {0} (Column Set, {1}{2}, {3}) + +SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString = {0} (Column Set, {1}, {2}, {3}) + +UniqueIndex_LabelPart = Unique + +NonUniqueIndex_LabelPart = Non-Unique + +ClusteredIndex_LabelPart = Clustered + +NonClusteredIndex_LabelPart = Non-Clustered + +History_LabelPart = History + +SystemVersioned_LabelPart = System-Versioned + +External_LabelPart = External + +FileTable_LabelPart = File Table + +DatabaseNotAccessible = The database {0} is not accessible. + + +############################################################################ +# Scripting Service + +ScriptingParams_ConnectionString_Property_Invalid = Error parsing ScriptingParams.ConnectionString property. + +ScriptingParams_FilePath_Property_Invalid = Invalid directory specified by the ScriptingParams.FilePath property. + +ScriptingListObjectsCompleteParams_ConnectionString_Property_Invalid = Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + + +StoredProcedureScriptParameterComment = -- TODO: Set parameter values here. + +ScriptingGeneralError = An error occurred while scripting the objects. +ScriptingExecuteNotSupportedError = Scripting as Execute is only supported for Stored Procedures + + +############################################################################ +# Backup Service +BackupTaskName = Backup Database + +# Backup File Validation Errors +BackupPathIsFolderError = Please provide a file path instead of directory path +InvalidBackupPathError = The provided path is invalid + +############################################################################ +# Task Service +TaskInProgress = In progress +TaskCompleted = Completed + +########################################################################### +# Restore +ConflictWithNoRecovery = Specifying this option when restoring a backup with the NORECOVERY option is not permitted. +InvalidPathForDatabaseFile = Invalid path for database file: '{0}' +Log = Log +RestorePlanFailed = Failed to create restore plan +RestoreNotSupported = Restore database is not supported +RestoreTaskName = Restore Database +RestoreCopyOnly = (Copy Only) +RestoreBackupSetComponent = Component +RestoreBackupSetName = Name +RestoreBackupSetType = Type +RestoreBackupSetServer = Server +RestoreBackupSetDatabase = Database +RestoreBackupSetPosition = Position +RestoreBackupSetFirstLsn = First LSN +RestoreBackupSetLastLsn = Last LSN +RestoreBackupSetCheckpointLsn = Checkpoint LSN +RestoreBackupSetFullLsn = Full LSN +RestoreBackupSetStartDate = Start Date +RestoreBackupSetFinishDate = Finish Date +RestoreBackupSetSize = Size +RestoreBackupSetUserName = User Name +RestoreBackupSetExpiration = Expiration +TheLastBackupTaken = The last backup taken ({0}) +NoBackupsetsToRestore = No backupset selected to be restored + +############################################################################ +# Generate Script +ScriptTaskName = scripting + +############################################################################ +# File Browser Validation Errors +InvalidPathError = Cannot access the specified path on the server: {0} + +############################################################################ +# Profiler +ProfilerConnectionNotFound = Connection not found +AzureSystemDbProfilingError = Cannot profile Azure system databases +CreateSessionFailed(String error) = Failed to create session: {0} +StartSessionFailed(String error) = Failed to start session: {0} +PauseSessionFailed(String error) = Failed to pause session: {0} +StopSessionFailed(String error) = Failed to stop session: {0} +SessionNotFound = Cannot find requested XEvent session +SessionAlreadyExists(String sessionName) = An XEvent session named {0} already exists + + +;job categories +CategoryLocal = [Uncategorized (Local)] +CategoryFromMsx = Jobs from MSX +CategoryMultiServer = [Uncategorized (Multi-Server)] +CategoryDBMaint = Database Maintenance +CategoryWebAssistant = Web Assistant +CategoryFullText = Full-Text +CategoryReplDistribution = REPL-Distribution +CategoryReplDistributionCleanup = REPL-Distribution Cleanup +CategoryReplHistoryCleanup = REPL-History Cleanup +CategoryReplLogReader = REPL-LogReader +CategoryReplMerge = REPL-Merge +CategoryReplSnapShot = REPL-Snapshot +CategoryReplCheckup = REPL-Checkup +CategoryReplCleanup = REPL-Subscription Cleanup +CategoryReplAlert = REPL-Alert Response +CategoryReplQReader = REPL-QueueReader +CategoryReplication = Replication +CategoryUncategorized = [Uncategorized] +CategoryLogShipping = Log Shipping +CategoryDBEngineTuningAdvisor = Database Engine Tuning Advisor +CategoryDataCollector = Data Collector + +UnknownSizeUnit(unit) = Unknown size unit {0} +UnexpectedRunType = Unexpected run type. +CredentialNoLongerExists = The object does no longer exist on server. +UnknownServerType(string serverTypeName) = Unknown server type '{0}'. +SetOwnerFailed(string ownerName) = The current login does not have permissions to set the database owner to '{0}' The database was created successfully however. +TargetServerNotSelected = You must specify the Target Servers on which this multi server job will execute. +ProxyAccountNotFound(string proxyName) = Proxy account '{0}' does not exist on the server. +SysadminAccount = SQL Server Agent Service Account +JobAlreadyExists(string jobName) = A job named '{0}' already exists. Enter a unique name for the job. +JobStepNameCannotBeBlank = The name of the job step cannot be blank. +JobStepNameAlreadyExists(string jobName) = There is already a step named '{0}' for this job. You must specify a different name. +AlertNameCannotBeBlank = The name of the alert cannot be blank. +CannotCreateNewAlert = Cannot create new alert. +CannotAlterAlert = Cannot alter alert. + +; Schedule error message +InvalidScheduleTitle = Invalid Schedule +InvalidWeeklySchedule = Select at least one day to be part of this weekly schedule. +StartDateGreaterThanEndDate = The job schedule starting date cannot be greater than the ending date. +StartTimeGreaterThanEndTime = The job schedule starting time cannot be after the ending time. +EndTimeEqualToStartTime = The job schedule ending time must be after the starting time. +InvalidStartDate = Start date must be on or after January 1, 1990. +ScheduleNameAlreadyExists(string scheduleName)=There is already a schedule named '{0}' for this job. You must specify a different name. + +; Exception thrown when job server is not available +JobServerIsNotAvailable = Job server is not available + +############################################################################ +# Admin Service + +NeverBackedUp = Never +Error_InvalidDirectoryName = Path {0} is not a valid directory +Error_ExistingDirectoryName = For directory {0} a file with name {1} already exist + +############################################################################ +# DacFx +ExportBacpacTaskName = Export bacpac +ImportBacpacTaskName = Import bacpac +ExtractDacpacTaskName = Extract dacpac +DeployDacpacTaskName = Deploy dacpac +GenerateScriptTaskName = Generate script +ExtractInvalidVersion = Invalid version '{0}' passed. Version must be in the format x.x.x.x where x is a number. + +############################################################################ +# Schema Compare +PublishChangesTaskName = Apply schema compare changes +SchemaCompareExcludeIncludeNodeNotFound = Failed to find the specified change in the model +OpenScmpConnectionBasedModelParsingError = Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}' +SchemaCompareSessionNotFound = Could not find the schema compare session to cancel \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.xlf new file mode 100644 index 0000000000..7ef7fcbe12 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.xlf @@ -0,0 +1,2029 @@ + + + + + + Connection parameters cannot be null + Connection parameters cannot be null + + + + OwnerUri cannot be null or empty + OwnerUri cannot be null or empty + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' does not have existing connection + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + . + Parameters: 0 - intent (string) + + + Connection canceled + Connection canceled + + + + OwnerUri cannot be null or empty + OwnerUri cannot be null or empty + + + + Connection details object cannot be null + Connection details object cannot be null + + + + ServerName cannot be null or empty + ServerName cannot be null or empty + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} cannot be null or empty when using SqlLogin authentication + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + The query has already completed, it cannot be cancelled + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Query successfully cancelled, failed to dispose query. Owner URI not found. + + + + Query was canceled by user + Query was canceled by user + + + + The batch has not completed, yet + The batch has not completed, yet + + + + Batch index cannot be less than 0 or greater than the number of batches + Batch index cannot be less than 0 or greater than the number of batches + + + + Result set index cannot be less than 0 or greater than the number of result sets + Result set index cannot be less than 0 or greater than the number of result sets + + + + Maximum number of bytes to return must be greater than zero + Maximum number of bytes to return must be greater than zero + + + + Maximum number of chars to return must be greater than zero + Maximum number of chars to return must be greater than zero + + + + Maximum number of XML bytes to return must be greater than zero + Maximum number of XML bytes to return must be greater than zero + + + + Access method cannot be write-only + Access method cannot be write-only + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper must be initialized before performing operations + + + + This FileStreamWrapper cannot be used for writing + This FileStreamWrapper cannot be used for writing + + + + (1 row affected) + (1 row affected) + + + + ({0} rows affected) + ({0} rows affected) + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Commands completed successfully. + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Query failed: {0} + . + Parameters: 0 - message (string) + + + (No column name) + (No column name) + + + + The requested query does not exist + The requested query does not exist + + + + This editor is not connected to a database + This editor is not connected to a database + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + + + + Sender for OnInfoMessage event must be a SqlConnection + Sender for OnInfoMessage event must be a SqlConnection + + + + Result cannot be saved until query execution has completed + Result cannot be saved until query execution has completed + + + + Internal error occurred while starting save task + Internal error occurred while starting save task + + + + A save request to the same path is in progress + A save request to the same path is in progress + + + + Failed to save {0}: {1} + Failed to save {0}: {1} + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Cannot read subset unless the results have been read from the server + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Start row cannot be less than 0 or greater than the number of rows in the result set + + + + Row count must be a positive integer + Row count must be a positive integer + + + + Could not retrieve column schema for result set + Could not retrieve column schema for result set + + + + Could not retrieve an execution plan from the result set + Could not retrieve an execution plan from the result set + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + An unexpected error occurred during Peek Definition execution: {0} + . + Parameters: 0 - errorMessage (string) + + + No results were found. + No results were found. + + + + No database object was retrieved. + No database object was retrieved. + + + + Please connect to a server. + Please connect to a server. + + + + Operation timed out. + Operation timed out. + + + + This object type is currently not supported by this feature. + This object type is currently not supported by this feature. + + + + Position is outside of file line range + Position is outside of file line range + + + + Position is outside of column range for line {0} + Position is outside of column range for line {0} + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + test + test + + + + Replacement of an empty string by an empty string. + Replacement of an empty string by an empty string. + + + + Edit session does not exist. + Edit session does not exist. + + + + Query has not completed execution + Query has not completed execution + + + + Query did not generate exactly one result set + Query did not generate exactly one result set + + + + Failed to add new row to update cache + Failed to add new row to update cache + + + + Given row ID is outside the range of rows in the edit cache + Given row ID is outside the range of rows in the edit cache + + + + An update is already pending for this row and must be reverted first + An update is already pending for this row and must be reverted first + + + + Given row ID does not have pending update + Given row ID does not have pending update + + + + Table or view metadata could not be found + Table or view metadata could not be found + + + + Invalid format for binary column + Invalid format for binary column + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Allowed values for boolean columns are 0, 1, "true", or "false" + + + + The column '{0}' is defined as NOT NULL but was not given a value + The column '{0}' is defined as NOT NULL but was not given a value + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + A delete is pending for this row, a cell update cannot be applied. + + + + Column ID must be in the range of columns for the query + Column ID must be in the range of columns for the query + + + + Column cannot be edited + Column cannot be edited + + + + No key columns were found + No key columns were found + + + + An output filename must be provided + An output filename must be provided + + + + Database object {0} cannot be used for editing. + Database object {0} cannot be used for editing. + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + Specified URI '{0}' does not have a default connection + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + A commit task is in progress. Please wait for completion. + + + + Exact numeric column is missing numeric precision or numeric scale + Exact numeric column is missing numeric precision or numeric scale + + + + <TBD> + <TBD> + + + + Cannot add row to result buffer, data reader does not contain rows + Cannot add row to result buffer, data reader does not contain rows + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + + + + NULL is not allowed for this column + NULL is not allowed for this column + + + + Edit session already exists. + Edit session already exists. + + + + Edit session has not been initialized + Edit session has not been initialized + + + + Edit session has already been initialized + Edit session has already been initialized + + + + Edit session has already been initialized or is in the process of initializing + Edit session has already been initialized or is in the process of initializing + + + + Query execution failed, see messages for details + Query execution failed, see messages for details + + + + Result limit cannot be negative + Result limit cannot be negative + + + + NULL + NULL + + + + A object name must be provided + A object name must be provided + + + + Explicitly specifying server or database is not supported + Explicitly specifying server or database is not supported + + + + Table metadata does not have extended properties + Table metadata does not have extended properties + + + + Table or view requested for edit could not be found + Table or view requested for edit could not be found + + + + Error expanding: {0} + Error expanding: {0} + + + + Error connecting to {0} + Error connecting to {0} + + + + Aggregates + Aggregates + + + + Server Roles + Server Roles + + + + Application Roles + Application Roles + + + + Assemblies + Assemblies + + + + Assembly Files + Assembly Files + + + + Asymmetric Keys + Asymmetric Keys + + + + Asymmetric Keys + Asymmetric Keys + + + + Data Compression Options + Data Compression Options + + + + Certificates + Certificates + + + + FileTables + FileTables + + + + Certificates + Certificates + + + + Check Constraints + Check Constraints + + + + Columns + Columns + + + + Constraints + Constraints + + + + Contracts + Contracts + + + + Credentials + Credentials + + + + Error Messages + Error Messages + + + + Server Role Membership + Server Role Membership + + + + Database Options + Database Options + + + + Database Roles + Database Roles + + + + Role Memberships + Role Memberships + + + + Database Triggers + Database Triggers + + + + Default Constraints + Default Constraints + + + + Defaults + Defaults + + + + Sequences + Sequences + + + + Endpoints + Endpoints + + + + Event Notifications + Event Notifications + + + + Server Event Notifications + Server Event Notifications + + + + Extended Properties + Extended Properties + + + + Filegroups + Filegroups + + + + Foreign Keys + Foreign Keys + + + + Full-Text Catalogs + Full-Text Catalogs + + + + Full-Text Indexes + Full-Text Indexes + + + + Functions + Functions + + + + Indexes + Indexes + + + + Inline Functions + Inline Functions + + + + Keys + Keys + + + + Linked Servers + Linked Servers + + + + Linked Server Logins + Linked Server Logins + + + + Logins + Logins + + + + Master Key + Master Key + + + + Master Keys + Master Keys + + + + Message Types + Message Types + + + + Table-Valued Functions + Table-Valued Functions + + + + Parameters + Parameters + + + + Partition Functions + Partition Functions + + + + Partition Schemes + Partition Schemes + + + + Permissions + Permissions + + + + Primary Keys + Primary Keys + + + + Programmability + Programmability + + + + Queues + Queues + + + + Remote Service Bindings + Remote Service Bindings + + + + Returned Columns + Returned Columns + + + + Roles + Roles + + + + Routes + Routes + + + + Rules + Rules + + + + Schemas + Schemas + + + + Security + Security + + + + Server Objects + Server Objects + + + + Management + Management + + + + Triggers + Triggers + + + + Service Broker + Service Broker + + + + Services + Services + + + + Signatures + Signatures + + + + Log Files + Log Files + + + + Statistics + Statistics + + + + Storage + Storage + + + + Stored Procedures + Stored Procedures + + + + Symmetric Keys + Symmetric Keys + + + + Synonyms + Synonyms + + + + Tables + Tables + + + + Triggers + Triggers + + + + Types + Types + + + + Unique Keys + Unique Keys + + + + User-Defined Data Types + User-Defined Data Types + + + + User-Defined Types (CLR) + User-Defined Types (CLR) + + + + Users + Users + + + + Views + Views + + + + XML Indexes + XML Indexes + + + + XML Schema Collections + XML Schema Collections + + + + User-Defined Table Types + User-Defined Table Types + + + + Files + Files + + + + Missing Caption + Missing Caption + + + + Broker Priorities + Broker Priorities + + + + Cryptographic Providers + Cryptographic Providers + + + + Database Audit Specifications + Database Audit Specifications + + + + Database Encryption Keys + Database Encryption Keys + + + + Event Sessions + Event Sessions + + + + Full Text Stoplists + Full Text Stoplists + + + + Resource Pools + Resource Pools + + + + Audits + Audits + + + + Server Audit Specifications + Server Audit Specifications + + + + Spatial Indexes + Spatial Indexes + + + + Workload Groups + Workload Groups + + + + SQL Files + SQL Files + + + + Server Functions + Server Functions + + + + SQL Type + SQL Type + + + + Server Options + Server Options + + + + Database Diagrams + Database Diagrams + + + + System Tables + System Tables + + + + Databases + Databases + + + + System Contracts + System Contracts + + + + System Databases + System Databases + + + + System Message Types + System Message Types + + + + System Queues + System Queues + + + + System Services + System Services + + + + System Stored Procedures + System Stored Procedures + + + + System Views + System Views + + + + Data-tier Applications + Data-tier Applications + + + + Extended Stored Procedures + Extended Stored Procedures + + + + Aggregate Functions + Aggregate Functions + + + + Approximate Numerics + Approximate Numerics + + + + Binary Strings + Binary Strings + + + + Character Strings + Character Strings + + + + CLR Data Types + CLR Data Types + + + + Configuration Functions + Configuration Functions + + + + Cursor Functions + Cursor Functions + + + + System Data Types + System Data Types + + + + Date and Time + Date and Time + + + + Date and Time Functions + Date and Time Functions + + + + Exact Numerics + Exact Numerics + + + + System Functions + System Functions + + + + Hierarchy Id Functions + Hierarchy Id Functions + + + + Mathematical Functions + Mathematical Functions + + + + Metadata Functions + Metadata Functions + + + + Other Data Types + Other Data Types + + + + Other Functions + Other Functions + + + + Rowset Functions + Rowset Functions + + + + Security Functions + Security Functions + + + + Spatial Data Types + Spatial Data Types + + + + String Functions + String Functions + + + + System Statistical Functions + System Statistical Functions + + + + Text and Image Functions + Text and Image Functions + + + + Unicode Character Strings + Unicode Character Strings + + + + Aggregate Functions + Aggregate Functions + + + + Scalar-valued Functions + Scalar-valued Functions + + + + Table-valued Functions + Table-valued Functions + + + + System Extended Stored Procedures + System Extended Stored Procedures + + + + Built-in Types + Built-in Types + + + + Built-in Server Roles + Built-in Server Roles + + + + User with Password + User with Password + + + + Search Property List + Search Property List + + + + Security Policies + Security Policies + + + + Security Predicates + Security Predicates + + + + Server Role + Server Role + + + + Search Property Lists + Search Property Lists + + + + Column Store Indexes + Column Store Indexes + + + + Table Type Indexes + Table Type Indexes + + + + Selective XML Indexes + Selective XML Indexes + + + + XML Namespaces + XML Namespaces + + + + XML Typed Promoted Paths + XML Typed Promoted Paths + + + + T-SQL Typed Promoted Paths + T-SQL Typed Promoted Paths + + + + Database Scoped Credentials + Database Scoped Credentials + + + + External Data Sources + External Data Sources + + + + External File Formats + External File Formats + + + + External Resources + External Resources + + + + External Tables + External Tables + + + + Always Encrypted Keys + Always Encrypted Keys + + + + Column Master Keys + Column Master Keys + + + + Column Encryption Keys + Column Encryption Keys + + + + Server + Server + + + + Error parsing ScriptingParams.ConnectionString property. + Error parsing ScriptingParams.ConnectionString property. + + + + Invalid directory specified by the ScriptingParams.FilePath property. + Invalid directory specified by the ScriptingParams.FilePath property. + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + No default + No default + + + + Input + Input + + + + Input/Output + Input/Output + + + + Input/ReadOnly + Input/ReadOnly + + + + Input/Output/ReadOnly + Input/Output/ReadOnly + + + + Default + Default + + + + null + null + + + + not null + not null + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + {0} ({1}) + {0} ({1}) + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1}Computed, {2}, {3}) + + + + {0} ({1}Computed) + {0} ({1}Computed) + + + + {0} (Column Set, {1}) + {0} (Column Set, {1}) + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Column Set, {1}{2}, {3}) + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Column Set, {1}, {2}, {3}) + + + + Unique + Unique + + + + Non-Unique + Non-Unique + + + + Clustered + Clustered + + + + Non-Clustered + Non-Clustered + + + + History + History + + + + System-Versioned + System-Versioned + + + + The database {0} is not accessible. + The database {0} is not accessible. + + + + Query has no results to return + Query has no results to return + + + + Result set has too many rows to be safely loaded + Result set has too many rows to be safely loaded + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + + + + Invalid path for database file: '{0}' + Invalid path for database file: '{0}' + + + + Log + Log + + + + Failed to create restore plan + Failed to create restore plan + + + + Restore database is not supported + Restore database is not supported + + + + Restore Database + Restore Database + + + + (Copy Only) + (Copy Only) + + + + Component + Component + + + + Type + Type + + + + Server + Server + + + + Database + Database + + + + Position + Position + + + + First LSN + First LSN + + + + Last LSN + Last LSN + + + + Checkpoint LSN + Checkpoint LSN + + + + Full LSN + Full LSN + + + + Start Date + Start Date + + + + Finish Date + Finish Date + + + + Size + Size + + + + User Name + User Name + + + + Expiration + Expiration + + + + Name + Name + + + + The last backup taken ({0}) + The last backup taken ({0}) + + + + Backup Database + Backup Database + + + + In progress + In progress + + + + Completed + Completed + + + + scripting + scripting + + + + Connection not found + Connection not found + + + + Cannot profile Azure system databases + Cannot profile Azure system databases + + + + Please provide a file path instead of directory path + Please provide a file path instead of directory path + + + + The provided path is invalid + The provided path is invalid + + + + Cannot access the specified path on the server: {0} + Cannot access the specified path on the server: {0} + + + + No backupset selected to be restored + No backupset selected to be restored + + + + Azure SQL DB + Azure SQL DB + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + Value {0} is too large to fit in column of type {1} + Value {0} is too large to fit in column of type {1} + . + Parameters: 0 - value (string), 1 - columnType (string) + + + Invalid format for column '{0}', column is defined as {1} + Invalid format for column '{0}', column is defined as {1} + . + Parameters: 0 - colName (string), 1 - colType (string) + + + Column with length is missing size + Column with length is missing size + + + + Scalar column missing scale + Scalar column missing scale + + + + -- TODO: Set parameter values here. + -- TODO: Set parameter values here. + + + + An error occurred while scripting the objects. + An error occurred while scripting the objects. + + + + Scripting as Execute is only supported for Stored Procedures + Scripting as Execute is only supported for Stored Procedures + + + + External + External + + + + File Table + File Table + + + + EditData queries targeting multiple tables are not supported + EditData queries targeting multiple tables are not supported + + + + EditData queries with aliased columns are not supported + EditData queries with aliased columns are not supported + + + + EditData queries with aggregate or expression columns are not supported + EditData queries with aggregate or expression columns are not supported + + + + EditData queries with duplicate columns are not supported + EditData queries with duplicate columns are not supported + + + + EditData queries must query the originally targeted table '{0}' + EditData queries must query the originally targeted table '{0}' + . + Parameters: 0 - tableName (string) + + + [Uncategorized (Local)] + [Uncategorized (Local)] + job categories + + + Jobs from MSX + Jobs from MSX + + + + [Uncategorized (Multi-Server)] + [Uncategorized (Multi-Server)] + + + + Database Maintenance + Database Maintenance + + + + Web Assistant + Web Assistant + + + + Full-Text + Full-Text + + + + REPL-Distribution + REPL-Distribution + + + + REPL-Distribution Cleanup + REPL-Distribution Cleanup + + + + REPL-History Cleanup + REPL-History Cleanup + + + + REPL-LogReader + REPL-LogReader + + + + REPL-Merge + REPL-Merge + + + + REPL-Snapshot + REPL-Snapshot + + + + REPL-Checkup + REPL-Checkup + + + + REPL-Subscription Cleanup + REPL-Subscription Cleanup + + + + REPL-Alert Response + REPL-Alert Response + + + + REPL-QueueReader + REPL-QueueReader + + + + Replication + Replication + + + + [Uncategorized] + [Uncategorized] + + + + Log Shipping + Log Shipping + + + + Database Engine Tuning Advisor + Database Engine Tuning Advisor + + + + Data Collector + Data Collector + + + + A job named '{0}' already exists. Enter a unique name for the job. + A job named '{0}' already exists. Enter a unique name for the job. + . + Parameters: 0 - jobName (string) + + + The name of the job step cannot be blank. + The name of the job step cannot be blank. + + + + There is already a step named '{0}' for this job. You must specify a different name. + There is already a step named '{0}' for this job. You must specify a different name. + . + Parameters: 0 - jobName (string) + + + The name of the alert cannot be blank. + The name of the alert cannot be blank. + + + + Cannot create new alert. + Cannot create new alert. + + + + Cannot alter alert. + Cannot alter alert. + + + + SQL Server Agent Service Account + SQL Server Agent Service Account + + + + Proxy account '{0}' does not exist on the server. + Proxy account '{0}' does not exist on the server. + . + Parameters: 0 - proxyName (string) + + + The object does no longer exist on server. + The object does no longer exist on server. + + + + Unknown server type '{0}'. + Unknown server type '{0}'. + . + Parameters: 0 - serverTypeName (string) + + + The current login does not have permissions to set the database owner to '{0}' The database was created successfully however. + The current login does not have permissions to set the database owner to '{0}' The database was created successfully however. + . + Parameters: 0 - ownerName (string) + + + You must specify the Target Servers on which this multi server job will execute. + You must specify the Target Servers on which this multi server job will execute. + + + + Unexpected run type. + Unexpected run type. + + + + Unknown size unit {0} + Unknown size unit {0} + . + Parameters: 0 - unit (string) + + + Cannot find requested XEvent session + Cannot find requested XEvent session + + + + Failed to stop session: {0} + Failed to stop session: {0} + . + Parameters: 0 - error (String) + + + Failed to start session: {0} + Failed to start session: {0} + . + Parameters: 0 - error (String) + + + Failed to create session: {0} + Failed to create session: {0} + . + Parameters: 0 - error (String) + + + Failed to pause session: {0} + Failed to pause session: {0} + . + Parameters: 0 - error (String) + + + An XEvent session named {0} already exists + An XEvent session named {0} already exists + . + Parameters: 0 - sessionName (String) + + + Invalid Schedule + Invalid Schedule + Schedule error message + + + Select at least one day to be part of this weekly schedule. + Select at least one day to be part of this weekly schedule. + + + + The job schedule starting date cannot be greater than the ending date. + The job schedule starting date cannot be greater than the ending date. + + + + The job schedule starting time cannot be after the ending time. + The job schedule starting time cannot be after the ending time. + + + + The job schedule ending time must be after the starting time. + The job schedule ending time must be after the starting time. + + + + Start date must be on or after January 1, 1990. + Start date must be on or after January 1, 1990. + + + + There is already a schedule named '{0}' for this job. You must specify a different name. + There is already a schedule named '{0}' for this job. You must specify a different name. + . + Parameters: 0 - scheduleName (string) + + + Job server is not available + Job server is not available + Exception thrown when job server is not available + + + Never + Never + + + + Path {0} is not a valid directory + Path {0} is not a valid directory + + + + For directory {0} a file with name {1} already exist + For directory {0} a file with name {1} already exist + + + + Beginning execution loop + Beginning execution loop + + + + An error occurred while the batch was being executed, but the error has been ignored. + An error occurred while the batch was being executed, but the error has been ignored. + + + + Batch execution completed {0} times... + Batch execution completed {0} times... + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + + + + Invalid version '{0}' passed. Version must be in the format x.x.x.x where x is a number. + Invalid version '{0}' passed. Version must be in the format x.x.x.x where x is a number. + + + + Export bacpac + Export bacpac + + + + Import bacpac + Import bacpac + + + + Extract dacpac + Extract dacpac + + + + Deploy dacpac + Deploy dacpac + + + + Generate script + Generate script + + + + Apply schema compare changes + Apply schema compare changes + + + + Failed to find the specified change in the model + Failed to find the specified change in the model + + + + Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}' + Error encountered while trying to parse connection information for endpoint '{0}' with error message '{1}' + + + + Could not find the schema compare session to cancel + Could not find the schema compare session to cancel + + + + Unsupported Save Format: {0} + Unsupported Save Format: {0} + . + Parameters: 0 - formatName (string) + + + A request for file {0} is already in progress + A request for file {0} is already in progress + . + Parameters: 0 - filePath (string) + + + Cannot serialize more data as no request for file {0} could be found + Cannot serialize more data as no request for file {0} could be found + . + Parameters: 0 - filePath (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hans.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hans.resx new file mode 100644 index 0000000000..e1dd659e07 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hans.resx @@ -0,0 +1,489 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089连接参数不能为 null + OwnerUri 不能为 null 或为空 + SpecifiedUri '{0}' 没有已有的连接 + AuthenticationType 值"{0}" 无效。 有效值为 'Integrated' 和 'SqlLogin'。 + '{0}' 为无效的ApplicationIntent值。 有效值为 'ReadWrite' 和 'ReadOnly'。 + 连接已取消 + OwnerUri 不能为 null 或为空 + 连接详细信息的对象不能为 null + ServerName 不能是 null 或是空白 + 使用 SqlLogin 身份验证时,{0} 不可是 null 或是空 + 查询已完成,无法取消 + 查询成功取消,无法处理查询。找不到 URI 的所有者。 + 查询已被用户取消 + 该批处理尚未完成 + 批量索引不能小于 0 或大于批量的总数 + 结果集索引不能小于 0 或大于结果集的总数 + 返回的最大字节数必须大于零 + 返回的最大字符数必须大于零 + 返回的 XML 最大字节数必须大于零 + 访问方法不能设置为”只写“ + 在执行操作之前,必须初始化 FileStreamWrapper + 该 FileStreamWrapper 不能用于写入 + (1 行受到影响) + (影响 {0} 行) + 命令已成功完成。 + Msg {0},级别 {1},状态 {2},第 {3} {4} {5} 行 + 查询失败︰ {0} + (没有列名称) + 请求的查询不存在。 + 此编辑器未连接到数据库 + 此编辑器会话已有正在进行中的查询。请取消这项查询,或等待它完成 + OnInfoMessage 事件的发送者必须是 SqlConnection + 查询完成前,不能保存结果 + 保存任务时发生内部错误 + 相同路径的保存请求正在进行中 + 未能保存 {0}: {1} + 没有从服务器读取结果之前,无法读取子数据集 + 起始行不能小于 0 或大于结果集中的行数 + 行数必须是一个正整数 + 未能从结果集获取列架构 + 未能从结果集获取执行计划 + 这功能目前不支持 Azure SQL DB 和数据仓库︰ {0} + 查看定义的执行过程中出现意外的错误︰ {0} + 未找到结果。 + 检索不到任何数据库对象。 + 请连接到服务器。 + 操作超时。 + 此功能当前不支持此对象类型。 + 位置超出文件行范围 + 第 {0} 行位置超出数据列范围 + 起始位置 ({0},{1}) 必须先于或等于结束位置 ({2},{3}) + Msg {0},级别 {1} ,状态 {2},第 {3} 行 + Msg {0},级别 {1},状态 {2},过程 {3},第 {4} 行 + Msg {0},级别 {1},状态 {2} + 执行批处理时发生错误。错误消息︰ {0} + ({0} 行受到影响) + 前一次执行尚未完成。 + 出现脚本错误。 + 正在分析 {0} 时发现语法错误。 + 出现严重错误。 + 已执行完 {0} 次... + 您已取消查询。 + 执行批次处理时发生错误。 + 执行批次处理时发生错误,但该错误已被忽略。 + Beginning execution loop + 不支持命令 {0}。 + 找不到变量 {0}。 + SQL 执行错误︰ {0} + 批处理解析封装器执行︰{0} 找到位于第 {1} 行: {2} 描述︰{3} + 批处理解析封装器执行引擎所收到的消息︰ 消息︰ {0},详细的消息︰ {1} + 批处理解析封装器执行引擎批次结果集处理︰ DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 批处理解析封装器执行引擎批次处理结果集已完成。 + 正在取消批处理解析封装器的批处理执行。 + 脚本警告。 + 有关此错误的详细信息,请参阅产品文档中的疑难解答主题。 + 文件 '{0}' 被递归方式包含。 + 缺少结束注释标记 '*/'。 + 未闭合的引号后的字符字串。 + '{0}' 在分析时发现语法错误。 + 未定义变量 {0}。 + 测试 + 用空字符串取代空字符串。 + 编辑会话不存在 + 查询尚未完成 + 查询并非产生单一结果集 + 无法添加新数据行以更新缓存,操作失败 + 给定数据行 ID 已超出 edit cache 中数据行的范围 + 这个数据行已经有一个更新正在等待使用,因此它必须先恢复原状。 + 给定行 ID 没有正在等待的更新操作 + 找不到表格或视图的元数据 + 二进制列格示错误 + Boolean 列必须填入数字 1 或 0, 或字符串 true 或 false + 必填单元格的值缺失 + 这行即将被删除,其中的单元格无法被更新 + 列 ID 必须在数据列总数內才可被查询 + 列无法被编辑 + 找不到键列 + 必须提供输出文件名 + 数据库对象 {0} 无法被编辑 + 指定的 URI '{0}' 没有默认的连接 + 提交的任务正在进行,请等待它完成 + 十进制列缺少数值精度或小数位数 + <TBD> + 无法在结果缓冲区添加行,数据读取器不包含任何行 + TIME 列的取值范围必须在 00:00:00.0000000 至 23:59:59.9999999 之间 + 该列不允许Null 值 + 编辑会话已存在 + 编辑会话尚未初始化 + 编辑会话已被初始化 + 编辑会话已被初始化或正在初始化中 + 执行查询失败,查看消息了解更多详情 + 结果集的限制值不能为负数 + + 必须提供对象名称 + 不支持显式指定服务器或者数据库 + 数据表的元数据没有扩展属性 + 找不到请求编辑的数据表或视图 + 扩展数据库时出错: {0} + 连接到 {0} 时出错 + 聚合 + 服务器角色 + 应用程序角色 + 程序集 + 程序集文件 + 非对称密钥 + 非对称密钥 + 数据压缩选项 + 证书 + 文件表 + 证书 + CHECK 约束 + + 约束 + 协定 + 凭据 + 错误消息 + 服务器角色成员资格 + 数据库选项 + 数据库角色 + 角色成员资格 + 数据库触发器 + 默认约束 + 默认值 + 序列 + 终结点 + 事件通知 + 服务器事件通知 + 扩展属性 + 文件组 + 外键 + 全文目录 + 全文检索 + 函数 + 索引 + 内联函数 + + 链接的服务器 + 链接的服务器登录名 + 登录名 + 主密钥 + 主密钥 + 消息类型 + 表值函数 + 参数 + 分区函数 + 分区方案 + 权限 + 主键 + 可编程性 + 队列 + 远程服务绑定 + 返回列 + 角色 + 路由 + 规则 + 架构 + 安全性 + 服务器对象 + 管理 + 触发器 + Service Broker + 服务 + 签名 + 日志文件 + 统计信息 + 存储 + 存储过程 + 对称密钥 + 同义词 + + 触发器 + 类型 + 唯一键 + 用户定义的数据类型 + 用户定义的类型(CLR) + 用户 + 视图 + XML 索引 + XML 架构集合 + 用户定义的表类型 + 文件 + 缺少标题 + Broker 优先级 + 加密提供程序 + 数据库审核规范 + 数据库加密密钥 + 事件会话 + 全文非索引字表 + 资源池 + 审核 + 服务器审核规范 + 空间索引 + 工作负荷组 + SQL 文件 + 服务器函数 + SQL 类型 + 服务器选项 + 数据库关系图 + 系统表 + 数据库 + 系统约定 + 系统数据库 + 系统消息类型 + 系统队列 + 系统服务 + 系统存储过程 + 系统视图 + 数据层应用程序 + 扩展存储过程 + 聚合函数 + 近似数字 + 二进制字符串 + 字符串 + CLR 数据类型 + 配置函数 + 游标函数 + 系统数据类型 + 日期和时间 + 日期和时间函数 + 精确数字 + 系统函数 + 层次结构 ID 函数 + 数学函数 + 元数据函数 + 其他数据类型 + 其他函数 + 行集函数 + 安全函数 + 空间数据类型 + 字符串函数 + 系统统计函数 + 文本和图像函数 + Unicode 字符串 + 聚合函数 + 标量值函数 + 表值函数 + 系统扩展存储过程 + 内置类型 + 内置服务器角色 + 具有密码的用户 + 搜索属性列表 + 安全策略 + 安全谓词 + 服务器角色 + 搜索属性列表 + 列存储索引 + 表类型索引 + 选择性 XML 索引 + XML 命名空间 + XML 特型提升路径 + T-SQL 特型提升路径 + 数据库范围的凭据 + 外部数据源 + 外部文件格式 + 外部资源 + 外部表 + Always Encrypted 密钥 + 列主密钥 + 列加密密钥 + 服务器 + 解析属性 ScriptingParams.ConnectionString 时出错 + ScriptingParams.FilePath 属性指定的路径是无效目录 + 解析属性 ScriptingListObjectsCompleteParams.ConnectionString 时出错 + {0} ({1}, {2}, {3}) + 无默认值 + 输入 + 输入/输出 + 输入/只读 + 输入/输出/只读 + 默认值 + Null + 非 Null + {0} ({1}, {2}) + {0} ({1}) + {0} ({1}Computed, {2}, {3}) + {0} ({1}Computed) + {0} (列集,{1}) + {0} (列集,{1}{2},{3}) + {0} (列集,{1},{2},{3}) + 唯一 + 非唯一 + 聚集 + 非聚集 + 历史记录 + 带有系统版本 + 不可用 + 当前默认文件组: {0} + {0} 的新文件组 + 默认值 + 文件 + 名称 + 只读 + 自动增长/最大大小 + ... + <默认值> + 文件组 + 逻辑名 + 文件类型 + 初始大小 (MB) + <新文件组> + 路径 + 文件名 + <原始设备> + 批量记录的 + + 简单 + 选择数据库所有者 + + 增量为 {0} MB,限制为 {1} MB + 增量为 {0}%,限制为 {1} MB + 增量为 {0} MB,增长无限制 + 增量为 {0}%,增长无限制 + 无限制 + 不超过{0} MB + 自动 + Service Broker + 排序规则 + 游标 + 杂项 + 恢复 + 状态 + ANSI NULL 默认值 + 启用 ANSI NULLS + ANSI 填充已启用 + 启用 ANSI 警告 + 算术中止已启用 + 自动关闭 + 自动创建统计信息 + 自动收缩 + 自动更新统计信息 + 自动异步更新统计信息 + 区分大小写的 + 已启用“提交时关闭游标” + 排序规则 + 串联 Null 时得到 Null + 数据库兼容级别 + 数据库状态 + 默认游标 + 已启用全文索引 + 数值舍入 —— 中止 + 页验证 + 已启用 Quoted Identifiers + 数据库为只读的 + 已启用 Recursive Triggers + 限制访问 + Select Into/Bulk Copy + 优先处理 Broker 优先级 + Service Broker Identifier + 已启用 Broker + 在检查点删除日志 + 启用跨数据库所有权链接 + 可信 + Date Correlation Optimization 已启用 prototype_db_prop_parameterization = Parameterization + 强迫的 + 简单 + 行数据 + 日志 + FILESTREAM 数据 + 不适用 + <默认路径> + 开着的连接 + SQL Server 需要关闭所有其它连接来改变数据库属性——你确认要改变属性并关闭所有其它连接吗? + AUTO_CLOSED + 紧急 + 不可访问 + 一般 + 离线 + 恢复中 + 等待恢复 + 恢复中 + 关机 + 待机 + 怀疑 + 全局 + ju + MULTI_USER + RESTRICTED_USER + SINGLE_USER + 校验码 + 没有 + TORN_PAGE_DETECTION + 启用 VarDecimal 存储格式 + SQL Server 2008 (100) + 启用加密 + + + 首要的 + 对于分配政策HASH,开始的哈希列的数量是可选的,但是应在1到16之间 + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + + 部分 + FILESTREAM 文件 + 没有可用的文件组 + 数据库 {0} 无法访问。 + 无查询结果 + 资料行因结果集太长而可能无法加载 + 参数化 + 当使用 NORECOVERY 选项还原备份时,不允许指定此选项。 + 数据库文件的路径无效:“{0}” + 日志 + 制订还原计划失败 + 不支持还原数据库 + 还原数据库 + (仅复制) + 组件 + 类型 + 服务器 + 数据库 + 位置 + 第一个 LSN + 最后一个 LSN + 检查点 LSN + 完整 LSN + 开始日期 + 完成日期 + 大小 + 用户名 + 过期 + 名称 + 上次执行的备份({0}) + 备份数据库 + 正在进行 + 已完成 + 开始执行脚本操作 + 找不到连接 + 所指定的文件名同时也是一个文件目录名: {0} + 无法验证备份文件的位置是否存在: {0} + 无法访问服务器上的指定路径: {0} + 未选择用于还原的备份集 + 从不 + Azure SQL 数据库 + Azure SQL 数据仓库 + Azure SQL Stretch Database + 路径 {0} 不是有效的目录 + {0} 文件夹中已存在名为 {1} 的文件 + 值 {0} 太大,无法放入类型为 {1} 的列 + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hant.resx b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hant.resx new file mode 100644 index 0000000000..1375592331 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/sr.zh-hant.resx @@ -0,0 +1,491 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +text/microsoft-resx1.3System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089連接參數不可為 null + OwnerUri 不能為 null 或空白 + SpecifiedUri '{0}' 沒有現有的連線 + AuthenticationType 值 "{0}" 無效。 有效值為 'Integrated' 和 'SqlLogin'。 + '{0}' 為無效的ApplicationIntent值。 有效值為 'ReadWrite' 和 'ReadOnly'。 + 已取消連線 + OwnerUri 不能是 null 或空白 + 連線詳細資料物件不能是 null + ServerName 不能是 null 或空白 + 使用 SqlLogin 驗證時,{0} 不可為 null 或是空白 + 查詢已完成,無法取消 + 成功地取消查詢,無法處置查詢。找不到擁有者 URI 。 + 使用者已取消查詢 + 批次尚未完成 + 批次索引不能小於 0 或大於批次的總數 + 結果集的索引不能小於 0 或大於結果集的總數 + 傳回的最大位元組數目必須大於零 + 傳回的最大字元數目必須大於零 + 傳回的最大 XML 位元組數目必須大於零 + 存取方法不可以設為唯寫 + 執行前,必須先初始化 FileStreamWrapper + 這個 FileStreamWrapper 不能用於寫入 + (1 列受影響) + ({0} 個資料列受到影響) + 命令已順利完成。 + 訊息 {0},層級 {1} ,狀態 {2},第 {3} {4} {5} 行 + 查詢失敗︰ {0} + (沒有資料行名稱) + 所要求的查詢不存在 + 這個編輯器尚未連接到資料庫 + 一個查詢已在這個編輯器工作階段。請取消這項查詢,或等待其完成。 + OnInfoMessage 事件的寄件者必須是一個 SqlConnection。 + 完成查詢執行前無法儲存結果 + 在儲存工作啟動時,發生內部錯誤 + 相同路徑的儲存要求正在進行中 + 無法儲存 {0}: {1} + 從伺服器讀取結果前,無法讀取子集 + 開始資料列不能小於 0 或大於結果集中的資料列總數 + 資料列計數必須是正整數 + 無法從結果集擷取資料行結構描述 + 無法從結果集擷取執行計劃 + 這項功能目前不支援 Azure SQL 資料庫和資料倉儲︰ {0} + 查看定義執行過程中發生未預期的錯誤︰ {0} + 找不到任何結果。 + 沒有資料庫物件被擷取。 + 請連線到伺服器。 + 作業逾時。 + 此功能目前不支援這種物件類型。 + 位置超出檔案行範圍 + 第 {0} 行位置超出資料行範圍 + 開始位置 ({0},{1}) 必須先於或等於結束位置 ({2},{3}) + 訊息 {0},層級 {1} ,狀態 {2},第 {3} 行 + 訊息 {0} ,層級 {1}, 狀態 {2}, 程序 {3},第 {4} 行 + 訊息 {0},層級 {1} ,狀態 {2} + 處理批次時,發生錯誤。錯誤訊息是︰ {0} + ({0} 個資料列受到影響) + 前一個執行尚未完成。 + 發生指令碼的錯誤。 + 正在剖析 {0} 時遇到不正確的語法。 + 發生嚴重的錯誤。 + 已執行完成 {0} 次... + 您已取消查詢。 + 執行此批次時發生錯誤。 + 執行此批次時發生錯誤,但錯誤以忽略。 + Beginning execution loop + 不支援命令 {0}。 + 找不到變數 {0}。 + SQL 執行錯誤︰ {0} + 批次剖析器包裝函式執行︰位於第 {1} 行: {2} 描述︰{3} 找到 {0} + 批次剖析器包裝函式執行引擎批次所收到的訊息︰ 訊息︰ {0},詳細的訊息︰ {1} + 批次剖析器包裝函式執行引擎批次結果集處理︰ DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 批次剖析器包裝函式執行引擎批次結果集已完成。 + 正在取消批次剖析器包裝函式的批次執行。 + 指令碼警告。 + 有關此錯誤的詳細資訊,請參閱產品文件中的疑難排解主題。 + 檔案 '{0}' 具有遞迴。 + 遺漏結束的註解記號 ' * /'。 + 字元字串後有未封閉的雙引號 + 正在剖析 {0} 時遇到不正確的語法。 + 未定義變數 {0}。 + 測試 + 用空白字串取代空白字串。 + 編輯工作階段不存在 + 查詢尚未完成 + 查詢並非產生單一結果集 + 在 cashe 裡更新資料列失敗 + 提供的資料列識別碼已超出 edit cashe 中資料列的範圍 + 這個資料列已經有一個更新正在等待使用,因此它必須先恢復原狀。 + 這個資料列識別碼並沒有正在等待更新 + 找不到資料表或檢視表中繼資料 + 二進位資料欄格示錯誤 + Boolean 欄位必須填入數字 1 或 0, 或字串 true 或 false + 必填儲存格未填 + 這個資料列即將被刪除,其中的儲存格無法被更新 + 資料行識別碼必須在資料行總數內才可被查詢 + 資料行無法被編輯 + 找不到索引鍵資料行 + 必須提供輸出檔名 + 資料庫物件 {0} 無法被編輯 + 指定的 URI '{0}' 沒有預設的連線 + 認可的工作正在進行,請等待它完成 + 十進位資料行缺少數值有效位數或小數位數 + <TBD> + 無法在結果緩衝區加資料列,資料讀取器不包含資料列 + TIME 欄的值範圍必須在 00:00:00.0000000 至 23:59:59.9999999 之間 + 這欄不允許填入 NULL 值 + 編輯工作階段已存在 + 編輯工作階段尚未初始化 + 編輯工作階段已初始化 + 編輯工作階段已完成初始化或正在初始化 + 查詢執行失敗, 請查看詳細資訊 + 結果限制不能為負 + NULL + 必須提供物件名稱 + 不支援明確指定的伺服器或資料庫 + 資料表中繼資料無擴充屬性 + 找不到要編輯的資料表或檢視表 + 擴充資料庫時發生錯誤:{0} + 連接到 {0} 時發生錯誤 + 彙總 + 伺服器角色 + 應用程式角色 + 組件 + 組件檔 + 非對稱金鑰 + 非對稱金鑰 + 資料壓縮選項 + 憑證 + FileTable + 憑證 + 檢查條件約束 + 資料行 + 條件約束 + 合約 + 認證 + 錯誤訊息 + 伺服器角色成員資格 + 資料庫選項 + 資料庫角色 + 角色成員資格 + 資料庫觸發程序 + 預設條件約束 + 預設 + 序列 + 端點 + 事件告知 + 伺服器事件通知 + 擴充屬性 + 檔案群組 + 外部索引鍵 + 全文檢索目錄 + 全文檢索索引 + 函式 + 索引 + 內嵌函式 + 索引鍵 + 連結的伺服器 + 連結的伺服器登入 + 登入 + 主要金鑰 + 主要金鑰 + 訊息類型 + 資料表值函式 + 參數 + 資料分割函式 + 資料分割配置 + 權限 + 主索引鍵 + 可程式性 + 佇列 + 遠端服務繫結 + 傳回的資料行 + 角色 + 路由 + 規則 + 結構描述 + 安全性 + 伺服器物件 + 管理 + 觸發程序 + Service Broker + 服務 + 簽章 + 記錄檔 + 統計資料 + 儲存體 + 預存程序 + 對稱金鑰 + 同義資料表 + 資料表 + 觸發程序 + 型別 + 唯一索引鍵 + 使用者定義資料類型 + 使用者定義型別 (CLR) + 使用者 + 檢視 + XML 索引 + XML 結構描述集合 + 使用者定義資料表類型 + 檔案 + 遺漏標題 + Broker 優先權 + 密碼編譯提供者 + 資料庫稽核規格 + 資料庫加密金鑰 + 事件工作階段 + 全文檢索停用字詞表 + 資源集區 + 稽核 + 伺服器稽核規格 + 空間索引 + 工作負載群組 + SQL 檔案 + 伺服器函式 + SQL 類型 + 伺服器選項 + 資料庫圖表 + 系統資料表 + 資料庫 + 系統合約 + 系統資料庫 + 系統訊息類型 + 系統佇列 + 系統服務 + 系統預存程序 + 系統檢視表 + 資料層應用程式 + 擴充預存程序 + 彙總函式 + 近似數值 + 二進位字串 + 字元字串 + CLR 資料型別 + 組態函式 + 資料指標函式 + 系統資料型別 + 日期和時間 + 日期和時間函式 + 精確數值 + 系統函式 + 階層識別碼函式 + 數學函式 + 中繼資料函式 + 其他資料型別 + 其他函式 + 資料列集函式 + 安全性函式 + 空間資料型別 + 字串函式 + 系統統計函式 + 文字和影像函式 + Unicode 字元字串 + 彙總函式 + 純量值函式 + 資料表值函式 + 系統擴充預存程序 + 內建型別 + 內建伺服器角色 + 有密碼的使用者 + 搜尋屬性清單 + 安全性原則 + 安全性述詞 + 伺服器角色 + 搜尋屬性清單 + 資料行儲存索引 + 資料表類型索引 + 選擇性 XML 索引 + XML 命名空間 + XML 具類型的升級路徑 + T-SQL 具類型的升級路徑 + 資料庫範圍認證 + 外部資料來源 + 外部檔案格式 + 外部資源 + 外部資料表 + Always Encrypted 金鑰 + 資料行主要金鑰 + 資料行加密金鑰 + 伺服器 + 剖析屬性 ScriptingParams.ConnectionString 時發生錯誤 + ScriptingParams.FilePath 屬性指定的路径是無效目錄 + 剖析屬性 ScriptingListObjectsCompleteParams.ConnectionString 時發生錯誤 + {0} ({1},{2},{3}) + 無預設值 + 輸入 + 輸入/輸出 + 輸入/唯讀 + 輸入/輸出/唯讀 + 預設值 + Null + 非 Null + {0} ({1},{2}) + {0} ({1}) + {0} ({1} 已計算,{2},{3}) + {0} ({1} 已計算) + {0} (資料行集,{1}) + {0} (資料行集,{1}{2},{3}) + {0} (資料行集,{1},{2},{3}) + 唯一 + 非唯一 + 叢集 + 非叢集 + 歷程記錄 + 系統建立版本 + 無法使用 + 當前預設檔案群組: {0} + {0} 的新檔案群組 + 預設值 + 檔案 + 名稱 + 唯讀 + 自動成長 / 大小上限 + ... + <預設> + 檔案群組 + 邏輯名稱 + 檔案類型 + 初始大小 (MB) + <新增檔案群組> + 路徑 + 檔案名稱 + <未經處理的裝置> + 大量記錄 + Full + Simple + 選取資料庫擁有者 + + 以 {0} MB 為單位,限制為 {1} MB + 以百分之 {0} 為單位,限制為 {1} MB + 以 {0} MB 為單位,無限制 + 以百分之 {0} 為單位,無限制 + 無限制 + 限制為 {0} MB + 自動 + Service Broker + 定序 + 資料指標 + 其他 + 復原 + 狀態 + ANSI NULL 預設值 + ANSI NULLS 已啟用 + +ANSI Padding 已啟用 + ANSI Warnings 已啟用 + Arithmetic Abort 已啟用 + 自動關閉 + 自動建立統計資料 + 自動壓縮 + 自動更新統計資料 + 自動非同步更新統計資料 + 區分大小寫 + 認可時關閉資料指標已啟用 + 定序 + 串連 Null 產生 Null + 資料庫相容性層級 + 資料庫狀態 + 預設資料指標 + 全文檢索索引已啟用 + 數值捨入中止 + 頁面確認 + 引號識別碼已啟用 + 資料庫唯讀 + 遞迴觸發程序已啟用 + 限制存取 + 選取/大量複製 + 接受 Broker 優先權 + Service Broker 識別碼 + Broker 已啟用 + 在檢查點截斷記錄 + 已啟用跨資料庫擁有權鏈結 + 可信任 + 已啟用日期相互關聯最佳化 prototype_db_prop_parameterization = 參數化 + 強制 + 簡易 + 資料列資料 + LOG + FILESTREAM 資料 + 不適用 + <預設路徑> + 開啟連接 + 為了變更資料庫屬性,SQL Server必須關閉所有其他與資料庫的連線。 +確定要變更屬性並關閉所有其他連線嗎? + AUTO_CLOSED + EMERGENCY + INACCESSIBLE + NORMAL + OFFLINE + RECOVERING + RECOVERY PENDING + RESTORING + SHUTDOWN + STANDBY + SUSPECT + GLOBAL + LOCAL + MULTI_USER + RESTRICTED_USER + SINGLE_USER + CHECKSUM + NONE + TORN_PAGE_DETECTION + VarDecimal 儲存格式已啟用 + SQL Server 2008 (100) + 加密已啟用 + OFF + ON + PRIMARY + 散發原則 HASH 的前置雜湊資料行是選擇性的,但應該介於 1 到 16 個資料行之間。 + SQL Server 2012 (110) + SQL Server 2014 (120) + SQL Server 2016 (130) + SQL Server vNext (140) + + Partial + FILESTREAM 檔案 + 沒有適用的檔案群組 + 無法存取資料庫 {0}。 + 沒有查詢結果可以回傳 + 資料列因結果集太長而無法載入 + 參數化 + 不允許使用 NORECOVERY 選項還原備份時,請指定這個選項。 + 資料庫檔案的路徑無效: '{0}' + 記錄檔 + 無法建立還原計畫 + 不支援還原資料庫 + 還原資料庫 + (僅複製) + 元件 + 型別 + 伺服器 + 資料庫 + 位置 + 第一個 LSN + 最後一個 LSN + 檢查點 LSN + 完整 LSN + 開始日期 + 完成日期 + 大小 + 使用者名稱 + 逾期 + 名稱 + 上次建立的備份 ({0}) + 備份資料庫 + 進行中 + 已完成 + 指令碼 + 找不到連接 + 指定的檔案名稱也是目錄名稱: {0} + 無法確認備份檔案位置的存在: {0} + 無法存取伺服器上指定的路徑: {0} + 無選擇的備份集可還原 + 永不 + Azure SQL DB + Azure SQL 資料倉儲 + Azure SQL 延展資料庫 + 路徑 {0} 不是有效的目錄 + 因目錄 {0} 中已有存在的檔案名稱 {1} + 數值 {0} 太大以致於無法符合欄位型態 {1} + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.de.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.de.xlf new file mode 100644 index 0000000000..9f563c61a4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.de.xlf @@ -0,0 +1,2776 @@ + + + + + Connection parameters cannot be null + Verbindungsparameter dürfen nicht null sein. + + + + + OwnerUri cannot be null or empty + OwnerUri darf nicht null oder leer sein. + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' hat keine gültige Verbindung + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Ungültiger Wert '{0}' für AuthenticationType. Gültige Werte sind 'Integrated' und 'SqlLogin'. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Ungültiger Wert '{0}' für ApplicationIntent. Gültige Werte sind 'ReadWrite' und 'ReadOnly'. + + . + Parameters: 0 - intent (string) + + + Connection canceled + Verbindung wurde abgebrochen. + + + + + OwnerUri cannot be null or empty + OwnerUri darf nicht null oder leer sein. + + + + + Connection details object cannot be null + Verbindungsdetails-Objekt darf nicht null sein. + + + + + ServerName cannot be null or empty + ServerName darf nicht null oder leer sein. + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} darf bei Verwendung der SqlLogin-Authentifizierung nicht null oder leer sein + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + Die Abfrage wurde bereits abgeschlossen und kann nicht abgebrochen werden + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Abfrage wurde erfolgreich abgebrochen, Fehler beim Abfrage verfügen. Benutzer-URI nicht gefunden. + + + + + Query was canceled by user + Die Abfrage wurde vom Benutzer abgebrochen. + + + + + The batch has not completed, yet + Die Stapelverarbeitung ist noch nicht abgeschlossen + + + + + Batch index cannot be less than 0 or greater than the number of batches + Batch-Index darf nicht kleiner als 0 oder größer als die Anzahl der Batches sein. + + + + + Result set index cannot be less than 0 or greater than the number of result sets + Der Index der Ergebnismenge darf nicht kleiner als 0 oder größer als die Anzahl der Ergebnismengen sein + + + + + Maximum number of bytes to return must be greater than zero + Die maximale Anzahl an Bytes die zurückgeben wird, muss größer als 0 sein. + + + + + Maximum number of chars to return must be greater than zero + Die maximale Anzahl an Zeichen die zurückgeben werden, muss größer als 0 sein. + + + + + Maximum number of XML bytes to return must be greater than zero + Die maximale Anzahl an XML Bytes die zurückgeben wird, muss größer als 0 sein. + + + + + Access method cannot be write-only + Die Zugriffsmethode kann nicht write-only sein. + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper muss initialisiert werden, bevor Operationen ausführt werden können + + + + + This FileStreamWrapper cannot be used for writing + Diese FileStreamWrapper kann nicht zum Schreiben verwendet werden + + + + + (1 row affected) + (1 Zeile betroffen) + + + + + ({0} rows affected) + ({0} Zeilen betroffen) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Die Befehle wurden erfolgreich ausgeführt. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Zeile MSG {0} auf {1} Status {2}, {3} {4} {5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Fehler bei Abfrage: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Kein Spaltenname) + + + + + The requested query does not exist + Die angeforderte Abfrage ist nicht vorhanden. + + + + + This editor is not connected to a database + Dieser Editor ist nicht mit einer Datenbank verbunden. + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Eine Abfrage wird für diese Sitzung bereits ausgeführt. Brechen Sie diese Abfrage ab, oder warten Sie auf Beendigung. + + + + + Sender for OnInfoMessage event must be a SqlConnection + Das sender Objekt für OnInfoMessage muss vom Typ SqlConnection sein + + + + + Result cannot be saved until query execution has completed + Das Ergebnis kann nicht gespeichert werden, solange die Abfrageausführung nicht abgeschlossen ist. + + + + + Internal error occurred while starting save task + Beim Speichern ist ein interner Fehler aufgetreten + + + + + A save request to the same path is in progress + Eine Speicheranforderung mit demselben Pfad wird bereits ausgeführt. + + + + + Failed to save {0}: {1} + Fehler beim Speichern von {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Der Teil kann nicht gelesen werden solange die Ergebnisse nicht vom Server gelesen wurden + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Index der Startzeile kann nicht kleiner als 0 oder größer als die Anzahl der Zeilen der Ergebnismenge sein + + + + + Row count must be a positive integer + Zeilenanzahl muss eine positive ganze Zahl sein. + + + + + Could not retrieve column schema for result set + Es konnten keine Schemainformationen der Spalte abgerufen werden + + + + + Could not retrieve an execution plan from the result set + Es konnten kein Ausführungsplan für die Ergebnismenge abgerufen werden + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + Diese Funktionalität wird derzeit nicht in Azure SQL DB ud Data Warehouse unterstützt: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Ein unerwarteter Fehler trat beim Einsehen der Definitionen auf: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + Es wurden keine Ergebnisse gefunden. + + + + + No database object was retrieved. + Es wurde kein Datenbankobjekt abgerufen + + + + + Please connect to a server. + Verbinden Sie Sich mit einem Server. + + + + + Operation timed out. + Zeitüberschreitung bei der Ausführung + + + + + This object type is currently not supported by this feature. + Dieser Objekttyp wird aktuell von dieser Funktionalität nicht unterstützt + + + + + Position is outside of file line range + Die Position befindet sich außerhalb der Zeile + + + + + Position is outside of column range for line {0} + Die Position befindet sich außerhalb der Spalte in Zeile {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Startposition ({0}, {1}) muss vor oder gleich der Endposition ({2}, {3}) sein + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Meldung {0}, Ebene {1}, Status {2}, Zeile {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Meldung {0}, Ebene {1}, Status {2}, Prozedur {3}, Zeile {4} + + + + + Msg {0}, Level {1}, State {2} + Meldung {0}, Ebene {1}, Status {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + Fehler beim Ausführen des Batches. Fehlermeldung: {0} + + + + + ({0} row(s) affected) + ({0} Zeile(n) betroffen) + + + + + The previous execution is not yet complete. + Die vorherige Ausführung ist noch nicht abgeschlossen. + + + + + A scripting error occurred. + Ein Skriptfehler ist aufgetreten. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Ein Syntaxfehler ist aufgetreten der bei Analyse von {0} + + + + + A fatal error occurred. + Ein schwerwiegender Fehler ist aufgetreten. + + + + + Batch execution completed {0} times... + {0}-mal ausgeführt... + + + + + You cancelled the query. + Sie haben die Abfrage abgebrochen. + + + + + An error occurred while the batch was being executed. + Fehler während der Batchausführung. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + Fehler während der Batchausführung, aber des Fehlers wurde ignoriert. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + Befehl {0} wird nicht unterstützt. + + + + + The variable {0} could not be found. + Die Variable {0} konnte nicht gefunden werden. + + + + + SQL Execution error: {0} + Fehler bei der SQL-Ausführung: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Batch-Ausführung des Batchanalysewrappers: {0} in Zeile {1} gefunden...: {2} Beschreibung: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Batch Parser Wrapper Execution Engine Meldung empfangen: Meldung: {0} Ausführliche Meldung: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Stapelverarbeitung Parser Wrapper Execution Engine Stapel ResultSet: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + Batch-Parser Wrapper Execution Engine wurde beendet ResultSet. + + + + + Canceling batch parser wrapper batch execution. + Ausführung des Batchanalysewrappers Batch abgebrochen. + + + + + Scripting warning. + Scripting-Warnung. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Weitere Informationen zu diesem Fehler finden Sie in den entsprechenden Abschnitten der Produktdokumentation. + + + + + File '{0}' recursively included. + Die Datei '{0}' ist rekursiv eingeschlossen. + + + + + Missing end comment mark '*/'. + Fehlender End Kommentarzeichen "* /". + + + + + Unclosed quotation mark after the character string. + Fehlendes schließendes Anführungszeichen nach der Zeichenfolge + + + + + Incorrect syntax was encountered while parsing '{0}'. + Syntaxfehler aufgetreten beim Analysieren von '{0}'. + + + + + Variable {0} is not defined. + Variable {0} ist nicht definiert. + + + + + test + Test + + + + + Replacement of an empty string by an empty string. + Ersatz einer leeren Zeichenfolge durch eine leere Zeichenfolge. + + + + + Edit session does not exist. + Die Sitzung "{0}" ist nicht vorhanden. + + + + + Query has not completed execution + Die Abfrage wurde nicht abgeschlossen + + + + + Query did not generate exactly one result set + Die Abfrage erzeugte mehr als eine Ergebnismenge + + + + + Failed to add new row to update cache + Fehler beim Hinzufügen einer neuen Zeile zum Aktualisierungscache + + + + + Given row ID is outside the range of rows in the edit cache + Die angegebene Zeilen-ID ist außerhalb des Bereiches des Bearbeitungscaches + + + + + An update is already pending for this row and must be reverted first + Für diese Zeile steht eine Aktualisierung an, die erst zurückgenommen werden muß + + + + + Given row ID does not have pending update + Die angegebene Zeilen-ID hat keine ausstehenden Aktualisierungen + + + + + Table or view metadata could not be found + Tabellen oder Sicht Metadaten konnten nicht gefunden werden + + + + + Invalid format for binary column + Ungültiges Format für eine binäre Spalte + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Spalten vom Typ Boolean müssen entweder der Zahl 0 oder 1 oder der Zeichenkette true oder false entsprechen + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Ein Pflichtfeld hat keinen Wert. + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + Für diese Zeile steht ein Löschbefehl aus, die Aktualisierung von Feldern kann nicht durchgeführt werden. + + + + + Column ID must be in the range of columns for the query + Die ID der Spalte muss innerhalb des Bereichs der Spalten der Abfrage sein + + + + + Column cannot be edited + Die Spalte kann nicht editiert werden + + + + + No key columns were found + Keine Schlüsselspalten gefunden + + + + + An output filename must be provided + Der Name der Ausgabedatei muss angegeben werden + + + + + Database object {0} cannot be used for editing. + Das Datenbankobjekt {0} kan nicht editiert werden + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + Spezifizierte URI '{0}' hat keine Standardverbindung + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Eine Commit-Anweisung wird ausgeführt. Bitte warten Sie bis zur Fertigstellung + + + + + Decimal column is missing numeric precision or numeric scale + Für die Decimal-Spalte fehlt die Angabe der Genauigkeit und Dezimalstellenanzahl + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + Kann Zeile nicht an Ergebnisbuffer anhängen, da keine Zeilen im Datareader enthalten sind. + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + Der Wert für eine Spalte vom Typ TIME muss zwischen 00:00:00.0000000 und 23:59:59.9999999 liegen + + + + + NULL is not allowed for this column + NULL ist für diese Spalte nicht erlaubt + + + + + Edit session already exists. + Es gibt bereits eine Session + + + + + Edit session has not been initialized + Eine Session wurde nocht nicht initialisiert + + + + + Edit session has already been initialized + Eine Session wurde bereits initialisiert + + + + + Edit session has already been initialized or is in the process of initializing + Eine Session wurde bereits initialisiert oder befindet sich im Prozess der Initialisierung. + + + + + Query execution failed, see messages for details + Fehler beim Ausführen der Abfrage. Weitere Informationen finden SIe in der Ausgabe + + + + + Result limit cannot be negative + Die Ergebnismengengrenze darf nicht negativ sein + + + + + NULL + NULL + + + + + A object name must be provided + Der Name des Objekts muss angegeben werden + + + + + Explicitly specifying server or database is not supported + Einen bestimmten Server oder Datenbank auszuwählen wird nicht unterstützt. + + + + + Table metadata does not have extended properties + Die Metadaten der Tabelle enthält keine erweiterten EIgenschaften. + + + + + Table or view requested for edit could not be found + Tabelle oder Sicht zur Bearbeitung konnte nicht gefunden werden + + + + + Error expanding: {0} + Fehler beim Erweitern von: {0} + + + + + Error connecting to {0} + Fehler bei der Verbindung zu {0} + + + + + Aggregates + Aggregate + + + + + Server Roles + Serverrollen + + + + + Application Roles + Anwendungsrollen + + + + + Assemblies + Assemblys + + + + + Assembly Files + Assemblydateien + + + + + Asymmetric Keys + Asymmetrische Schlüssel + + + + + Asymmetric Keys + Asymmetrische Schlüssel + + + + + Data Compression Options + Datenkomprimierungsoptionen + + + + + Certificates + Zertifikate + + + + + FileTables + FileTables + + + + + Certificates + Zertifikate + + + + + Check Constraints + Einschränkungen überprüfen + + + + + Columns + Spalten + + + + + Constraints + Einschränkungen + + + + + Contracts + Verträge + + + + + Credentials + Anmeldeinformationen + + + + + Error Messages + Fehlermeldungen + + + + + Server Role Membership + Serverrollenmitgliedschaft + + + + + Database Options + Datenbankoptionen + + + + + Database Roles + Datenbankrollen + + + + + Role Memberships + Rollenmitgliedschaften + + + + + Database Triggers + Datenbanktrigger + + + + + Default Constraints + DEFAULT-Einschränkungen + + + + + Defaults + Standardwerte + + + + + Sequences + Sequenzen + + + + + Endpoints + Endpunkte + + + + + Event Notifications + Ereignisbenachrichtigungen + + + + + Server Event Notifications + Serverbenachrichtigungsereignisse + + + + + Extended Properties + Erweiterte Eigenschaften + + + + + Filegroups + Dateigruppen + + + + + Foreign Keys + Fremdschlüssel + + + + + Full-Text Catalogs + Volltextkataloge + + + + + Full-Text Indexes + Volltextindizes + + + + + Functions + Funktionen + + + + + Indexes + Indizes + + + + + Inline Functions + Inlinefunktionen + + + + + Keys + Schlüssel + + + + + Linked Servers + Verbindungsserver + + + + + Linked Server Logins + Anmeldungen für Verbindungsserver + + + + + Logins + Anmeldungen + + + + + Master Key + Hauptschlüssel + + + + + Master Keys + Hauptschlüssel + + + + + Message Types + Meldungstypen + + + + + Table-Valued Functions + Tabellenwertfunktionen + + + + + Parameters + Parameter + + + + + Partition Functions + Partitionsfunktionen + + + + + Partition Schemes + Partitionsschemas + + + + + Permissions + Berechtigungen + + + + + Primary Keys + Primärschlüssel + + + + + Programmability + Programmierbarkeit + + + + + Queues + Warteschlangen + + + + + Remote Service Bindings + Remotedienstbindungen + + + + + Returned Columns + Zurückgegebene Spalten + + + + + Roles + Rollen + + + + + Routes + Routen + + + + + Rules + Regeln + + + + + Schemas + Schemas + + + + + Security + Sicherheit + + + + + Server Objects + Serverobjekte + + + + + Management + Verwaltung + + + + + Triggers + Trigger + + + + + Service Broker + Service Broker + + + + + Services + Dienste + + + + + Signatures + Signaturen + + + + + Log Files + Protokolldateien + + + + + Statistics + Statistik + + + + + Storage + Speicher + + + + + Stored Procedures + Gespeicherte Prozeduren + + + + + Symmetric Keys + Symmetrische Schlüssel + + + + + Synonyms + Synonyme + + + + + Tables + Tabellen + + + + + Triggers + Trigger + + + + + Types + Typen + + + + + Unique Keys + Eindeutige Schlüssel + + + + + User-Defined Data Types + Benutzerdefinierte Datentypen + + + + + User-Defined Types (CLR) + Benutzerdefinierte Typen (CLR) + + + + + Users + Benutzer + + + + + Views + Sichten + + + + + XML Indexes + XML-Indizes + + + + + XML Schema Collections + XML-Schemaauflistungen + + + + + User-Defined Table Types + Benutzerdefinierte Tabellentypen + + + + + Files + Dateien + + + + + Missing Caption + Fehlende Beschriftung + + + + + Broker Priorities + Brokerprioritäten + + + + + Cryptographic Providers + Kryptografieanbieter + + + + + Database Audit Specifications + Datenbank-Überwachungsspezifikationen + + + + + Database Encryption Keys + Verschlüsselungsschlüssel für Datenbank + + + + + Event Sessions + Ereignissitzungen + + + + + Full Text Stoplists + Volltext-Stopplisten + + + + + Resource Pools + Ressourcenpools + + + + + Audits + Überwachungen + + + + + Server Audit Specifications + Serverüberwachungsspezifikationen + + + + + Spatial Indexes + Räumliche Indizes + + + + + Workload Groups + Arbeitsauslastungsgruppen + + + + + SQL Files + SQL-Dateien + + + + + Server Functions + Serverfunktionen + + + + + SQL Type + SQL-Typ + + + + + Server Options + Serveroptionen + + + + + Database Diagrams + Datenbankdiagramme + + + + + System Tables + Systemtabellen + + + + + Databases + Datenbanken + + + + + System Contracts + Systemverträge + + + + + System Databases + Systemdatenbanken + + + + + System Message Types + Systemmeldungstypen + + + + + System Queues + Systemwarteschlangen + + + + + System Services + Systemdienste + + + + + System Stored Procedures + Gespeicherte Systemprozeduren + + + + + System Views + Systemsichten + + + + + Data-tier Applications + Datenebenenanwendungen + + + + + Extended Stored Procedures + Erweiterte gespeicherte Prozeduren + + + + + Aggregate Functions + Aggregatfunktionen + + + + + Approximate Numerics + Ungefähre numerische Ausdrücke + + + + + Binary Strings + Binärzeichenfolgen + + + + + Character Strings + Zeichenfolgen + + + + + CLR Data Types + CLR-Datentypen + + + + + Configuration Functions + Konfigurationsfunktionen + + + + + Cursor Functions + Cursorfunktionen + + + + + System Data Types + Systemdatentypen + + + + + Date and Time + Datum und Uhrzeit + + + + + Date and Time Functions + Datums- und Uhrzeitfunktionen + + + + + Exact Numerics + Genaue numerische Ausdrücke + + + + + System Functions + Systemfunktionen + + + + + Hierarchy Id Functions + Hierarchie-ID-Funktionen + + + + + Mathematical Functions + Mathematische Funktionen + + + + + Metadata Functions + Metadatenfunktionen + + + + + Other Data Types + Andere Datentypen + + + + + Other Functions + Andere Funktionen + + + + + Rowset Functions + Rowsetfunktionen + + + + + Security Functions + Sicherheitsfunktionen + + + + + Spatial Data Types + Räumliche Datentypen + + + + + String Functions + Zeichenfolgenfunktionen + + + + + System Statistical Functions + Statistische Systemfunktionen + + + + + Text and Image Functions + Text- und Bildfunktionen + + + + + Unicode Character Strings + Unicode-Zeichenfolgen + + + + + Aggregate Functions + Aggregatfunktionen + + + + + Scalar-valued Functions + Skalarwertfunktionen + + + + + Table-valued Functions + Tabellenwertfunktionen + + + + + System Extended Stored Procedures + Erweiterte gespeicherte Systemprozeduren + + + + + Built-in Types + Integrierte Typen + + + + + Built-in Server Roles + Integrierte Serverrollen + + + + + User with Password + Benutzer mit Kennwort + + + + + Search Property List + Sucheigenschaftenliste + + + + + Security Policies + Sicherheitsrichtlinien + + + + + Security Predicates + Sicherheitsprädikate + + + + + Server Role + Serverrolle + + + + + Search Property Lists + Sucheigenschaftenlisten + + + + + Column Store Indexes + Spaltenspeicherindizes + + + + + Table Type Indexes + Tabellentypindex + + + + + Selective XML Indexes + Selektive XML-Indexe + + + + + XML Namespaces + XML-Namespaces + + + + + XML Typed Promoted Paths + XML-typisierte höher gestufte Pfade + + + + + T-SQL Typed Promoted Paths + T-SQL-typisierte höher gestufte Pfade + + + + + Database Scoped Credentials + Datenbankweit gültige Anmeldeinformationen + + + + + External Data Sources + Externe Datenquellen + + + + + External File Formats + Externe Dateiformate + + + + + External Resources + Externe Ressourcen + + + + + External Tables + Externe Tabellen + + + + + Always Encrypted Keys + Immer verschlüsselte Schlüssel + + + + + Column Master Keys + Spaltenhauptschlüssel + + + + + Column Encryption Keys + Spaltenverschlüsselungsschlüssel + + + + + Server + Server + + + + + Error parsing ScriptingParams.ConnectionString property. + Fehler beim Analysieren der Eigenschaft ScriptingParams.ConnectionString. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + Ungültiges Verzeichnis angeben in der Eigenschaft ScriptingParams.FilePath. + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Fehler beim Analysieren der Eigenschaft ScriptingListObjectsCompleteParams.ConnectionString + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Kein Standard + + + + + Input + Eingabe + + + + + Input/Output + Eingabe/Ausgabe + + + + + Input/ReadOnly + Eingabe/schreibgeschützt + + + + + Input/Output/ReadOnly + Eingabe/Ausgabe/schreibgeschützt + + + + + Default + Standard + + + + + null + NULL + + + + + not null + nicht NULL + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1}berechnet, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1}berechnet) + + + + + {0} (Column Set, {1}) + {0} (Spaltensatz, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Spaltensatz, {1} {2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Spaltensatz, {1}, {2}, {3}) + + + + + Unique + Eindeutig + + + + + Non-Unique + Nicht eindeutig + + + + + Clustered + Gruppiert + + + + + Non-Clustered + Nicht gruppiert + + + + + History + Verlauf + + + + + System-Versioned + System-Mit Versionsangabe + + + + + Unavailable + Nicht verfügbar + + + + + Current default filegroup: {0} + Aktuelle Standarddateigruppe: {0} + + + + + New Filegroup for {0} + Neue Dateigruppe für "{0}" + + + + + Default + Standard + + + + + Files + Dateien + + + + + Name + Name + + + + + Read-Only + Schreibgeschützt + + + + + Autogrowth / Maxsize + Automatische Vergrößerung/Maximale Größe + + + + + ... + ... + + + + + <default> + <Standard> + + + + + Filegroup + Dateigruppe + + + + + Logical Name + Logischer Name + + + + + File Type + Dateityp + + + + + Initial Size (MB) + Anfangsgröße (MB) + + + + + <new filegroup> + <neue Dateigruppe> + + + + + Path + Pfad + + + + + File Name + Dateiname + + + + + <raw device> + <unformatiertes Medium> + + + + + Bulk-logged + Massenprotokolliert + + + + + Full + Vollständig + + + + + Simple + Einfach + + + + + Select Database Owner + Datenbankbesitzer auswählen + + + + + None + Kein(e) + + + + + By {0} MB, Limited to {1} MB + Um {0} MB, auf {1} MB beschränkt + + + + + By {0} percent, Limited to {1} MB + Um {0} Prozent, auf {1} MB beschränkt + + + + + By {0} MB, Unlimited + Um {0} MB, unbegrenzt + + + + + By {0} percent, Unlimited + Um {0} Prozent, unbegrenzt + + + + + Unlimited + Unbegrenzt + + + + + Limited to {0} MB + Auf {0} MB beschränkt + + + + + Automatic + Automatisch + + + + + Service Broker + Service Broker + + + + + Collation + Sortierung + + + + + Cursor + Cursor + + + + + Miscellaneous + Verschiedenes + + + + + Recovery + Wiederherstellung + + + + + State + Status + + + + + ANSI NULL Default + ANSI NULL Default + + + + + ANSI NULLS Enabled + ANSI NULLS aktiviert + + + + + ANSI Padding Enabled + ANSI-Auffüllung aktiviert + + + + + ANSI Warnings Enabled + ANSI Warnings aktiviert + + + + + Arithmetic Abort Enabled + Abbruch bei arithmetischem Fehler aktiviert + + + + + Auto Close + Automatisch schließen + + + + + Auto Create Statistics + Statistik automatisch erstellen + + + + + Auto Shrink + Automatisch verkleinern + + + + + Auto Update Statistics + Statistiken automatisch aktualisieren + + + + + Auto Update Statistics Asynchronously + Statistik automatisch asynchron aktualisieren + + + + + Case Sensitive + Unterscheidung nach Groß-/Kleinschreibung + + + + + Close Cursor on Commit Enabled + Schließen des Cursors nach Commit aktiviert + + + + + Collation + Sortierung + + + + + Concatenate Null Yields Null + Verketten von NULL-Werten ergibt NULL + + + + + Database Compatibility Level + Datenbank-Kompatibilitätsgrad + + + + + Database State + Datenbankstatus + + + + + Default Cursor + Standardcursor + + + + + Full-Text Indexing Enabled + Volltextindizierung aktiviert + + + + + Numeric Round-Abort + Abbruch bei numerischem Runden + + + + + Page Verify + Seitenüberprüfung + + + + + Quoted Identifiers Enabled + Bezeichner in Anführungszeichen aktiviert + + + + + Database Read-Only + Datenbank schreibgeschützt + + + + + Recursive Triggers Enabled + Rekursive Trigger aktiviert + + + + + Restrict Access + Zugriff beschränken + + + + + Select Into/Bulk Copy + Select Into/Bulk Copy + + + + + Honor Broker Priority + Brokerpriorität berücksichtigen + + + + + Service Broker Identifier + Service Broker-Bezeichner + + + + + Broker Enabled + Broker aktiviert + + + + + Truncate Log on Checkpoint + Protokoll bei Prüfpunkt abschneiden + + + + + Cross-database Ownership Chaining Enabled + Datenbankübergreifende Besitzverkettung aktiviert + + + + + Trustworthy + Vertrauenswürdig + + + + + Date Correlation Optimization Enabled + Optimierung der Datumskorrelation aktiviert: +prototype_db_prop_parameterization = Parameterization + + + + + Forced + Erzwungen + + + + + Simple + Einfach + + + + + ROWS Data + ROWS (Daten) + + + + + LOG + LOG + + + + + FILESTREAM Data + FILESTREAM-Daten + + + + + Not Applicable + Nicht zutreffend + + + + + <default path> + <Standardpfad> + + + + + Open Connections + Geöffnete Verbindungen + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Zum Ändern der Datenbankeigenschaften muss SQL Server alle anderen Verbindungen mit der Datenbank schließen. Möchten Sie wirklich die Eigenschaften ändern und alle anderen Verbindungen schließen? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + VarDecimal-Speicherformat aktiviert + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Verschlüsselung aktiviert + + + + + OFF + AUS + + + + + ON + EIN + + + + + PRIMARY + PRIMÄR + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Die Anzahl führender Hashspalten ist bei der HASH-Verteilungsrichtlinie optional, sollte aber zwischen 1 und 16 Spalten liegen. + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Kein(e) + + + + + Partial + Teilweise + + + + + FILESTREAM Files + FILESTREAM-Dateien + + + + + No Applicable Filegroup + Keine anwendbare Dateigruppe + + + + + The database {0} is not accessible. + Auf die Datenbank "{0}" kann nicht zugegriffen werden. + + + + + Query has no results to return + Abfrage hat keine Ergebnis zum Zurückgeben + + + + + Result set has too many rows to be safely loaded + Ergebnismenge ist zu groß, um sicher geladen zu werden + + + + Parameterization + Parametrisierung + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + Diese Option darf nicht angegeben werden, wenn eine Sicherung mit der NORECOVERY-Option wiederhergestellt wird. + + + + + Invalid path for database file: '{0}' + Ungültiger Pfad für Datenbankdatei: {0} + + + + + Log + Protokoll + + + + + Failed to create restore plan + Fehler beim Erstellen des Wiederherstellungsplan + + + + + Restore database is not supported + Wiederherstellen der Datenbank wird nicht unterstützt. + + + + + Restore Database + Datenbank wiederherstellen + + + + + (Copy Only) + (nur kopieren) + + + + + Component + Komponente + + + + + Type + Typ + + + + + Server + Server + + + + + Database + Datenbank + + + + + Position + Position + + + + + First LSN + Erste LSN + + + + + Last LSN + Letzte LSN + + + + + Checkpoint LSN + Prüfpunkt-LSN + + + + + Full LSN + Vollständige LSN + + + + + Start Date + Startdatum + + + + + Finish Date + Beendigungsdatum + + + + + Size + Größe + + + + + User Name + Benutzername + + + + + Expiration + Ablaufdatum + + + + + Name + Name + + + + + The last backup taken ({0}) + Letzte Sicherung ({0}) + + + + + Backup Database + Datenbank sichern + + + + + In progress + In Bearbeitung + + + + + Completed + Abgeschlossen + + + + + scripting + Skripterstellung + + + + + Connection not found + Verbindung nicht gefunden + + + + + Please provide a file path instead of directory path + Der angegebene Dateiname ist zugleich ein Verzeichnisname: {0} + + + + + The provided path is invalid + Es kann nicht überprüft werden, ob der Speicherort der Sicherungsdatei vorhanden ist: {0} + + + + + Cannot access the specified path on the server: {0} + Auf den angegebenen Pfad auf dem Server kann nicht zugegriffen werden: {0} + + + + + No backupset selected to be restored + Kein Sicherungssatz zur Wiederherstellung ausgewählt + + + + + Never + Nie + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + Der Pfad {0} ist kein gültiges Verzeichnis + + + + + For directory {0} a file with name {1} already exists + Die Datei {1} im Verzeichnis {0} existiert bereits. + + + + + Value {0} is too large to fit in column of type {1} + Der Wert {0} ist zu groß für eine Spalte mit dem Datentyp {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.es.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.es.xlf new file mode 100644 index 0000000000..d91d12a638 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.es.xlf @@ -0,0 +1,2775 @@ + + + + + Connection parameters cannot be null + Los parámetros de conexión no pueden ser nulos + + + + + OwnerUri cannot be null or empty + OwnerUri no puede ser nulo ni estar vacío + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' no tiene una conexión existente + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + El valor '{0}' no es válido para AuthenticationType. Los valores válidos son 'Integrated' y 'SqlLogin'. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + El valor '{0}' no es válido para ApplicationIntent. Los valores válidos son 'ReadWrite' y 'ReadOnly'. + + . + Parameters: 0 - intent (string) + + + Connection canceled + Conexión cancelada + + + + + OwnerUri cannot be null or empty + OwnerUri no puede ser nulo ni estar vacío + + + + + Connection details object cannot be null + El objeto de detalles de conexión no puede ser nulo + + + + + ServerName cannot be null or empty + ServerName no puede ser nulo ni estar vacío + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} no puede ser nulo ni estar vacío cuando se utiliza autenticación SqlLogin + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + Ya se ha completado la consulta, no se puede cancelar + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + La consulta fue cancelada con éxito, pero no se ha podido desechar. No se encontró el URI del propietario. + + + + + Query was canceled by user + Consulta cancelada por el usuario + + + + + The batch has not completed, yet + El lote aún no ha finalizado, + + + + + Batch index cannot be less than 0 or greater than the number of batches + Índice de lote no puede ser menor que 0 o mayor que el número de lotes + + + + + Result set index cannot be less than 0 or greater than the number of result sets + Índice del conjunto de resultados no puede ser menor que 0 o mayor que el número de conjuntos de resultados + + + + + Maximum number of bytes to return must be greater than zero + El número máximo de bytes a devolver debe ser mayor que cero + + + + + Maximum number of chars to return must be greater than zero + El número máximo de caracteres a devolver debe ser mayor que cero + + + + + Maximum number of XML bytes to return must be greater than zero + El número máximo de bytes XML a devolver debe ser mayor que cero + + + + + Access method cannot be write-only + El método de acceso no puede ser de sólo escritura + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper debe inicializarse antes de realizar operaciones + + + + + This FileStreamWrapper cannot be used for writing + Este FileStreamWrapper no se puede utilizar para escritura. + + + + + (1 row affected) + (1 fila afectada) + + + + + ({0} rows affected) + ({0} filas afectadas) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Comandos finalizados correctamente. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, nivel {1} estado {2}, línea {3} {4} {5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Error en la consulta: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Ningún nombre de columna) + + + + + The requested query does not exist + La consulta solicitada no existe + + + + + This editor is not connected to a database + Este editor no está conectado a una base de datos + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Una consulta ya está en curso para esta sesión de editor. Por favor, cancelar esta consulta o esperar su finalización. + + + + + Sender for OnInfoMessage event must be a SqlConnection + Remitente de eventos de OnInfoMessage debe ser un objeto SqlConnection + + + + + Result cannot be saved until query execution has completed + No se puede guardar el resultado hasta que haya finalizado la ejecución de la consulta + + + + + Internal error occurred while starting save task + Error interno al iniciar el guardado de la tarea + + + + + A save request to the same path is in progress + Una operacion de guardado en la misma ruta se encuentra en curso + + + + + Failed to save {0}: {1} + Error al guardar {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + No se puede leer el subconjunto, a menos que los resultados se han leído desde el servidor + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Fila de inicio no puede ser menor que 0 o mayor que el número de filas en el conjunto de resultados + + + + + Row count must be a positive integer + La cantidad de filas debe ser un entero positivo + + + + + Could not retrieve column schema for result set + No se pudo recuperar el esquema de columna para el conjunto de resultados + + + + + Could not retrieve an execution plan from the result set + No se pudo recuperar un plan de ejecución del conjunto de resultados + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + Esta característica actualmente no se admite en la base de datos de SQL Azure y almacén de datos: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Se ha producido un error inesperado durante la ejecución de la definición de Peek: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + No se encontraron resultados. + + + + + No database object was retrieved. + No se pudo obtener ningún objeto asociado a la base de datos. + + + + + Please connect to a server. + Por favor, conéctese a un servidor + + + + + Operation timed out. + Tiempo de espera agotado para esta operación. + + + + + This object type is currently not supported by this feature. + Esta característica no admite actualmente este tipo de objeto. + + + + + Position is outside of file line range + Posición está fuera del intervalo de la línea de archivo + + + + + Position is outside of column range for line {0} + Posición está fuera del intervalo de la columna de la línea {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Posición de inicio ({0}, {1}) debe preceder o ser igual a la posición final ({2}, {3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, {1}, nivel de estado {2}, línea {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msj {0}, {1}, nivel de estado {2}, procedimiento {3}, línea {4} + + + + + Msg {0}, Level {1}, State {2} + Msg {0}, nivel {1}, {2} de estado + + + + + An error occurred while the batch was being processed. The error message is: {0} + Se produjo un error al procesar el lote. Mensaje de error: {0} + + + + + ({0} row(s) affected) + ({0} filas afectadas) + + + + + The previous execution is not yet complete. + La ejecución anterior aún no está completa. + + + + + A scripting error occurred. + Se ha producido un error de secuencias de comandos. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Se encontró sintaxis incorrecta mientras se estaba analizando {0}. + + + + + A fatal error occurred. + Se ha producido un error grave. + + + + + Batch execution completed {0} times... + La ejecución se completó {0} veces... + + + + + You cancelled the query. + Se canceló la consulta. + + + + + An error occurred while the batch was being executed. + Se produjo un error mientras se ejecutaba el lote. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + Se produjo un error mientras se ejecutaba el lote, pero se ha omitido el error. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + No se admite el comando {0}. + + + + + The variable {0} could not be found. + La variable {0} no se encontró. + + + + + SQL Execution error: {0} + Error de ejecución de SQL: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Ejecución de contenedor del analizador por lotes: {0} se encuentra... en la línea {1}: {2} Descripción: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Lote analizador contenedor ejecución motor lote mensaje recibido: mensaje: {0} mensaje detallado: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Motor de ejecución de analizador contenedor lote ResultSet procesamiento por lotes: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + Finalizó el elemento ResultSet analizador contenedor ejecución motor los lotes. + + + + + Canceling batch parser wrapper batch execution. + Cancelando la ejecución por lotes del contenedor del analizador por lotes. + + + + + Scripting warning. + Advertencia de scripting. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Para obtener más información acerca de este error, vea los temas de solución de problemas en la documentación del producto. + + + + + File '{0}' recursively included. + El archivo '{0}' se incluyó recursivamente. + + + + + Missing end comment mark '*/'. + Falta la marca de final de comentario ' * /'. + + + + + Unclosed quotation mark after the character string. + Sin comilla de cierre después de la cadena de caracteres. + + + + + Incorrect syntax was encountered while parsing '{0}'. + Se encontró sintaxis incorrecta al analizar '{0}'. + + + + + Variable {0} is not defined. + La variable {0} no está definida. + + + + + test + prueba + + + + + Replacement of an empty string by an empty string. + Sustitución de una cadena vacía por una cadena vacía. + + + + + Edit session does not exist. + Sesión de edición no existe, + + + + + Query has not completed execution + La consulta no ha finalizado. + + + + + Query did not generate exactly one result set + La consulta no generó un único set de resultados + + + + + Failed to add new row to update cache + Falló al agregar una nueva fila a la caché de actualización + + + + + Given row ID is outside the range of rows in the edit cache + El ID de la fila ingresado, se encuentra fuera del rango de filas de la caché de edición + + + + + An update is already pending for this row and must be reverted first + Una actualización está pendiente para esta fila y debe de revertirse primero + + + + + Given row ID does not have pending update + El ID de la fila ingresado no tiene actualizaciones pendientes + + + + + Table or view metadata could not be found + La metadata de la tabla o vista no pudo ser encontrada + + + + + Invalid format for binary column + Formato inválido para columna binaria + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Columnas del tipo boolean deben de ser numéricos 1 o 0, o tipo string true o false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Falta un valor requerido de la celda + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + Existe una eliminación pendiente para esta fila, una actualización de celda no puede ser realizada. + + + + + Column ID must be in the range of columns for the query + El ID de la columna debe de estar en el rango de columnas de la consulta. + + + + + Column cannot be edited + La columna no puede ser editada + + + + + No key columns were found + No se encontró ninguna columna clave + + + + + An output filename must be provided + Proporcione un nombre de archivo de salida + + + + + Database object {0} cannot be used for editing. + Objeto de base de datos {0} no puede ser usado para modificación. + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + SpecifiedUri '{0}' no tiene alguna conexión por defecto + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Una tarea de confirmación se encuentra en progreso. Por favor espere que la operación termine. + + + + + Decimal column is missing numeric precision or numeric scale + Columna del tipo decimal no tiene precisión o escala numérica + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + No se pueden agregar filas al buffer de resultados, el lector de datos no contiene filas + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + Los valores en la columna TIME deben estar incluidos en el rango desde 00:00:00:000000 hasta 23:59:59.999999 + + + + + NULL is not allowed for this column + No se permite un valor NULL en esta columna + + + + + Edit session already exists. + La sesión de edición ya existe. + + + + + Edit session has not been initialized + La sesión de edición no se inicializó + + + + + Edit session has already been initialized + La sesión de edición ya se inicializó + + + + + Edit session has already been initialized or is in the process of initializing + La sesión de edición ya se inicializo o se encuentra en proceso de inicialización + + + + + Query execution failed, see messages for details + La ejecución de la consulta falló, ver los mensajes para obtener mas detalle + + + + + Result limit cannot be negative + El límite del resultado no puede ser negativo + + + + + NULL + NULL + + + + + A object name must be provided + Se debe proveer un nombre de objeto + + + + + Explicitly specifying server or database is not supported + No se permite especificar explícitamente el servidor o la base de datos + + + + + Table metadata does not have extended properties + Los metadatos de la tabla no tienen propiedades extendidas + + + + + Table or view requested for edit could not be found + La tabla o vista solicitada para edición no se encuentra + + + + + Error expanding: {0} + Error en expansión: {0} + + + + + Error connecting to {0} + Error conectando a {0} + + + + + Aggregates + Agregados + + + + + Server Roles + Roles de servidor + + + + + Application Roles + Roles de aplicación + + + + + Assemblies + Ensamblados + + + + + Assembly Files + Archivos de ensamblado + + + + + Asymmetric Keys + Claves asimétricas + + + + + Asymmetric Keys + Claves asimétricas + + + + + Data Compression Options + Opciones de compresión de datos + + + + + Certificates + Certificados + + + + + FileTables + Tablas de archivos + + + + + Certificates + Certificados + + + + + Check Constraints + Restricciones CHECK + + + + + Columns + Columnas + + + + + Constraints + Restricciones + + + + + Contracts + Contratos + + + + + Credentials + Credenciales + + + + + Error Messages + Mensajes de error + + + + + Server Role Membership + Pertenencia a roles de servidor + + + + + Database Options + Opciones de base de datos + + + + + Database Roles + Roles de base de datos + + + + + Role Memberships + Pertenencias a roles + + + + + Database Triggers + Desencadenadores de base de datos + + + + + Default Constraints + Restricciones DEFAULT + + + + + Defaults + Valores predeterminados + + + + + Sequences + Secuencias + + + + + Endpoints + Extremos + + + + + Event Notifications + Notificaciones de eventos + + + + + Server Event Notifications + Notificaciones de eventos de servidor + + + + + Extended Properties + Propiedades extendidas + + + + + Filegroups + Grupos de archivos + + + + + Foreign Keys + Claves externas + + + + + Full-Text Catalogs + Catálogos de texto completo + + + + + Full-Text Indexes + Índices de texto completo + + + + + Functions + Funciones + + + + + Indexes + Índices + + + + + Inline Functions + Funciones Inline + + + + + Keys + Claves + + + + + Linked Servers + Servidores vinculados + + + + + Linked Server Logins + Inicios de sesión de servidor vinculado + + + + + Logins + Inicios de sesión + + + + + Master Key + Clave maestra + + + + + Master Keys + Claves maestras + + + + + Message Types + Tipos de mensaje + + + + + Table-Valued Functions + Funciones con valores de tabla + + + + + Parameters + Parámetros + + + + + Partition Functions + Funciones de partición + + + + + Partition Schemes + Esquemas de partición + + + + + Permissions + Permisos + + + + + Primary Keys + Claves principales + + + + + Programmability + Programación + + + + + Queues + Colas + + + + + Remote Service Bindings + Enlaces de servicio remoto + + + + + Returned Columns + Columnas devueltos + + + + + Roles + Roles + + + + + Routes + Rutas + + + + + Rules + Reglas + + + + + Schemas + Esquemas + + + + + Security + Seguridad + + + + + Server Objects + Objetos de servidor + + + + + Management + Administración + + + + + Triggers + Desencadenadores + + + + + Service Broker + Service Broker + + + + + Services + Servicios + + + + + Signatures + Firmas + + + + + Log Files + Archivos de registro + + + + + Statistics + Estadísticas + + + + + Storage + Almacenamiento + + + + + Stored Procedures + Procedimientos almacenados + + + + + Symmetric Keys + Claves simétricas + + + + + Synonyms + Sinónimos + + + + + Tables + Tablas + + + + + Triggers + Desencadenadores + + + + + Types + Tipos + + + + + Unique Keys + Claves únicas + + + + + User-Defined Data Types + Tipos de datos definidos por el usuario + + + + + User-Defined Types (CLR) + Tipos definidos por el usuario (CLR) + + + + + Users + Usuarios + + + + + Views + Vistas + + + + + XML Indexes + Índices XML + + + + + XML Schema Collections + Colecciones de esquemas XML + + + + + User-Defined Table Types + Tipos de tablas definidos por el usuario + + + + + Files + Archivos + + + + + Missing Caption + Falta el título + + + + + Broker Priorities + Prioridades de Broker + + + + + Cryptographic Providers + Proveedores de servicios criptográficos + + + + + Database Audit Specifications + Especificaciones de auditoría de base de datos + + + + + Database Encryption Keys + Claves de cifrado de base de datos + + + + + Event Sessions + Sesiones de eventos + + + + + Full Text Stoplists + Listas de palabras irrelevantes de texto completo + + + + + Resource Pools + Grupos de recursos de servidor + + + + + Audits + Auditorías + + + + + Server Audit Specifications + Especificaciones de auditoría de servidor + + + + + Spatial Indexes + Índices espaciales + + + + + Workload Groups + Grupos de cargas de trabajo + + + + + SQL Files + Archivos SQL + + + + + Server Functions + Funciones de servidor + + + + + SQL Type + Tipo SQL + + + + + Server Options + Opciones de servidor + + + + + Database Diagrams + Diagramas de base de datos + + + + + System Tables + Tablas del sistema + + + + + Databases + Bases de datos + + + + + System Contracts + Contratos del sistema + + + + + System Databases + Bases de datos del sistema + + + + + System Message Types + Tipos de mensaje del sistema + + + + + System Queues + Colas del sistema + + + + + System Services + Servicios del sistema + + + + + System Stored Procedures + Procedimientos almacenados del sistema + + + + + System Views + Vistas del sistema + + + + + Data-tier Applications + Aplicaciones de capa de datos + + + + + Extended Stored Procedures + Procedimientos almacenados extendidos + + + + + Aggregate Functions + Funciones de agregado + + + + + Approximate Numerics + Valores numéricos aproximados + + + + + Binary Strings + Cadenas binarias + + + + + Character Strings + Cadenas de caracteres + + + + + CLR Data Types + Tipos de datos CLR + + + + + Configuration Functions + Funciones de configuración + + + + + Cursor Functions + Funciones del cursor + + + + + System Data Types + Tipos de datos del sistema + + + + + Date and Time + Fecha y hora + + + + + Date and Time Functions + Funciones de fecha y hora + + + + + Exact Numerics + Valores numéricos exactos + + + + + System Functions + Funciones del sistema + + + + + Hierarchy Id Functions + Funciones de id. de jerarquía + + + + + Mathematical Functions + Funciones matemáticas + + + + + Metadata Functions + Funciones de metadatos + + + + + Other Data Types + Otros tipos de datos + + + + + Other Functions + Otras funciones + + + + + Rowset Functions + Funciones de conjunto de filas + + + + + Security Functions + Funciones de seguridad + + + + + Spatial Data Types + Tipos de datos espaciales + + + + + String Functions + Funciones de cadena + + + + + System Statistical Functions + Funciones estadísticas del sistema + + + + + Text and Image Functions + Funciones de texto y de imagen + + + + + Unicode Character Strings + Cadenas de caracteres Unicode + + + + + Aggregate Functions + Funciones de agregado + + + + + Scalar-valued Functions + Funciones escalares + + + + + Table-valued Functions + Funciones con valores de tabla + + + + + System Extended Stored Procedures + Procedimientos almacenados extendidos del sistema + + + + + Built-in Types + Tipos integrados + + + + + Built-in Server Roles + Roles de servidor integrados + + + + + User with Password + Usuario con contraseña + + + + + Search Property List + Lista de propiedades de búsqueda + + + + + Security Policies + Directivas de seguridad + + + + + Security Predicates + Predicados de seguridad + + + + + Server Role + Rol de servidor + + + + + Search Property Lists + Listas de propiedades de búsqueda + + + + + Column Store Indexes + Índices de almacenamiento de columnas + + + + + Table Type Indexes + Índices de tipo de tabla + + + + + Selective XML Indexes + Índices XML selectivos + + + + + XML Namespaces + Espacios de nombres XML + + + + + XML Typed Promoted Paths + Rutas de acceso promovidas de tipo XML + + + + + T-SQL Typed Promoted Paths + Rutas de acceso promovidas de tipo T-SQL + + + + + Database Scoped Credentials + Credenciales de ámbito de base de datos + + + + + External Data Sources + Orígenes de datos externos + + + + + External File Formats + Formatos de archivo externo + + + + + External Resources + Recursos externos + + + + + External Tables + Tablas externas + + + + + Always Encrypted Keys + Siempre claves cifradas + + + + + Column Master Keys + Claves maestras de columna + + + + + Column Encryption Keys + Claves de cifrado de columna + + + + + Server + Servidor + + + + + Error parsing ScriptingParams.ConnectionString property. + Error interpretando la propiedad ScriptingParams.ConnectionString + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + El directorio especificado en la propiedad ScriptingParams.FilePath no es válido + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Error interpretando la propiedad ScriptingListObjectsCompleteParams.ConnectionString + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Sin valores predeterminados + + + + + Input + Entrada + + + + + Input/Output + Entrada/salida + + + + + Input/ReadOnly + Entrada/solo lectura + + + + + Input/Output/ReadOnly + Entrada/salida/solo lectura + + + + + Default + Predeterminado + + + + + null + NULL + + + + + not null + no es NULL + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1}calculado, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1}calculado) + + + + + {0} (Column Set, {1}) + {0} (Conjunto de columnas, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Conjunto de columnas, {1}{2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Conjunto de columnas, {1}, {2}, {3}) + + + + + Unique + Único + + + + + Non-Unique + No único + + + + + Clustered + Clúster + + + + + Non-Clustered + No en clúster + + + + + History + Historial + + + + + System-Versioned + Con versión del sistema + + + + + Unavailable + No disponible + + + + + Current default filegroup: {0} + Grupo de archivos predeterminado: {0} + + + + + New Filegroup for {0} + Grupo de archivos nuevo para: {0} + + + + + Default + Predeterminado + + + + + Files + Archivos + + + + + Name + Nombre + + + + + Read-Only + Solo lectura + + + + + Autogrowth / Maxsize + Crecimiento automático / tamaño máximo + + + + + ... + ... + + + + + <default> + <predeterminado> + + + + + Filegroup + Grupo de archivos + + + + + Logical Name + Nombre lógico + + + + + File Type + Tipo de archivo + + + + + Initial Size (MB) + Tamaño inicial (MB) + + + + + <new filegroup> + <nuevo grupo de archivos> + + + + + Path + Ruta de acceso + + + + + File Name + Nombre de archivo + + + + + <raw device> + <dispositivo sin formato> + + + + + Bulk-logged + Registro masivo + + + + + Full + Completo + + + + + Simple + Simple + + + + + Select Database Owner + Seleccionar propietario de base de datos + + + + + None + Ninguno + + + + + By {0} MB, Limited to {1} MB + Por {0} MB, limitado a {1} MB + + + + + By {0} percent, Limited to {1} MB + Por {0} porciento, limitado a {1} MB + + + + + By {0} MB, Unlimited + Por {0} MB, sin límite + + + + + By {0} percent, Unlimited + Por {0} porciento, sin límite + + + + + Unlimited + Sin límite + + + + + Limited to {0} MB + Limitado a {0} MB + + + + + Automatic + Automático + + + + + Service Broker + Service Broker + + + + + Collation + Intercalación + + + + + Cursor + Cursor + + + + + Miscellaneous + Varios + + + + + Recovery + Recuperación + + + + + State + Estado + + + + + ANSI NULL Default + ANSI NULL predeterminado + + + + + ANSI NULLS Enabled + ANSI NULLS habilitados + + + + + ANSI Padding Enabled + Relleno ANSI habilitado + + + + + ANSI Warnings Enabled + Advertencias ANSI habilitadas + + + + + Arithmetic Abort Enabled + Anulación aritmética habilitada + + + + + Auto Close + Cierre automático + + + + + Auto Create Statistics + Crear estadísticas automáticamente + + + + + Auto Shrink + Reducir automáticamente + + + + + Auto Update Statistics + Actualizar estadísticas automáticamente + + + + + Auto Update Statistics Asynchronously + Actualizar estadísticas automáticamente de forma asincrónica + + + + + Case Sensitive + Sensible a mayúsculas y minúsculas + + + + + Close Cursor on Commit Enabled + Cierre del cursor al confirmar habilitado + + + + + Collation + Intercalación + + + + + Concatenate Null Yields Null + Concatenar valores NULL produce NULL + + + + + Database Compatibility Level + Nivel de compatibilidad de base de datos + + + + + Database State + Estado de la base de datos + + + + + Default Cursor + Cursor predeterminado + + + + + Full-Text Indexing Enabled + Índice de texto completo habilitado + + + + + Numeric Round-Abort + Anular redondeo numérico + + + + + Page Verify + Comprobación de página + + + + + Quoted Identifiers Enabled + Identificadores entre comillas habilitados + + + + + Database Read-Only + Base de datos de solo lectura + + + + + Recursive Triggers Enabled + Desencadenadores recursivos habilitados + + + + + Restrict Access + Restringir acceso + + + + + Select Into/Bulk Copy + Select Into/Bulk Copy + + + + + Honor Broker Priority + Asignar prioridad de agente + + + + + Service Broker Identifier + Identificador de Service Broker + + + + + Broker Enabled + Broker habilitado + + + + + Truncate Log on Checkpoint + Truncar registro en el punto de control + + + + + Cross-database Ownership Chaining Enabled + Encadenamiento de propiedad entre bases de datos habilitado + + + + + Trustworthy + De confianza + + + + + Date Correlation Optimization Enabled + Optimización de correlación de fechas Enabledprototype_db_prop_parameterization = Parameterization + + + + + Forced + Forzado + + + + + Simple + Simple + + + + + ROWS Data + Datos de ROWS + + + + + LOG + LOG + + + + + FILESTREAM Data + Datos de FILESTREAM + + + + + Not Applicable + No aplicable + + + + + <default path> + <ruta predeterminada> + + + + + Open Connections + Conexiones abiertas + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Para cambiar las propiedades de la base de datos, SQL Server debe cerrar todas las otras conexiones a la base de datos. ¿Seguro que desea cambiar las propiedades y cerrar todas las otras conexiones? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + Formato de almacenamiento VarDecimal habilitado + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Cifrado habilitado + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Para la directiva de distribución HASH, el número de columnas iniciales hash es opcional pero debe de ser entre 1 y 16 columnas + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Ninguno + + + + + Partial + Parcial + + + + + FILESTREAM Files + Archivos FILESTREAM + + + + + No Applicable Filegroup + Grupo de archivos no aplicable + + + + + The database {0} is not accessible. + La base de datos {0} no es accesible. + + + + + Query has no results to return + La consulta no devolvió resultados + + + + + Result set has too many rows to be safely loaded + El conjunto de resultados contiene demasiada filas para cargarlo de forma segura + + + + Parameterization + Parametrización + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + No se permite restaurar una copia de seguridad con la opción NORECOVERY + + + + + Invalid path for database file: '{0}' + Ruta de archivo no válida: '{0}' + + + + + Log + Registro + + + + + Failed to create restore plan + No se pudo crear un plan de restauraciones + + + + + Restore database is not supported + No se admite restaurar la base de datos + + + + + Restore Database + Restaurar base de datos + + + + + (Copy Only) + (Copiar solamente) + + + + + Component + Componente + + + + + Type + Tipo + + + + + Server + Servidor + + + + + Database + Base de datos + + + + + Position + Posición + + + + + First LSN + Primer LSN + + + + + Last LSN + Último LSN + + + + + Checkpoint LSN + Checkpoint LSN + + + + + Full LSN + LSN completo + + + + + Start Date + Fecha de inicio + + + + + Finish Date + Fecha de finalización + + + + + Size + Tamaño + + + + + User Name + Nombre del usuario + + + + + Expiration + Expiración + + + + + Name + Nombre + + + + + The last backup taken ({0}) + La última copia de seguridad tomada ({0}) + + + + + Backup Database + Copia de seguridad de la base de datos + + + + + In progress + En curso + + + + + Completed + Completado + + + + + scripting + scripting + + + + + Connection not found + Conexión no encontrada + + + + + Please provide a file path instead of directory path + El nombre del archivo especificado es un nombre de directorio: {0} + + + + + The provided path is invalid + No se puede verificar la existencia de la ubicación del archivo de copia de seguridad: {0} + + + + + Cannot access the specified path on the server: {0} + No se puede acceder a la ruta de acceso especificada en el servidor: {0} + + + + + No backupset selected to be restored + Ningún backupset seleccionado para ser restaurado + + + + + Never + Nunca + + + + + Azure SQL DB + Azure SQL Database + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + La ruta de acceso [{0}] no es un directorio válido + + + + + For directory {0} a file with name {1} already exists + Ya existe un archivo {1} en el directorio '{0}' + + + + + Value {0} is too large to fit in column of type {1} + El valor {0} es muy grande para el tipo de columna {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.fr.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.fr.xlf new file mode 100644 index 0000000000..0dac86b81b --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.fr.xlf @@ -0,0 +1,2775 @@ + + + + + Connection parameters cannot be null + Les paramètres de connexion ne peuvent pas être null + + + + + OwnerUri cannot be null or empty + OwnerUri ne peut pas être null ou vide. + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' n’a pas de connexion existante + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Valeur '{0}' non valide pour AuthenticationType. Les valeurs valides sont 'Integrated' et 'SqlLogin'. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Valeur '{0}' non valide pour ApplicationIntent. Les valeurs valides sont 'ReadWrite' et 'ReadOnly'. + + . + Parameters: 0 - intent (string) + + + Connection canceled + Connexion annulée + + + + + OwnerUri cannot be null or empty + OwnerUri ne peut pas être null ou vide. + + + + + Connection details object cannot be null + L'objet "détails de connexion" ne peut pas être null + + + + + ServerName cannot be null or empty + ServerName ne peut pas être null ou vide + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} ne peut pas être nul ou vide quand l'authentification SqlLogin est utilisée + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + La requête est déjà terminée, elle ne peut pas être annulée. + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Requête annulée avec succès, échec de la libération de la requête. L'URI propriétaire n'a pas été trouvée. + + + + + Query was canceled by user + La requête a été annulée par l’utilisateur + + + + + The batch has not completed, yet + Le lot n’a pas terminé encore + + + + + Batch index cannot be less than 0 or greater than the number of batches + Index de lot ne peut pas être inférieur à 0 ou supérieur au nombre de lots + + + + + Result set index cannot be less than 0 or greater than the number of result sets + L'index de résultats ne peut pas être inférieur à 0 ou supérieur au nombre de résultats + + + + + Maximum number of bytes to return must be greater than zero + Le nombre maximal d'octets à renvoyer doit être supérieur à zéro + + + + + Maximum number of chars to return must be greater than zero + Le nombre maximal de caractères à renvoyer doit être supérieur à zéro + + + + + Maximum number of XML bytes to return must be greater than zero + Le nombre maximal d’octets XML à renvoyer doit être supérieur à zéro + + + + + Access method cannot be write-only + Méthode d’accès ne peut pas être en écriture seule + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper doit être initialisée avant d’effectuer des opérations + + + + + This FileStreamWrapper cannot be used for writing + Ce FileStreamWrapper ne peut pas être utilisé pour l’écriture + + + + + (1 row affected) + (1 ligne affectée) + + + + + ({0} rows affected) + ({0} lignes affectées) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Commandes terminées avec succès. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, au niveau état {2}, {1}, ligne {3} {4} {5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + La requête a échoué : {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Aucun nom de colonne) + + + + + The requested query does not exist + La requête demandée n’existe pas + + + + + This editor is not connected to a database + Cet éditeur n’est pas connecté à une base de données + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Une requête est déjà en cours pour cette session d’éditeur. Veuillez annuler cette requête, ou attendre son achèvement. + + + + + Sender for OnInfoMessage event must be a SqlConnection + L’expéditeur de l’événement de OnInfoMessage doit être un objet SqlConnection + + + + + Result cannot be saved until query execution has completed + Impossible d’enregistrer les résultats jusqu'à ce que l’exécution de la requête est terminée. + + + + + Internal error occurred while starting save task + Une erreur interne s'est produite lors du démarrage de la tâche de sauvegarde. + + + + + A save request to the same path is in progress + Une requête de sauvegarde vers le même chemin est en cours + + + + + Failed to save {0}: {1} + Impossible d’enregistrer {0} : {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Impossible de lire le sous-élément à moins que les résultats aient été lus depuis le serveur + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + La ligne de début ne peut pas être inférieure à 0 ou supérieure au nombre de lignes de résultats + + + + + Row count must be a positive integer + Le nombre de lignes doit être un entier positif + + + + + Could not retrieve column schema for result set + Impossible de récupérer le schéma des colonnes pour le jeu de résultats + + + + + Could not retrieve an execution plan from the result set + Impossible de récupérer un plan d’exécution pour le jeu de résultats + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + Cette fonctionnalité n'est actuellement pas supportée sur Azure SQL DB et Data Warehouse : {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Une erreur inattendue s'est produite lors de l'exécution du coup d'oeil à la définition: {0}. + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + Aucun résultat trouvé. + + + + + No database object was retrieved. + Aucun objet de base de données n'a été récupéré. + + + + + Please connect to a server. + Veuillez vous connecter à un serveur. + + + + + Operation timed out. + Opération a expiré. + + + + + This object type is currently not supported by this feature. + Ce type d'objet n'est actuellement pas supporté par cette fonctionnalité + + + + + Position is outside of file line range + La position est en dehors de la plage de lignes du fichier + + + + + Position is outside of column range for line {0} + La position est en dehors de la plage de colonnes pour la ligne {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Position de début ({0}, {1}) doit précéder ou être égale à la position de fin ({2}, {3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, Niveau {1}, État {2}, Ligne {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0}, Niveau {1}, État {2}, Procédure {3}, Ligne {4} + + + + + Msg {0}, Level {1}, State {2} + Msg {0}, Niveau {1}, État {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + Une erreur s'est produite lors du traitement du lot. Le message d'erreur est : {0} + + + + + ({0} row(s) affected) + ({0} lignes affectées) + + + + + The previous execution is not yet complete. + L'exécution précédente n'est pas encore terminée. + + + + + A scripting error occurred. + Une erreur de script s'est produite. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Une syntaxe incorrecte a été trouvée lors de l'analyse de {0}. + + + + + A fatal error occurred. + Une erreur irrécupérable s'est produite. + + + + + Batch execution completed {0} times... + L'exécution a été effectuée {0} fois... + + + + + You cancelled the query. + Vous avez annulé la requête. + + + + + An error occurred while the batch was being executed. + Une erreur s'est produite lors de l'exécution du lot. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + Une erreur s'est produite lors de l'exécution du lot, mais elle a été ignorée. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + La commande {0} n'est pas prise en charge. + + + + + The variable {0} could not be found. + Impossible de trouver la variable {0}. + + + + + SQL Execution error: {0} + Erreur d’exécution de SQL : {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Exécution du wrapper de l'analyseur du lot : {0} trouvé... à la ligne {1} : {2} Description : {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Message reçu du lot du moteur d'exécution du wrapper de l'analyseur du lot : Message : {0} Message détaillé : {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Traitement du ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot : DataReader.FieldCount : {0} DataReader.RecordsAffected : {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + ResultSet du lot du moteur d'exécution du wrapper de l'analyseur du lot terminé. + + + + + Canceling batch parser wrapper batch execution. + Annulation de l'exécution du lot du wrapper de l'analyseur du lot. + + + + + Scripting warning. + Avertissement de script. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Pour plus d'informations sur cette erreur, consultez les rubriques de dépannage dans la documentation du produit. + + + + + File '{0}' recursively included. + Le fichier '{0}' a été inclus de manière récursive. + + + + + Missing end comment mark '*/'. + La marque de commentaire de fin '*/' est manquante. + + + + + Unclosed quotation mark after the character string. + Guillemets non fermés après la chaîne de caractères. + + + + + Incorrect syntax was encountered while parsing '{0}'. + Détection d'une syntaxe incorrecte pendant l'analyse de '{0}'. + + + + + Variable {0} is not defined. + La variable {0} n'est pas définie. + + + + + test + test + + + + + Replacement of an empty string by an empty string. + Remplacement d’une chaîne vide à une chaîne vide. + + + + + Edit session does not exist. + La session d'édition n’existe pas. + + + + + Query has not completed execution + La requête n’a pas terminé l’exécution + + + + + Query did not generate exactly one result set + La requête n’a pas généré exactement un jeu de résultats + + + + + Failed to add new row to update cache + Impossible d’ajouter la nouvelle ligne pour mettre à jour le cache + + + + + Given row ID is outside the range of rows in the edit cache + L'identifiant de ligne spécifié est en dehors de la plage de lignes dans le cache d’édition + + + + + An update is already pending for this row and must be reverted first + Une mise à jour est déjà en attente pour cette ligne et doit être d’abord annulée + + + + + Given row ID does not have pending update + L'identifiant de la ligne n'a pas de mise à jour en attente + + + + + Table or view metadata could not be found + Les métadonnées de la table ou de la vue n’ont pas pu être trouvées + + + + + Invalid format for binary column + Format invalide pour une colonne binary + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Les colonnes booléennes doivent être un numérique 1 ou 0, ou une chaîne true ou false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Une valeur de cellule requise est manquante. + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + Une suppression est en attente pour cette ligne, une mise à jour de cellule ne peut pas être appliquée. + + + + + Column ID must be in the range of columns for the query + La colonne Id doit être dans la plage des colonnes de la requête + + + + + Column cannot be edited + La colonne ne peut pas être éditée + + + + + No key columns were found + Aucune colonne clé n'a été trouvée + + + + + An output filename must be provided + Un nom de fichier de sortie doit être fourni + + + + + Database object {0} cannot be used for editing. + L'objet de base de données {0} ne peut pas être utilisé pour éditer + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + L'Uri spécifiée '{0}' n’a pas de connexion par défaut + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Une tâche commit est en cours. Veuillez, s'il vous plaît, attendre la fin. + + + + + Decimal column is missing numeric precision or numeric scale + La colonne decimal manque d'une précision numérique + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + Impossible d'ajouter une ligne au tampon de résultats, le data reader ne contient aucune ligne + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + Les valeurs de colonne TIME doivent être contenues entre 00:00:00.0000000 et 23:59:59.9999999 + + + + + NULL is not allowed for this column + NULL n'est pas autorisé pour cette colonne + + + + + Edit session already exists. + La session d'édition existe déjà. + + + + + Edit session has not been initialized + La session d'édition n'a pas été initialisée + + + + + Edit session has already been initialized + La session d'édition a déjà été initialisée + + + + + Edit session has already been initialized or is in the process of initializing + La session d'édition a déjà été initialisée ou est en cours d'initialisation + + + + + Query execution failed, see messages for details + L'exécution de la requête a échoué, voir les messages pour plus de détails + + + + + Result limit cannot be negative + La limite de résultat ne peut pas être négative + + + + + NULL + NULL + + + + + A object name must be provided + Un nom d'objet doit être fourni + + + + + Explicitly specifying server or database is not supported + La spécification explicite du serveur ou de la base de données n'est pas pris en charge + + + + + Table metadata does not have extended properties + Les métadonnées de tables n'ont pas de propriétés étendues + + + + + Table or view requested for edit could not be found + La table ou la vue demandée pour édition n'a pas pu être trouvée + + + + + Error expanding: {0} + Erreur en développant : {0} + + + + + Error connecting to {0} + Erreur en se connectant à {0} + + + + + Aggregates + Agrégats + + + + + Server Roles + Rôles serveur + + + + + Application Roles + Rôles d'application + + + + + Assemblies + Assemblys + + + + + Assembly Files + Fichiers d'assembly + + + + + Asymmetric Keys + Clés asymétriques + + + + + Asymmetric Keys + Clés asymétriques + + + + + Data Compression Options + Options de compression de données + + + + + Certificates + Certificats + + + + + FileTables + FileTables + + + + + Certificates + Certificats + + + + + Check Constraints + Contraintes de validation + + + + + Columns + Colonnes + + + + + Constraints + Contraintes + + + + + Contracts + Contrats + + + + + Credentials + Informations d'identification + + + + + Error Messages + Messages d'erreur + + + + + Server Role Membership + Appartenance au rôle de serveur + + + + + Database Options + Options de la base de données + + + + + Database Roles + Rôles de base de données + + + + + Role Memberships + Appartenances aux rôles + + + + + Database Triggers + Déclencheurs de base de données + + + + + Default Constraints + Contraintes par défaut + + + + + Defaults + Par défaut + + + + + Sequences + Séquences + + + + + Endpoints + Points de terminaison + + + + + Event Notifications + Notifications d'événements + + + + + Server Event Notifications + Notifications d'événements du serveur + + + + + Extended Properties + Propriétés étendues + + + + + Filegroups + Groupes de fichiers + + + + + Foreign Keys + Clés étrangères + + + + + Full-Text Catalogs + Catalogues de recherche en texte intégral + + + + + Full-Text Indexes + Index de recherche en texte intégral + + + + + Functions + Fonctions + + + + + Indexes + Index + + + + + Inline Functions + Fonctions incluses + + + + + Keys + Clés + + + + + Linked Servers + Serveurs liés + + + + + Linked Server Logins + Connexions de serveur lié + + + + + Logins + Connexions + + + + + Master Key + Clé principale + + + + + Master Keys + Clés principales + + + + + Message Types + Types de messages + + + + + Table-Valued Functions + Fonctions table + + + + + Parameters + Paramètres + + + + + Partition Functions + Fonctions de partition + + + + + Partition Schemes + Schémas de partition + + + + + Permissions + Autorisations + + + + + Primary Keys + Clés primaires + + + + + Programmability + Programmabilité + + + + + Queues + Files d'attente + + + + + Remote Service Bindings + Liaisons de service distant + + + + + Returned Columns + Colonnes retournées + + + + + Roles + Rôles + + + + + Routes + Itinéraires  + + + + + Rules + Règles + + + + + Schemas + Schémas + + + + + Security + Sécurité + + + + + Server Objects + Objets serveur + + + + + Management + Gestion + + + + + Triggers + Déclencheurs + + + + + Service Broker + Service Broker + + + + + Services + Services + + + + + Signatures + Signatures + + + + + Log Files + Fichiers journaux + + + + + Statistics + Statistiques + + + + + Storage + Stockage + + + + + Stored Procedures + Procédures stockées + + + + + Symmetric Keys + Clés symétriques + + + + + Synonyms + Synonymes + + + + + Tables + Tables + + + + + Triggers + Déclencheurs + + + + + Types + Types + + + + + Unique Keys + Clés uniques + + + + + User-Defined Data Types + Types de données définis par l'utilisateur + + + + + User-Defined Types (CLR) + Types définis par l'utilisateur (CLR) + + + + + Users + Utilisateurs + + + + + Views + Vues + + + + + XML Indexes + Index XML + + + + + XML Schema Collections + Collections de schémas XML + + + + + User-Defined Table Types + Types de tables définis par l'utilisateur + + + + + Files + Fichiers + + + + + Missing Caption + Légende manquante + + + + + Broker Priorities + Priorités de Service Broker + + + + + Cryptographic Providers + Fournisseurs de chiffrement + + + + + Database Audit Specifications + Spécifications de l'audit de la base de données + + + + + Database Encryption Keys + Clés de chiffrement de la base de données + + + + + Event Sessions + Sessions d'événements + + + + + Full Text Stoplists + Listes de mots vides de texte intégral + + + + + Resource Pools + Pools de ressources + + + + + Audits + Audits + + + + + Server Audit Specifications + Spécifications de l'audit du serveur + + + + + Spatial Indexes + Index spatiaux + + + + + Workload Groups + Groupes de charges de travail + + + + + SQL Files + Fichiers SQL + + + + + Server Functions + Fonctions du serveur + + + + + SQL Type + Type SQL + + + + + Server Options + Options de serveur + + + + + Database Diagrams + Schémas de base de données + + + + + System Tables + Tables système + + + + + Databases + Bases de données + + + + + System Contracts + Contrats système + + + + + System Databases + Bases de données système + + + + + System Message Types + Types de messages système + + + + + System Queues + Files d'attente système + + + + + System Services + Services système + + + + + System Stored Procedures + Procédures stockées système + + + + + System Views + Vues système + + + + + Data-tier Applications + Applications de la couche Données + + + + + Extended Stored Procedures + Procédures stockées étendues + + + + + Aggregate Functions + Fonctions d'agrégation + + + + + Approximate Numerics + Valeurs numériques approximatives + + + + + Binary Strings + Chaînes binaires + + + + + Character Strings + Chaînes de caractères + + + + + CLR Data Types + Types de données CLR + + + + + Configuration Functions + Fonctions de configuration + + + + + Cursor Functions + Fonctions du curseur + + + + + System Data Types + Types de données système + + + + + Date and Time + Date et heure + + + + + Date and Time Functions + Fonctions de date et d'heure + + + + + Exact Numerics + Valeurs numériques exactes + + + + + System Functions + Fonctions système + + + + + Hierarchy Id Functions + Fonctions de l'ID de hiérarchie + + + + + Mathematical Functions + Fonctions mathématiques + + + + + Metadata Functions + Fonctions de métadonnées + + + + + Other Data Types + Autres types de données + + + + + Other Functions + Autres fonctions + + + + + Rowset Functions + Fonctions d'ensemble de lignes + + + + + Security Functions + Fonctions de sécurité + + + + + Spatial Data Types + Types de données spatiales + + + + + String Functions + Fonctions de chaîne + + + + + System Statistical Functions + Fonctions statistiques système + + + + + Text and Image Functions + Fonctions de texte et d'image + + + + + Unicode Character Strings + Chaînes de caractères Unicode + + + + + Aggregate Functions + Fonctions d'agrégation + + + + + Scalar-valued Functions + Fonctions scalaires + + + + + Table-valued Functions + Fonctions table + + + + + System Extended Stored Procedures + Procédures stockées étendues système + + + + + Built-in Types + Types intégrés + + + + + Built-in Server Roles + Rôles serveur intégrés + + + + + User with Password + Utilisateur avec mot de passe + + + + + Search Property List + Liste des propriétés de recherche + + + + + Security Policies + Stratégies de sécurité + + + + + Security Predicates + Prédicats de sécurité + + + + + Server Role + Rôle de serveur + + + + + Search Property Lists + Listes des propriétés de recherche + + + + + Column Store Indexes + Index de stockage de colonnes + + + + + Table Type Indexes + Index de types de tables + + + + + Selective XML Indexes + Index XML sélectifs + + + + + XML Namespaces + Espaces de noms XML + + + + + XML Typed Promoted Paths + Chemins d'accès promus typés XML + + + + + T-SQL Typed Promoted Paths + Chemins d'accès promus typés T-SQL + + + + + Database Scoped Credentials + Informations d'identification incluses dans l'étendue de la base de données + + + + + External Data Sources + Sources de données externes + + + + + External File Formats + Formats de fichier externes + + + + + External Resources + Ressources externes + + + + + External Tables + Tables externes + + + + + Always Encrypted Keys + Clés Always Encrypted + + + + + Column Master Keys + Clés principales de la colonne + + + + + Column Encryption Keys + Clés de chiffrement de la colonne + + + + + Server + Serveur + + + + + Error parsing ScriptingParams.ConnectionString property. + Erreur en analysant la propriété ScriptingParams.ConnectionString. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + Répertoire invalide spécifié pour la propriété ScriptingParams.FilePath. + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Erreur en analysant la propriété ScriptingListObjectsCompleteParams.ConnectionString. + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Pas de valeur par défaut + + + + + Input + Entrée + + + + + Input/Output + Entrée/sortie + + + + + Input/ReadOnly + Entrée/ReadOnly + + + + + Input/Output/ReadOnly + Entrée/sortie/ReadOnly + + + + + Default + Par défaut + + + + + null + Null + + + + + not null + Non Null + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1}Calculé, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1}Calculé) + + + + + {0} (Column Set, {1}) + {0} (Jeu de colonnes, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Jeu de colonnes, {1}{2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Jeu de colonnes, {1}, {2}, {3}) + + + + + Unique + Unique + + + + + Non-Unique + Non unique + + + + + Clustered + Ordonné en clusters + + + + + Non-Clustered + Non-Clustere + + + + + History + Historique + + + + + System-Versioned + System-Versioned + + + + + Unavailable + Indisponible + + + + + Current default filegroup: {0} + Groupe de fichiers par défaut actuel : {0} + + + + + New Filegroup for {0} + Nouveau groupe de fichiers pour {0} + + + + + Default + Par défaut + + + + + Files + Fichiers + + + + + Name + Nom + + + + + Read-Only + Lecture seule + + + + + Autogrowth / Maxsize + Redimensionnement automatique / Taille max + + + + + ... + ... + + + + + <default> + <par défaut> + + + + + Filegroup + Groupe de fichiers + + + + + Logical Name + Nom logique + + + + + File Type + Type de fichier + + + + + Initial Size (MB) + Taille initiale (Mo) + + + + + <new filegroup> + <new filegroup> + + + + + Path + Chemin d'accès + + + + + File Name + Nom de fichier  + + + + + <raw device> + <raw device> + + + + + Bulk-logged + Bulk-logged + + + + + Full + Full + + + + + Simple + Simple + + + + + Select Database Owner + Sélectionner le propriétaire de base de données + + + + + None + Aucune + + + + + By {0} MB, Limited to {1} MB + Par {0} Mo, Limité à {1} Mo + + + + + By {0} percent, Limited to {1} MB + Par {0} %, Limité à {1} Mo + + + + + By {0} MB, Unlimited + Par {0} Mo, Illimité + + + + + By {0} percent, Unlimited + Par {0} %, Illimité + + + + + Unlimited + Illimité + + + + + Limited to {0} MB + Limité à {0} Mo + + + + + Automatic + Automatique + + + + + Service Broker + Service Broker + + + + + Collation + Classement + + + + + Cursor + Curseur + + + + + Miscellaneous + Divers + + + + + Recovery + Restauration + + + + + State + État + + + + + ANSI NULL Default + Paramètre par défaut ANSI NULL + + + + + ANSI NULLS Enabled + Valeurs ANSI NULLS activées + + + + + ANSI Padding Enabled + Padding ANSI activé + + + + + ANSI Warnings Enabled + ANSI Warnings activés + + + + + Arithmetic Abort Enabled + Annulation arithmétique (Arithmetic Abort) activée + + + + + Auto Close + Fermeture automatique + + + + + Auto Create Statistics + Création automatique des statistiques + + + + + Auto Shrink + Réduction automatique + + + + + Auto Update Statistics + Mise à jour automatique des statistiques + + + + + Auto Update Statistics Asynchronously + Mise à jour automatique des statistiques en mode asynchrone + + + + + Case Sensitive + Sensible à la casse + + + + + Close Cursor on Commit Enabled + Fermeture du curseur lors de la validation activée + + + + + Collation + Classement + + + + + Concatenate Null Yields Null + La concaténation de la valeur Null donne Null + + + + + Database Compatibility Level + Niveau de compatibilité de la base de données + + + + + Database State + État de la base de données + + + + + Default Cursor + Curseur par défaut + + + + + Full-Text Indexing Enabled + Indexation de texte intégral activée + + + + + Numeric Round-Abort + Abandon en cas d'arrondi numérique + + + + + Page Verify + Vérification de la page : + + + + + Quoted Identifiers Enabled + Identificateurs entre guillemets activés + + + + + Database Read-Only + Base de données en lecture seule + + + + + Recursive Triggers Enabled + Déclencheurs récursifs activés + + + + + Restrict Access + Restreindre l'accès + + + + + Select Into/Bulk Copy + Select Into / Bulk Copy + + + + + Honor Broker Priority + Priorité du service Broker respectée + + + + + Service Broker Identifier + Identifant de Service Broker + + + + + Broker Enabled + Broker activé + + + + + Truncate Log on Checkpoint + Truncate Log on Checkpoint + + + + + Cross-database Ownership Chaining Enabled + Chaînage des propriétés des bases de données croisées activé + + + + + Trustworthy + Digne de confiance + + + + + Date Correlation Optimization Enabled + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + + + + + Forced + Forcé + + + + + Simple + Simple + + + + + ROWS Data + Données ROWS + + + + + LOG + LOG + + + + + FILESTREAM Data + Données FILESTREAM + + + + + Not Applicable + Non applicable + + + + + <default path> + <default path> + + + + + Open Connections + Ouvrir les connexions + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Pour changer les propriétés de la base de données, SQL Server doit fermer toutes les autres connexions à la base de données. Etes-vous sûr de vouloir changer les propriétés et fermer toutes les autres connexions ? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + Format de stockage VarDecimal activé + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Chiffrement activé + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Pour la politique de distribution HASH, le nombre de colonnes hash qui débutent est optionnel mais devrait être entre 1 et 16 colonnes. + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Aucun + + + + + Partial + Partiel + + + + + FILESTREAM Files + Fichiers FILESTREAM + + + + + No Applicable Filegroup + Aucun groupe de fichiers applicable + + + + + The database {0} is not accessible. + La base de données {0} est inaccessible. + + + + + Query has no results to return + La requête n'a aucun résultat à retourner + + + + + Result set has too many rows to be safely loaded + Le jeu de résultats a trop de lignes pour être chargé en toute sécurité + + + + Parameterization + Paramétrage + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + La spécification de cette option lors de la restauration d'une sauvegarde avec l'option NORECOVERY n'est pas permise. + + + + + Invalid path for database file: '{0}' + Chemin d'accès non valide pour le fichier de base de données : « {0} » + + + + + Log + Journal + + + + + Failed to create restore plan + Échec de la création du plan de restauration + + + + + Restore database is not supported + La restauration de la base de données n'est pas supportée + + + + + Restore Database + Restaurer la base de données + + + + + (Copy Only) + (Copie seule) + + + + + Component + Composant + + + + + Type + Type + + + + + Server + Serveur  + + + + + Database + Base de données  + + + + + Position + Position + + + + + First LSN + Premier NSE + + + + + Last LSN + Dernier NSE + + + + + Checkpoint LSN + NSE du point de contrôle + + + + + Full LSN + Tous les NSE + + + + + Start Date + Date de début + + + + + Finish Date + Date de fin + + + + + Size + Taille + + + + + User Name + Nom d'utilisateur  + + + + + Expiration + Expiration  + + + + + Name + Nom  + + + + + The last backup taken ({0}) + La dernière sauvegarde effectuée ({0}) + + + + + Backup Database + Sauvegarder la base de données + + + + + In progress + Opération en cours + + + + + Completed + Terminé + + + + + scripting + script + + + + + Connection not found + Connexion introuvable + + + + + Please provide a file path instead of directory path + Le nom de fichier spécifié est également un nom de répertoire: {0} + + + + + The provided path is invalid + Impossible de vérifier l'existence de l'emplacement du fichier de sauvegarde: {0} + + + + + Cannot access the specified path on the server: {0} + Impossible d'accéder au chemin d'accès spécifié sur le serveur: {0} + + + + + No backupset selected to be restored + Aucun jeu de sauvegarde n'a été sélectionné pour être restauré. + + + + + Never + Jamais + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + Le chemin {0} n'est pas un répertoire valide. + + + + + For directory {0} a file with name {1} already exists + Pour le répertoire {0} un fichier avec le nom {1} existe déjà + + + + + Value {0} is too large to fit in column of type {1} + La valeur {0} est trop grande pour tenir dans la colonne de type {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.it.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.it.xlf new file mode 100644 index 0000000000..a0e5730db8 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.it.xlf @@ -0,0 +1,2775 @@ + + + + + Connection parameters cannot be null + Parametri di connessione non possono essere null + + + + + OwnerUri cannot be null or empty + OwnerUri non può essere null o vuoto + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri: '{0}' non dispone di connessione esistente + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Valore non valido: '{0}' per AuthenticationType. I valori validi sono 'Integrated' e 'SqlLogin'. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Valore '{0}' non valido per ApplicationIntent. I valori validi sono 'ReadWrite' e 'ReadOnly'. + + . + Parameters: 0 - intent (string) + + + Connection canceled + Connessione annullata + + + + + OwnerUri cannot be null or empty + OwnerUri non può essere null o vuoto + + + + + Connection details object cannot be null + L'oggetto Dettagli di connessione non può essere null + + + + + ServerName cannot be null or empty + ServerName non può essere null o vuoto + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} non può essere null o vuoto quando si utilizza l'autenticazione SqlLogin + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + La query è già stata completata e non può essere annullata + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Query annullata correttamente, impossibile eliminare query. URI proprietario non trovato. + + + + + Query was canceled by user + Query annullata dall'utente + + + + + The batch has not completed, yet + Il batch non è ancora stato completato + + + + + Batch index cannot be less than 0 or greater than the number of batches + Indice di batch non può essere minore di 0 o maggiore del numero di batch + + + + + Result set index cannot be less than 0 or greater than the number of result sets + Indice di set di risultati non può essere minore di 0 o maggiore del numero di set di risultati + + + + + Maximum number of bytes to return must be greater than zero + Numero massimo di byte da restituire deve essere maggiore di zero + + + + + Maximum number of chars to return must be greater than zero + Numero massimo di caratteri da restituire deve essere maggiore di zero + + + + + Maximum number of XML bytes to return must be greater than zero + Numero massimo di byte XML da restituire deve essere maggiore di zero + + + + + Access method cannot be write-only + Il metodo di accesso non può essere in sola scrittura + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper deve essere inizializzato prima di eseguire operazioni + + + + + This FileStreamWrapper cannot be used for writing + Questo FileStreamWrapper non può essere utilizzato per la scrittura + + + + + (1 row affected) + (1 riga interessata) + + + + + ({0} rows affected) + ({0} righe interessate) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Comandi completati correttamente. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, Livello {1}, Stato {2}, Riga {3} {4} {5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Query non riuscita: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Nessun nome di colonna) + + + + + The requested query does not exist + La query richiesta non esiste + + + + + This editor is not connected to a database + Questo editor non è connesso a un database + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Una query è già in corso per questa sessione dell'editor. Annullare la query o attendere il completamento. + + + + + Sender for OnInfoMessage event must be a SqlConnection + Mittente per l'evento OnInfoMessage deve essere un oggetto SqlConnection + + + + + Result cannot be saved until query execution has completed + Non è possibile salvare il risultato finché non viene completata l'esecuzione della query + + + + + Internal error occurred while starting save task + Errore interno durante l'avvio del task di salvataggio + + + + + A save request to the same path is in progress + È in corso una richiesta di salvataggio sullo stesso percorso + + + + + Failed to save {0}: {1} + Impossibile salvare {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Impossibile leggere sottoinsieme a meno che i risultati sono stati letti dal server + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Riga di inizio non può essere minore di 0 o maggiore del numero di righe nel set di risultati + + + + + Row count must be a positive integer + Il numero di righe deve essere un numero intero positivo + + + + + Could not retrieve column schema for result set + Impossibile recuperare schema di colonne per set di risultati + + + + + Could not retrieve an execution plan from the result set + Impossibile recuperare un piano di esecuzione dal set di risultati + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + Questa funzionalità non è supportata su DB SQL Azure e Data Warehouse: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Si è verificato un errore imprevisto durante l'esecuzione di definizione Peek: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + Nessun risultato trovato. + + + + + No database object was retrieved. + Non è stato recuperato alcun oggetto di database. + + + + + Please connect to a server. + Connettersi a un server. + + + + + Operation timed out. + Timeout dell'operazione. + + + + + This object type is currently not supported by this feature. + Questo tipo di oggetto non è supportato da questa funzionalità. + + + + + Position is outside of file line range + La posizione non rientra nell'intervallo di righe del file + + + + + Position is outside of column range for line {0} + Posizione non rientra nell'intervallo di colonne per riga {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Posizione iniziale ({0}, {1}) deve essere precedente o uguale alla posizione finale ({2}, {3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg. {0}, Livello {1}, Stato {2}, Riga {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg. {0}, Livello {1}, Stato {2}, Procedura {3}, Riga {4} + + + + + Msg {0}, Level {1}, State {2} + Msg. {0}, Livello {1}, Stato {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + Si è verificato un errore durante l'elaborazione batch. Messaggio di errore: {0} + + + + + ({0} row(s) affected) + ({0} righe interessate dall'operazione) + + + + + The previous execution is not yet complete. + L'esecuzione precedente non è ancora completa. + + + + + A scripting error occurred. + Si è verificato un errore di scripting. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Sintassi errata rilevata durante l'analisi di '{0}'. + + + + + A fatal error occurred. + Si è verificato un errore irreversibile. + + + + + Batch execution completed {0} times... + Esecuzione completata {0} volte... + + + + + You cancelled the query. + È stata annullata la query. + + + + + An error occurred while the batch was being executed. + Si è verificato un errore durante l'esecuzione del batch. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + Si è verificato un errore durante l'esecuzione del batch, ma l'errore è stato ignorato. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + Il comando {0} non è supportato. + + + + + The variable {0} could not be found. + Impossibile trovare la variabile {0}. + + + + + SQL Execution error: {0} + Errore di esecuzione di SQL: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Esecuzione del wrapper parser batch: trovati {0}... alla riga {1}: {2} Descrizione: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Motore di esecuzione wrapper parser di batch, ricevuto messaggio batch: messaggio: {0} messaggio dettagliato: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Motore di esecuzione wrapper parser di batch, elaborazione batch di ResultSet: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + Motore di esecuzione wrapper parser di batch, batch di ResultSet completato. + + + + + Canceling batch parser wrapper batch execution. + Annullamento dell'esecuzione batch del wrapper parser batch. + + + + + Scripting warning. + Avviso di script. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Per ulteriori informazioni su questo errore, vedere gli argomenti sulla risoluzione dei problemi nella documentazione del prodotto. + + + + + File '{0}' recursively included. + File '{0}' incluso ricorsivamente. + + + + + Missing end comment mark '*/'. + Marker ' * /' di fine commento mancante. + + + + + Unclosed quotation mark after the character string. + Virgolette mancanti alla fine della stringa di caratteri. + + + + + Incorrect syntax was encountered while parsing '{0}'. + Sintassi errata rilevata durante l'analisi di '{0}'. + + + + + Variable {0} is not defined. + Variabile {0} non è definita. + + + + + test + test + + + + + Replacement of an empty string by an empty string. + Sostituzione di una stringa vuota con una stringa vuota. + + + + + Edit session does not exist. + La sessione di editing non esiste. + + + + + Query has not completed execution + Esecuzione query non completata + + + + + Query did not generate exactly one result set + La query non ha generato esattamente un insieme di risultati + + + + + Failed to add new row to update cache + Errore nell'aggiunta di una riga durante l'aggiornamento della cache + + + + + Given row ID is outside the range of rows in the edit cache + L'ID riga specificato è fuori dal range di righe della cache della modifica + + + + + An update is already pending for this row and must be reverted first + Un aggiornamento di questa riga è già in corso e dev'essere annullato prima di procedere + + + + + Given row ID does not have pending update + Questo ID di riga non ha aggiornamenti in corso + + + + + Table or view metadata could not be found + Metadati della tabella o della vista non trovati + + + + + Invalid format for binary column + Formato non valido per una colonna binaria + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Colonne booleane devono contenere valori numerici 0 o 1, o stringhe true o false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Il valore di cella richiesto è mancante + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + La cancellazione di questa riga è in corso, impossibile aggiornare la cella. + + + + + Column ID must be in the range of columns for the query + L'ID della colonna dev'essere incluso nel range delle colonne della query + + + + + Column cannot be edited + Impossibile modificare la colonna + + + + + No key columns were found + Impossibile trovare colonne chiave + + + + + An output filename must be provided + Occorre fornire un nome di file di output + + + + + Database object {0} cannot be used for editing. + L'oggetto {0} del database non può essere usato per la modifica. + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + L'URI specificato '{0}' non ha una connessione di default + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Azione commit in corso - attenderne il completamento. + + + + + Decimal column is missing numeric precision or numeric scale + Precisione o scala mancante nella colonna Decimal + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + Impossibile aggiungere una riga al buffer risultati - il datareader non contiene righe + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + I valori della colonna Time devono essere compresi tra 00:00:00.0000000 e 23:59:59.9999999 + + + + + NULL is not allowed for this column + NULL non è consentito per questa colonna + + + + + Edit session already exists. + La sessione di editing esiste già. + + + + + Edit session has not been initialized + La sessione di editing non è stata inizializzata. + + + + + Edit session has already been initialized + La sessione di editing è già stata inizializzata. + + + + + Edit session has already been initialized or is in the process of initializing + La sessione di editing è già stata inizializzata o è in fase di inizializzazione + + + + + Query execution failed, see messages for details + Esecuzione della query fallita - vedere i messaggi per ulteriori dettagli + + + + + Result limit cannot be negative + Il limite del risultato non può essere negativo + + + + + NULL + NULL + + + + + A object name must be provided + Il nome dell'oggetto è obbligatorio + + + + + Explicitly specifying server or database is not supported + Non è possibile specificare in modo esplicito il nome di un server o di un database + + + + + Table metadata does not have extended properties + Nessuna proprietà estesa per la tabella + + + + + Table or view requested for edit could not be found + Impossibile trovare la Tabella o la Vista necessarie alla modifica + + + + + Error expanding: {0} + Errore durante l'espansione dell'oggetto: {0} + + + + + Error connecting to {0} + Errore durante la connessione a {0}' + + + + + Aggregates + Aggregazioni + + + + + Server Roles + Ruoli del server + + + + + Application Roles + Ruoli applicazione + + + + + Assemblies + Assembly + + + + + Assembly Files + File di assembly + + + + + Asymmetric Keys + Chiavi asimmetriche + + + + + Asymmetric Keys + Chiavi asimmetriche + + + + + Data Compression Options + Opzioni di compressione dati + + + + + Certificates + Certificati + + + + + FileTables + Tabelle file + + + + + Certificates + Certificati + + + + + Check Constraints + Vincoli CHECK + + + + + Columns + Colonne + + + + + Constraints + Vincoli + + + + + Contracts + Contratti + + + + + Credentials + Credenziali + + + + + Error Messages + Messaggi di errore + + + + + Server Role Membership + Appartenenze al ruolo del server + + + + + Database Options + Opzioni database + + + + + Database Roles + Ruoli database + + + + + Role Memberships + Appartenenze a ruoli + + + + + Database Triggers + Trigger database + + + + + Default Constraints + Vincoli predefiniti + + + + + Defaults + Impostazioni predefinite + + + + + Sequences + Sequenze + + + + + Endpoints + Endpoint + + + + + Event Notifications + Notifiche degli eventi + + + + + Server Event Notifications + Notifiche degli eventi server + + + + + Extended Properties + Proprietà estese + + + + + Filegroups + Filegroup + + + + + Foreign Keys + Chiavi esterne + + + + + Full-Text Catalogs + Cataloghi full-text + + + + + Full-Text Indexes + Indici full-text + + + + + Functions + Funzioni + + + + + Indexes + Indici + + + + + Inline Functions + Funzioni inline + + + + + Keys + Chiavi + + + + + Linked Servers + Server collegati + + + + + Linked Server Logins + Accessi server collegato + + + + + Logins + Accessi + + + + + Master Key + Chiave master + + + + + Master Keys + Chiavi master + + + + + Message Types + Tipi di messaggio + + + + + Table-Valued Functions + Funzioni con valori di tabella + + + + + Parameters + Parametri + + + + + Partition Functions + Funzioni di partizione + + + + + Partition Schemes + Schemi di partizione + + + + + Permissions + Autorizzazioni + + + + + Primary Keys + Chiavi primarie + + + + + Programmability + Programmazione + + + + + Queues + Code + + + + + Remote Service Bindings + Associazioni a servizi remoti + + + + + Returned Columns + Colonne restituite + + + + + Roles + Ruoli + + + + + Routes + Route + + + + + Rules + Regole + + + + + Schemas + Schemi + + + + + Security + Sicurezza + + + + + Server Objects + Oggetti server + + + + + Management + Gestione + + + + + Triggers + Trigger + + + + + Service Broker + Service Broker + + + + + Services + Servizi + + + + + Signatures + Firme + + + + + Log Files + File di log + + + + + Statistics + Statistiche + + + + + Storage + Archiviazione + + + + + Stored Procedures + Stored procedure + + + + + Symmetric Keys + Chiavi simmetriche + + + + + Synonyms + Sinonimi + + + + + Tables + Tabelle + + + + + Triggers + Trigger + + + + + Types + Tipi + + + + + Unique Keys + Chiavi univoche + + + + + User-Defined Data Types + Tipi di dati definiti dall'utente + + + + + User-Defined Types (CLR) + Tipi definiti dall'utente (UDT) (CLR) + + + + + Users + Utenti + + + + + Views + Viste + + + + + XML Indexes + Indici XML + + + + + XML Schema Collections + Raccolte XML Schema + + + + + User-Defined Table Types + Tipi di tabella definiti dall'utente + + + + + Files + File + + + + + Missing Caption + Didascalia mancante + + + + + Broker Priorities + Priorità di Service Broker + + + + + Cryptographic Providers + Provider del servizio di crittografia + + + + + Database Audit Specifications + Specifiche di controllo database + + + + + Database Encryption Keys + Chiavi di crittografia database + + + + + Event Sessions + Sessioni eventi + + + + + Full Text Stoplists + Elenchi di parole non significative full-text + + + + + Resource Pools + Pool di risorse + + + + + Audits + Controlli + + + + + Server Audit Specifications + Specifiche controllo server + + + + + Spatial Indexes + Indici spaziali + + + + + Workload Groups + Gruppi del carico di lavoro + + + + + SQL Files + File SQL + + + + + Server Functions + Funzioni server + + + + + SQL Type + Tipo SQL + + + + + Server Options + Opzioni server + + + + + Database Diagrams + Diagrammi di database + + + + + System Tables + Tabelle di sistema + + + + + Databases + Database + + + + + System Contracts + Contratti di sistema + + + + + System Databases + Database di sistema + + + + + System Message Types + Tipi di messaggi di sistema + + + + + System Queues + Code di sistema + + + + + System Services + Servizi di sistema + + + + + System Stored Procedures + Stored procedure di sistema + + + + + System Views + Viste di sistema + + + + + Data-tier Applications + Applicazioni livello dati + + + + + Extended Stored Procedures + Stored procedure estese + + + + + Aggregate Functions + Funzioni di aggregazione + + + + + Approximate Numerics + Valori numerici approssimati + + + + + Binary Strings + Stringhe binarie + + + + + Character Strings + Stringhe di caratteri + + + + + CLR Data Types + Tipi di dati CLR + + + + + Configuration Functions + Funzioni di configurazione + + + + + Cursor Functions + Funzioni per i cursori + + + + + System Data Types + Tipi di dati di sistema + + + + + Date and Time + Data e ora + + + + + Date and Time Functions + Funzioni di data e ora + + + + + Exact Numerics + Valori numerici esatti + + + + + System Functions + Funzioni di sistema + + + + + Hierarchy Id Functions + Funzioni di ID di gerarchia + + + + + Mathematical Functions + Funzioni matematiche + + + + + Metadata Functions + Funzioni per i metadati + + + + + Other Data Types + Altri tipi di dati + + + + + Other Functions + Altre funzioni + + + + + Rowset Functions + Funzioni per i set di righe + + + + + Security Functions + Funzioni di sicurezza + + + + + Spatial Data Types + Tipi di dati spaziali + + + + + String Functions + Funzioni per i valori stringa + + + + + System Statistical Functions + Funzioni statistiche di sistema + + + + + Text and Image Functions + Funzioni per i valori text e image + + + + + Unicode Character Strings + Stringhe di caratteri Unicode + + + + + Aggregate Functions + Funzioni di aggregazione + + + + + Scalar-valued Functions + Funzioni a valori scalari + + + + + Table-valued Functions + Funzioni con valori di tabella + + + + + System Extended Stored Procedures + Stored procedure estese di sistema + + + + + Built-in Types + Tipi predefiniti + + + + + Built-in Server Roles + Ruoli del server predefiniti + + + + + User with Password + Utente con password + + + + + Search Property List + Elenco delle proprietà di ricerca + + + + + Security Policies + Criteri di sicurezza + + + + + Security Predicates + Predicati di sicurezza + + + + + Server Role + Ruolo del server + + + + + Search Property Lists + Elenchi delle proprietà di ricerca + + + + + Column Store Indexes + Indici dell'archivio colonne + + + + + Table Type Indexes + Indici del tipo di tabella + + + + + Selective XML Indexes + Indici XML selettivi + + + + + XML Namespaces + Spazi dei nomi XML + + + + + XML Typed Promoted Paths + Percorsi promossi con tipizzazione XML + + + + + T-SQL Typed Promoted Paths + Percorsi promossi con tipizzazione T-SQL + + + + + Database Scoped Credentials + Credenziali con ambito database + + + + + External Data Sources + Origini dati esterne + + + + + External File Formats + Formati di file esterni + + + + + External Resources + Risorse esterne + + + + + External Tables + Tabelle esterne + + + + + Always Encrypted Keys + Chiavi Always Encrypted + + + + + Column Master Keys + Chiavi master della colonna + + + + + Column Encryption Keys + Chiavi di crittografia della colonna + + + + + Server + Server + + + + + Error parsing ScriptingParams.ConnectionString property. + Errore durante l'analisi della proprietà ScriptingParams.ConnectionString. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + La Directory specificata dalla proprietà ScriptingParams.FilePath non è valida. + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Errore durante l'analisi della proprietà ScriptingListObjectsCompleteParams.ConnectionString. + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Nessun valore predefinito + + + + + Input + Input + + + + + Input/Output + Input/Output + + + + + Input/ReadOnly + Input/ReadOnly + + + + + Input/Output/ReadOnly + Input/Output/ReadOnly + + + + + Default + Predefinito + + + + + null + Null + + + + + not null + non Null + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1} calcolato, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1} calcolato) + + + + + {0} (Column Set, {1}) + {0} (Set di colonne: {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Set di colonne: {1} {2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Set di colonne: {1}, {2}, {3}) + + + + + Unique + Univoco + + + + + Non-Unique + Non univoco + + + + + Clustered + Cluster + + + + + Non-Clustered + Non cluster + + + + + History + Cronologia + + + + + System-Versioned + Con controllo delle versioni di sistema + + + + + Unavailable + Non disponibile + + + + + Current default filegroup: {0} + Filegroup predefinito corrente: {0} + + + + + New Filegroup for {0} + Nuovo Filegroup per {0} + + + + + Default + Predefinito + + + + + Files + File + + + + + Name + Nome + + + + + Read-Only + Sola lettura + + + + + Autogrowth / Maxsize + Aumento automatico / Maxsize + + + + + ... + ... + + + + + <default> + <predefinito> + + + + + Filegroup + Filegroup + + + + + Logical Name + Nome logico + + + + + File Type + Tipo di file + + + + + Initial Size (MB) + Dimensioni iniziali (MB) + + + + + <new filegroup> + <nuovo Filegroup> + + + + + Path + Percorso + + + + + File Name + Nome file + + + + + <raw device> + <dispositivo RAW> + + + + + Bulk-logged + Registrazione delle operazioni bulk + + + + + Full + Completo + + + + + Simple + Semplice + + + + + Select Database Owner + Seleziona il proprietario del Database + + + + + None + Nessuno + + + + + By {0} MB, Limited to {1} MB + Di {0} MB, limitato a {1} MB + + + + + By {0} percent, Limited to {1} MB + Di {0} percento, limitato a {1} MB + + + + + By {0} MB, Unlimited + Di {0} MB, illimitato + + + + + By {0} percent, Unlimited + Di {0} percento, illimitato + + + + + Unlimited + Senza limiti + + + + + Limited to {0} MB + Limitato a {0} MB + + + + + Automatic + Automatico + + + + + Service Broker + Service Broker + + + + + Collation + Regole di confronto + + + + + Cursor + Cursore + + + + + Miscellaneous + Varie + + + + + Recovery + Recupero + + + + + State + Stato + + + + + ANSI NULL Default + Impostazione predefinita ANSI NULL + + + + + ANSI NULLS Enabled + ANSI NULLS abilitati + + + + + ANSI Padding Enabled + ANSI Padding abilitato + + + + + ANSI Warnings Enabled + Avvisi ANSI abilitati + + + + + Arithmetic Abort Enabled + Arithmetic Abort abilitata + + + + + Auto Close + Chiusura automatica + + + + + Auto Create Statistics + Creazione statistiche automatica + + + + + Auto Shrink + Compattazione automatica + + + + + Auto Update Statistics + Aggiornamento statistiche automatico + + + + + Auto Update Statistics Asynchronously + Aggiornamento statistiche asincrono automatico + + + + + Case Sensitive + Distinzione maiuscole/minuscole + + + + + Close Cursor on Commit Enabled + Chiusura cursore in caso di commit abilitata + + + + + Collation + Regole di confronto + + + + + Concatenate Null Yields Null + La concatenazione di valori Null restituisce valori Null + + + + + Database Compatibility Level + Livello di compatibilità del database + + + + + Database State + Stato database + + + + + Default Cursor + Cursore predefinito + + + + + Full-Text Indexing Enabled + Indicizzazione full-text + + + + + Numeric Round-Abort + Interruzione per perdita di precisione numerica + + + + + Page Verify + Verifica pagina + + + + + Quoted Identifiers Enabled + Identificatori delimitati abilitati + + + + + Database Read-Only + Database di sola lettura + + + + + Recursive Triggers Enabled + Trigger ricorsivi abilitati + + + + + Restrict Access + Limitazione accesso + + + + + Select Into/Bulk Copy + Select Into/Bulk Copy + + + + + Honor Broker Priority + Rispetta priorità di Service Broker + + + + + Service Broker Identifier + Identificatore Service Broker + + + + + Broker Enabled + Broker abilitato + + + + + Truncate Log on Checkpoint + Tronca Log al Checkpoint + + + + + Cross-database Ownership Chaining Enabled + Concatenamento della proprietà tra database abilitato + + + + + Trustworthy + Trustworthy + + + + + Date Correlation Optimization Enabled + Ottimizzazione correlazione date Enabledprototype_db_prop_parameterization = parametrizzazione + + + + + Forced + Forzato + + + + + Simple + Semplice + + + + + ROWS Data + Dati RIGHE + + + + + LOG + LOG + + + + + FILESTREAM Data + Dati FILESTREAM + + + + + Not Applicable + Non applicabile + + + + + <default path> + <percorso predefinito> + + + + + Open Connections + Connessioni aperte + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Per modificare le proprietà del database, SQL Server deve chiudere tutte le altre connessioni al database_ Sei sicuro di voler modificare le proprietà e chiudere tutte le altre connessioni? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + Formato di archiviazione VarDecimal abilitato + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Crittografia abilitata + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Per il criterio di distribuzione HASH, il numero di colonne iniziali di hash è facoltativo, ma dovrebbe essere da 1 a 16 colonne + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Nessuno + + + + + Partial + Parziale + + + + + FILESTREAM Files + File FILESTREAM + + + + + No Applicable Filegroup + Nessun Filegroup applicabile + + + + + The database {0} is not accessible. + Il database {0} non è accessibile. + + + + + Query has no results to return + La query non ha risultati da restituire + + + + + Result set has too many rows to be safely loaded + L'insieme di risultati ha troppe righe per essere caricato in modo sicuro + + + + Parameterization + Parametrizzazione + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + Non è consentito specificare questa opzione quando si ripristina un backup con NORECOVERY. + + + + + Invalid path for database file: '{0}' + Percorso non valido per il file di database: '{0}' + + + + + Log + Log + + + + + Failed to create restore plan + Impossibile creare un piano di ripristino. + + + + + Restore database is not supported + Ripristino del database non supportato. + + + + + Restore Database + Ripristina Database + + + + + (Copy Only) + (Sola Copia) + + + + + Component + Componente + + + + + Type + Tipo + + + + + Server + Server + + + + + Database + Database + + + + + Position + Posizione + + + + + First LSN + Primo LSN + + + + + Last LSN + Ultimo LSN + + + + + Checkpoint LSN + LSN di checkpoint + + + + + Full LSN + LSN completo + + + + + Start Date + Data di inizio + + + + + Finish Date + Data di fine + + + + + Size + Dimensione + + + + + User Name + Nome utente + + + + + Expiration + Scadenza + + + + + Name + Nome + + + + + The last backup taken ({0}) + L'ultimo backup effettuato ({0}) + + + + + Backup Database + Backup database + + + + + In progress + In corso + + + + + Completed + Completato + + + + + scripting + scripting + + + + + Connection not found + Connessione non trovata + + + + + Please provide a file path instead of directory path + Il nome file specificato è anche un nome di cartella: {0} + + + + + The provided path is invalid + Impossibile verificare l'esistenza della posizione del file di backup: {0} + + + + + Cannot access the specified path on the server: {0} + Impossibile accedere al percorso specificato sul server: {0} + + + + + No backupset selected to be restored + Nessun insieme di backup selezionato per il ripristino + + + + + Never + Mai + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + Il percorso [{0}] non è una directory valida. + + + + + For directory {0} a file with name {1} already exists + Nella directory '{0}' esiste già il file {1} + + + + + Value {0} is too large to fit in column of type {1} + Il valore {0} è troppo grande per essere contenuto in una colonna di tipo {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ja.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ja.xlf new file mode 100644 index 0000000000..065c937efb --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ja.xlf @@ -0,0 +1,2776 @@ + + + + + Connection parameters cannot be null + 接続パラメーターを null にすることはできません。 + + + + + OwnerUri cannot be null or empty + OwnerUri を null または空にすることはできません。 + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' には、既存の接続はありません。 + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + AuthenticationType の値 '{0}' が無効です。有効な値は 'Integrated' または 'SqlLogin' です。 + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + ApplicationIntent の値 '{0}' が無効です。有効な値は 'ReadWrite' または 'ReadOnly' です。 + + . + Parameters: 0 - intent (string) + + + Connection canceled + 接続がキャンセルされました。 + + + + + OwnerUri cannot be null or empty + OwnerUri を null または空にすることはできません。 + + + + + Connection details object cannot be null + 接続の詳細オブジェクトを null にすることはできません。 + + + + + ServerName cannot be null or empty + ServerName を null または空にすることはできません。 + + + + + {0} cannot be null or empty when using SqlLogin authentication + SqlLogin 認証を使用する場合に、{0} を null または空にすることはできません。 + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + クエリは既に完了して、取り消すことができません。 + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + クエリのキャンセルに成功しましたが、クエリの処理に失敗しました。OwnerURIが見つかりません。 + + + + + Query was canceled by user + クエリは、ユーザーによってキャンセルされました + + + + + The batch has not completed, yet + バッチがまだ完了していません、 + + + + + Batch index cannot be less than 0 or greater than the number of batches + バッチのインデックスは、0 未満あるいは、バッチの数より大きい値にすることはできません。 + + + + + Result set index cannot be less than 0 or greater than the number of result sets + 結果セットのインデックスは、0 未満あるいは、結果セットの数より大きい値にすることはできません + + + + + Maximum number of bytes to return must be greater than zero + 戻り値の最大バイト数は 0 より大きくする必要があります。 + + + + + Maximum number of chars to return must be greater than zero + 戻り値の最大文字数は 0 より大きくする必要があります。 + + + + + Maximum number of XML bytes to return must be greater than zero + 戻り値の最大のXMLバイト数は 0 より大きくする必要があります。 + + + + + Access method cannot be write-only + アクセス メソッドを書き込み専用にすることはできません。 + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper は、操作を実行する前に初期化されなければなりません。 + + + + + This FileStreamWrapper cannot be used for writing + この FileStreamWrapper は、書き込みには利用できません。 + + + + + (1 row affected) + (1 件処理されました) + + + + + ({0} rows affected) + ({0} 行処理されました) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + コマンドが正常に完了しました。 + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + クエリに失敗しました: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (列名なし) + + + + + The requested query does not exist + 要求されたクエリは存在しません + + + + + This editor is not connected to a database + このエディターは、データベースに接続されていません。 + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + このエディターのクエリは既に実行中です。クエリをキャンセルするか完了まで待って下さい。 + + + + + Sender for OnInfoMessage event must be a SqlConnection + OnInfoMessage イベントのSenderは、SqlConnectionである必要があります。 + + + + + Result cannot be saved until query execution has completed + クエリの実行が完了するまで、結果を保存することはできません。 + + + + + Internal error occurred while starting save task + 保存タスクの開始中に内部エラーが発生しました。 + + + + + A save request to the same path is in progress + 同一のパスへの保存リクエストを実行中です。 + + + + + Failed to save {0}: {1} + {0} を保存できませんでした: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + サーバーから結果が受信されていないため、サブセットを読み取ることができません。 + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + 開始行は 0 未満か、結果セット内の行数より大きい値にすることはできません。 + + + + + Row count must be a positive integer + 行数は正の整数でなければなりません。 + + + + + Could not retrieve column schema for result set + 結果セットの列のスキーマを取得できませんでした。 + + + + + Could not retrieve an execution plan from the result set + 結果セットから実行プランを取得できませんでした。 + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + この機能はAzure SQL DBとData Warehouseでは、現在サポートされていません: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Peek Definitionの実行中に予期しないエラーが発生しました: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + 結果は見つかりませんでした。 + + + + + No database object was retrieved. + データベース オブジェクトを取得できませんでした。 + + + + + Please connect to a server. + サーバーに接続してください。 + + + + + Operation timed out. + 操作がタイムアウトになりました。 + + + + + This object type is currently not supported by this feature. + このオブジェクトの種類は現在この機能ではサポートされていません。 + + + + + Position is outside of file line range + 位置がファイルの行の範囲外です。 + + + + + Position is outside of column range for line {0} + 位置が行 {0} の列の範囲外です。 + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + 開始位置 ({0}, {1}) は、終了位置 ({2}, {3}) より前、または同じでなければなりません。 + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, Level {1}, State {2}, Line {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + + + + + Msg {0}, Level {1}, State {2} + Msg {0}, Level {1}, State {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + バッチを処理中にエラーが発生しました。エラー メッセージ: {0} + + + + + ({0} row(s) affected) + ({0} 件処理されました) + + + + + The previous execution is not yet complete. + 前回の実行がまだ完了していません。 + + + + + A scripting error occurred. + スクリプト エラーが発生しました。 + + + + + Incorrect syntax was encountered while {0} was being parsed. + {0} の解析中に不正な構文が見つかりました。 + + + + + A fatal error occurred. + 致命的なエラーが発生しました。 + + + + + Batch execution completed {0} times... + 実行を {0} 回完了しました... + + + + + You cancelled the query. + クエリをキャンセルしました。 + + + + + An error occurred while the batch was being executed. + バッチの実行中にエラーが発生しました。 + + + + + An error occurred while the batch was being executed, but the error has been ignored. + バッチの実行中にエラーが発生しましたが、エラーを無視しました。 + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + コマンド {0} はサポートされていません。 + + + + + The variable {0} could not be found. + 変数 {0} が見つかりませんでした。 + + + + + SQL Execution error: {0} + SQL の実行エラー: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + バッチ パーサー ラッパーの実行: 行 {1}: {2} で {0} を検出... 説明: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + バッチ パーサー ラッパー実行エンジンのバッチ メッセージを受信しました: メッセージ: {0} 詳細メッセージ: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + バッチ パーサー ラッパー実行エンジンのバッチ ResultSet 処理: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + バッチ パーサー ラッパー実行エンジンのバッチ ResultSet が終了しました。 + + + + + Canceling batch parser wrapper batch execution. + バッチ パーサー ラッパーのバッチ実行をキャンセルしています。 + + + + + Scripting warning. + スクリプトの警告。 + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + このエラーの詳細については、製品ドキュメントのトラブルシューティングに関するトピックを参照してください。 + + + + + File '{0}' recursively included. + ファイル '{0}' が再帰的に含まれています。 + + + + + Missing end comment mark '*/'. + '*/' でマークされたコメントの終端がありません。 + + + + + Unclosed quotation mark after the character string. + 文字列の引用符が閉じていません。 + + + + + Incorrect syntax was encountered while parsing '{0}'. + '{0}' の解析中に無効な構文が見つかりました。 + + + + + Variable {0} is not defined. + 変数 {0} が定義されていません。 + + + + + test + テスト + + + + + Replacement of an empty string by an empty string. + 空の文字列で空の文字列を置換しています。 + + + + + Edit session does not exist. + 編集セッションは存在しません。 + + + + + Query has not completed execution + クエリの実行が完了していません。 + + + + + Query did not generate exactly one result set + クエリは 1 つの結果セットを生成できませんでした。 + + + + + Failed to add new row to update cache + キャッシュを更新する新しい行を追加できませんでした。 + + + + + Given row ID is outside the range of rows in the edit cache + 与えられた行IDは、編集キャッシュに存在する行の範囲外です。 + + + + + An update is already pending for this row and must be reverted first + この行に対する更新がすでに保留されています。まず更新を戻す必要があります。 + + + + + Given row ID does not have pending update + 与えられた行IDには保留中の更新はありません。 + + + + + Table or view metadata could not be found + テーブルまたはビューのメタデータが見つかりませんでした。 + + + + + Invalid format for binary column + バイナリ列の形式が無効です。 + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + ブール列の型は1もしくは0の数値、または true もしくは false の文字列でなければいけません。 + + + + + The column '{0}' is defined as NOT NULL but was not given a value + 必須なセルの値が入力されていません。 + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + この行の削除が保留中であるため、セルの更新は適用できません。 + + + + + Column ID must be in the range of columns for the query + 列 ID がクエリの列の範囲である必要があります。 + + + + + Column cannot be edited + 列を編集できません。 + + + + + No key columns were found + キー列が見つかりませんでした。 + + + + + An output filename must be provided + 出力ファイル名を指定する必要があります。 + + + + + Database object {0} cannot be used for editing. + データベース オブジェクト {0} は、編集のため使用できません。 + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + 指定された URI '{0}' には既定の接続はありません。 + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + コミット処理は実行中です。完了するまで待機してください。 + + + + + Decimal column is missing numeric precision or numeric scale + Decimal 型の列に有効桁数もしくは小数点以下桁数のどちらかが存在していません。 + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + 結果バッファーへ行を追加できません。データリーダーは行を含んでいません。 + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + time 型の値は 00:00:00.0000000 と 23:59:59.9999999 の範囲内になければなりません。 + + + + + NULL is not allowed for this column + この列では NULL は許可されていません。 + + + + + Edit session already exists. + 編集セッションがすでに存在します。 + + + + + Edit session has not been initialized + 編集セッションが初期化されていません。 + + + + + Edit session has already been initialized + 編集セッションはすでに初期化されました。 + + + + + Edit session has already been initialized or is in the process of initializing + 編集セッションはすでに初期化されたか、初期化中です。 + + + + + Query execution failed, see messages for details + クエリーの実行が失敗しました。詳細メッセージを確認してください。 + + + + + Result limit cannot be negative + 結果の上限は負の値にできません。 + + + + + NULL + NULL + + + + + A object name must be provided + オブジェクトの名前を指定する必要があります。 + + + + + Explicitly specifying server or database is not supported + 明示的なサーバーもしくはデータベースの指定はサポートされていません。 + + + + + Table metadata does not have extended properties + テーブルメタデータは拡張プロパティを持っていません。 + + + + + Table or view requested for edit could not be found + 編集を要求したテーブルもしくはビューが見つかりませんでした。 + + + + + Error expanding: {0} + '{0}' の拡張中にエラーが発生しました。 + + + + + Error connecting to {0} + {0} への接続中にエラーが発生しました + + + + + Aggregates + 集約 + + + + + Server Roles + サーバー ロール + + + + + Application Roles + アプリケーション ロール + + + + + Assemblies + アセンブリ + + + + + Assembly Files + アセンブリ ファイル + + + + + Asymmetric Keys + 非対称キー + + + + + Asymmetric Keys + 非対称キー + + + + + Data Compression Options + データ圧縮オプション + + + + + Certificates + 証明書 + + + + + FileTables + ファイルテーブル + + + + + Certificates + 証明書 + + + + + Check Constraints + CHECK 制約 + + + + + Columns + + + + + + Constraints + 制約 + + + + + Contracts + コントラクト + + + + + Credentials + 資格情報 + + + + + Error Messages + エラー メッセージ + + + + + Server Role Membership + サーバー ロール メンバーシップ + + + + + Database Options + データベース オプション + + + + + Database Roles + データベース ロール + + + + + Role Memberships + ロール メンバーシップ + + + + + Database Triggers + データベース トリガー + + + + + Default Constraints + 既定の制約 + + + + + Defaults + 既定値 + + + + + Sequences + シーケンス + + + + + Endpoints + エンドポイント + + + + + Event Notifications + イベント通知 + + + + + Server Event Notifications + サーバー イベント通知 + + + + + Extended Properties + 拡張プロパティ + + + + + Filegroups + ファイル グループ + + + + + Foreign Keys + 外部キー + + + + + Full-Text Catalogs + フルテキスト カタログ + + + + + Full-Text Indexes + フルテキスト インデックス + + + + + Functions + 関数 + + + + + Indexes + インデックス + + + + + Inline Functions + インライン関数 + + + + + Keys + キー + + + + + Linked Servers + リンク サーバー + + + + + Linked Server Logins + リンク サーバー ログイン + + + + + Logins + ログイン + + + + + Master Key + マスター キー + + + + + Master Keys + マスター キー + + + + + Message Types + メッセージ型 + + + + + Table-Valued Functions + テーブル値関数 + + + + + Parameters + パラメーター + + + + + Partition Functions + パーティション関数 + + + + + Partition Schemes + パーティション構成 + + + + + Permissions + アクセス許可 + + + + + Primary Keys + 主キー + + + + + Programmability + プログラミング + + + + + Queues + キュー + + + + + Remote Service Bindings + リモート サービスのバインド + + + + + Returned Columns + 返された列 + + + + + Roles + ロール + + + + + Routes + ルート + + + + + Rules + ルール + + + + + Schemas + スキーマ + + + + + Security + セキュリティ + + + + + Server Objects + サーバー オブジェクト + + + + + Management + 管理 + + + + + Triggers + トリガー + + + + + Service Broker + Service Broker + + + + + Services + サービス + + + + + Signatures + 署名 + + + + + Log Files + ログ ファイル + + + + + Statistics + 統計 + + + + + Storage + ストレージ + + + + + Stored Procedures + ストアド プロシージャ + + + + + Symmetric Keys + 対称キー + + + + + Synonyms + シノニム + + + + + Tables + テーブル + + + + + Triggers + トリガー + + + + + Types + + + + + + Unique Keys + 一意キー + + + + + User-Defined Data Types + ユーザー定義データ型 + + + + + User-Defined Types (CLR) + ユーザー定義型 (CLR) + + + + + Users + ユーザー + + + + + Views + ビュー + + + + + XML Indexes + XML インデックス + + + + + XML Schema Collections + XML スキーマ コレクション + + + + + User-Defined Table Types + ユーザー定義テーブル型 + + + + + Files + ファイル + + + + + Missing Caption + キャプションが見つかりません + + + + + Broker Priorities + Broker の優先度 + + + + + Cryptographic Providers + 暗号化プロバイダー + + + + + Database Audit Specifications + データベース監査の仕様 + + + + + Database Encryption Keys + データベース暗号化キー + + + + + Event Sessions + イベント セッション + + + + + Full Text Stoplists + フルテキスト ストップリスト + + + + + Resource Pools + リソース プール + + + + + Audits + 監査 + + + + + Server Audit Specifications + サーバー監査の仕様 + + + + + Spatial Indexes + 空間インデックス + + + + + Workload Groups + ワークロード グループ + + + + + SQL Files + SQL ファイル + + + + + Server Functions + サーバー関数 + + + + + SQL Type + SQL 型 + + + + + Server Options + サーバー オプション + + + + + Database Diagrams + データベース ダイアグラム + + + + + System Tables + システム テーブル + + + + + Databases + データベース + + + + + System Contracts + システム コントラクト + + + + + System Databases + システム データベース + + + + + System Message Types + システム メッセージの種類 + + + + + System Queues + システム キュー + + + + + System Services + システム サービス + + + + + System Stored Procedures + システム ストアド プロシージャ + + + + + System Views + システム ビュー + + + + + Data-tier Applications + データ層アプリケーション + + + + + Extended Stored Procedures + 拡張ストアド プロシージャ + + + + + Aggregate Functions + 集計関数 + + + + + Approximate Numerics + 概数 + + + + + Binary Strings + バイナリ文字列 + + + + + Character Strings + 文字列 + + + + + CLR Data Types + CLR データ型 + + + + + Configuration Functions + 構成関数 + + + + + Cursor Functions + カーソル関数 + + + + + System Data Types + システム データ型 + + + + + Date and Time + 日付と時刻 + + + + + Date and Time Functions + 日付と時刻関数 + + + + + Exact Numerics + 真数 + + + + + System Functions + システム関数 + + + + + Hierarchy Id Functions + 階層 ID 関数 + + + + + Mathematical Functions + 数学関数 + + + + + Metadata Functions + メタデータ関数 + + + + + Other Data Types + その他のデータ型 + + + + + Other Functions + その他の関数 + + + + + Rowset Functions + 行セット関数 + + + + + Security Functions + セキュリティ関数 + + + + + Spatial Data Types + 空間データ型 + + + + + String Functions + 文字列関数 + + + + + System Statistical Functions + システム統計関数 + + + + + Text and Image Functions + テキストとイメージ関数 + + + + + Unicode Character Strings + Unicode 文字列 + + + + + Aggregate Functions + 集計関数 + + + + + Scalar-valued Functions + スカラー値関数 + + + + + Table-valued Functions + テーブル値関数 + + + + + System Extended Stored Procedures + システム拡張ストアド プロシージャ + + + + + Built-in Types + ビルトイン型 + + + + + Built-in Server Roles + 組み込みのサーバー ロール + + + + + User with Password + ユーザーとパスワード + + + + + Search Property List + 検索プロパティ リスト + + + + + Security Policies + セキュリティ ポリシー + + + + + Security Predicates + セキュリティ述語 + + + + + Server Role + サーバー ロール + + + + + Search Property Lists + 検索プロパティ リスト + + + + + Column Store Indexes + 列のストア インデックス + + + + + Table Type Indexes + テーブル型インデックス + + + + + Selective XML Indexes + 選択的 XML インデックス + + + + + XML Namespaces + XML 名前空間 + + + + + XML Typed Promoted Paths + XML の型指定された昇格パス + + + + + T-SQL Typed Promoted Paths + T-SQL の型指定された昇格パス + + + + + Database Scoped Credentials + データベース スコープ資格情報 + + + + + External Data Sources + 外部データ ソース + + + + + External File Formats + 外部ファイル形式 + + + + + External Resources + 外部リソース + + + + + External Tables + 外部テーブル + + + + + Always Encrypted Keys + Always Encrypted キー + + + + + Column Master Keys + 列マスター キー + + + + + Column Encryption Keys + 列暗号化キー + + + + + Server + サーバー + + + + + Error parsing ScriptingParams.ConnectionString property. + ScriptingParams.ConnectionString プロパティの解析エラーです。 + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + ScriptingParams.FilePath プロパティで指定されたディレクトリが無効です。 + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + ScriptingListObjectsCompleteParams.ConnectionString プロパティの解析エラーです。 + + + + + {0} ({1}, {2}, {3}) + {0} ({1}、{2}、{3}) + + + + + No default + 既定値以外 + + + + + Input + 入力 + + + + + Input/Output + 入力/出力 + + + + + Input/ReadOnly + 入力/読み取り専用 + + + + + Input/Output/ReadOnly + 入力/出力/読み取り専用 + + + + + Default + 既定値 + + + + + null + NULL + + + + + not null + NULL 以外 + + + + + {0} ({1}, {2}) + {0} ({1}、{2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1} 計算値、{2}、{3}) + + + + + {0} ({1}Computed) + {0} ({1} 計算値) + + + + + {0} (Column Set, {1}) + {0} (列セット、{1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (列セット、{1}{2}、{3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (列セット、{1}、{2}、{3}) + + + + + Unique + 一意 + + + + + Non-Unique + 一意でない + + + + + Clustered + クラスター化 + + + + + Non-Clustered + 非クラスター + + + + + History + 履歴 + + + + + System-Versioned + システムバージョン管理 + + + + + Unavailable + 使用不可 + + + + + Current default filegroup: {0} + 現在の既定のファイル グループ: {0} + + + + + New Filegroup for {0} + 新しいファイルグループ {0} + + + + + Default + 既定値 + + + + + Files + ファイル + + + + + Name + 名前 + + + + + Read-Only + 読み取り専用 + + + + + Autogrowth / Maxsize + 自動拡張 / 最大容量 + + + + + ... + ... + + + + + <default> + <既定> + + + + + Filegroup + ファイル グループ + + + + + Logical Name + 論理名 + + + + + File Type + ファイルタイプ + + + + + Initial Size (MB) + 初期サイズ (MB) + + + + + <new filegroup> + <新しいファイルグループ> + + + + + Path + パス + + + + + File Name + ファイル名 + + + + + <raw device> + <RAWデバイス> + + + + + Bulk-logged + 一括ログ + + + + + Full + 完全 + + + + + Simple + 単純 + + + + + Select Database Owner + データベース 所有者の選択 + + + + + None + なし + + + + + By {0} MB, Limited to {1} MB + {0} MBごと、{1} MBを上限 + + + + + By {0} percent, Limited to {1} MB + {0} パーセントごと、{1} MBまで + + + + + By {0} MB, Unlimited + {0} MBごと、無制限 + + + + + By {0} percent, Unlimited + {0} パーセントごと、無制限 + + + + + Unlimited + 無制限 + + + + + Limited to {0} MB + {0} MBまで + + + + + Automatic + 自動 + + + + + Service Broker + Service Broker + + + + + Collation + 照合順序 + + + + + Cursor + カーソル + + + + + Miscellaneous + その他 + + + + + Recovery + 復旧 + + + + + State + 状態 + + + + + ANSI NULL Default + ANSI NULL 既定値 + + + + + ANSI NULLS Enabled + ANSI NULLS 有効 + + + + + ANSI Padding Enabled + ANSI Padding 有効 + + + + + ANSI Warnings Enabled + ANSI 警告有効 + + + + + Arithmetic Abort Enabled + 算術アボート有効 + + + + + Auto Close + 自動クローズ + + + + + Auto Create Statistics + 統計の自動作成 + + + + + Auto Shrink + 自動圧縮 + + + + + Auto Update Statistics + 統計の自動更新 + + + + + Auto Update Statistics Asynchronously + 統計の非同期的自動更新 + + + + + Case Sensitive + 大文字と小文字を区別する + + + + + Close Cursor on Commit Enabled + コミットでカーソルを閉じる + + + + + Collation + 照合順序 + + + + + Concatenate Null Yields Null + Nullとの連結をNullとして取り扱う + + + + + Database Compatibility Level + データベース互換性レベル + + + + + Database State + データベース状態 + + + + + Default Cursor + 既定のカーソル + + + + + Full-Text Indexing Enabled + フルテキスト インデックス 有効化 + + + + + Numeric Round-Abort + 数値丸め処理アボート + + + + + Page Verify + ページ確認 + + + + + Quoted Identifiers Enabled + 引用符で囲まれた識別子が有効 + + + + + Database Read-Only + 読み取り専用データベース + + + + + Recursive Triggers Enabled + 再帰トリガー有効 + + + + + Restrict Access + アクセスの制限 + + + + + Select Into/Bulk Copy + Select Into/ バルクコピー + + + + + Honor Broker Priority + Broker の優先度の許可 + + + + + Service Broker Identifier + Service Broker 識別子 + + + + + Broker Enabled + ブローカー有効化 + + + + + Truncate Log on Checkpoint + チェックポイントでのログの切り捨て + + + + + Cross-database Ownership Chaining Enabled + 複数データベースの組み合わせ所有権有効 + + + + + Trustworthy + 信頼可能 + + + + + Date Correlation Optimization Enabled + データ相関性の最適化 +Enabledprototype_db_prop_parameterization = Parameterization + + + + + Forced + 強制 + + + + + Simple + 単純 + + + + + ROWS Data + 列データ + + + + + LOG + ログ + + + + + FILESTREAM Data + FILESTREAM データ + + + + + Not Applicable + 適用不可 + + + + + <default path> + <既定のパス> + + + + + Open Connections + コネクションを開く + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + データベースのプロパティを変更するには、SQL Server はデータベースへの他のすべての接続を閉じる必要があります。プロパティを変更して、他のすべての接続を閉じてよろしいですか? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + VarDecimal ストレージ形式有効 + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + 暗号化有効 + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + 配布ポリシーのハッシュでは、ハッシュの先頭列の番号は任意ですが、1 から 16 個の列にする必要があります + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + なし + + + + + Partial + 部分的 + + + + + FILESTREAM Files + FILESTREAM ファイル + + + + + No Applicable Filegroup + 適用不可なファイルグループ + + + + + The database {0} is not accessible. + データベース {0} にアクセスできません。 + + + + + Query has no results to return + クエリーは結果を返しませんでした + + + + + Result set has too many rows to be safely loaded + 結果セットの行数が多すぎるため安全にロードすることはできません + + + + Parameterization + パラメーター化 + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + NORECOVERY オプションを使用してバックアップを復元するときにこのオプションを指定することはできません。 + + + + + Invalid path for database file: '{0}' + データベース ファイルのパスが無効です: '{0}' + + + + + Log + ログ + + + + + Failed to create restore plan + リストア プランの作成に失敗しました。 + + + + + Restore database is not supported + データベースのリストアはサポートされていません。 + + + + + Restore Database + データベースのリストア + + + + + (Copy Only) + (コピーのみ) + + + + + Component + コンポーネント + + + + + Type + 種類 + + + + + Server + サーバー + + + + + Database + データベース + + + + + Position + 位置 + + + + + First LSN + 最初の LSN + + + + + Last LSN + 最後の LSN + + + + + Checkpoint LSN + チェックポイントの LSN + + + + + Full LSN + 全 LSN + + + + + Start Date + 開始日 + + + + + Finish Date + 完了日 + + + + + Size + サイズ + + + + + User Name + ユーザー名 + + + + + Expiration + 有効期限 + + + + + Name + 名前 + + + + + The last backup taken ({0}) + 最後に作成されたバックアップ ({0}) + + + + + Backup Database + データベースをバックアップする + + + + + In progress + 実行中 + + + + + Completed + 完了 + + + + + scripting + スクリプト + + + + + Connection not found + 接続が見つかりません。 + + + + + Please provide a file path instead of directory path + 指定されたファイル名がディレクトリ名と同じです: {0} + + + + + The provided path is invalid + バックアップ ファイルの場所が存在するかどうか確認できません: {0} + + + + + Cannot access the specified path on the server: {0} + サーバーで指定されたパスにアクセスできません: {0} + + + + + No backupset selected to be restored + リストアするバックアップセットが選択されていません + + + + + Never + 行わない + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + パス {0} は有効なディレクトリではありません + + + + + For directory {0} a file with name {1} already exists + ディレクトリ {0} 内に {1} という名前のファイルは既に存在します + + + + + Value {0} is too large to fit in column of type {1} + 値 {0} は大きすぎるため、型 {1} の列に収まりません + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ko.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ko.xlf new file mode 100644 index 0000000000..34a658e824 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ko.xlf @@ -0,0 +1,2777 @@ + + + + + Connection parameters cannot be null + 연결 매개 변수는 null 일 수 없습니다. + + + + + OwnerUri cannot be null or empty + OwnerUri은 null 이거나 비어 있을 수 없습니다. + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUrl '{0}'는 기존 연결이 없습니다. + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + AuthenticationType 값으로 ' {0} '이 (가) 잘못 되었습니다. 유효한 값은 'Integrated'나 'SqlLogin' 입니다. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + ApplicationIntent 값으로 ' {0} '이 (가) 잘못 되었습니다. 유효한 값은 'ReadWrite'나 'ReadOnly' 입니다. + + . + Parameters: 0 - intent (string) + + + Connection canceled + 연결이 취소되었습니다. + + + + + OwnerUri cannot be null or empty + OwnerUri는 null 이나 빈값일 수 없습니다 + + + + + Connection details object cannot be null + 연결 세부 정보 개체는 null이 될 수 없습니다. + + + + + ServerName cannot be null or empty + 서버 이름은 null이거나 비어 있을 수 없습니다. + + + + + {0} cannot be null or empty when using SqlLogin authentication + SqlLogin 인증 사용 시 {0}은(는) null이나 빈값일 수 없습니다. + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + 쿼리가 이미 완료되어 취소할 수 없습니다. + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + 쿼리 취소가 완료되었으나 쿼리를 삭제하는데 실패했습니다. Owner URI를 찾을 수 없습니다. + + + + + Query was canceled by user + 사용자가 쿼리를 취소 했습니다. + + + + + The batch has not completed, yet + 일괄 처리가 아직 완료되지 않았습니다. + + + + + Batch index cannot be less than 0 or greater than the number of batches + 일괄 처리 인덱스는 0 미만 이거나 일괄 처리 갯수 보다 클 수 없습니다. + + + + + Result set index cannot be less than 0 or greater than the number of result sets + 결과 집합 인덱스는 0 미만 이거나 결과 집합의 갯수보다 클 수 없습니다. + + + + + Maximum number of bytes to return must be greater than zero + 반환되는 최대 바이트 수는 0보다 커야 합니다. + + + + + Maximum number of chars to return must be greater than zero + 반환되는 최대 문자 수는 0보다 커야 합니다. + + + + + Maximum number of XML bytes to return must be greater than zero + 반환되는 최대 XML 바이트 수는 0보다 커야 합니다. + + + + + Access method cannot be write-only + 액세스 방법은 쓰기 전용이 될 수 없습니다. + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper 는 작업을 수행 하기 전에 초기화 해야 합니다. + + + + + This FileStreamWrapper cannot be used for writing + FileStreamWrapper 는 쓰기용으로 사용할 수 없습니다. + + + + + (1 row affected) + (1 개 행이 영향을 받음) + + + + + ({0} rows affected) + ({0} 개 행이 영향을 받음) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + 명령이 성공적으로 완료 되었습니다. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + 메시지 {0}, 수준 {1}, 상태 {2}, 줄 {3} {4} {5}. + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + 쿼리 실패: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (열 이름 없음) + + + + + The requested query does not exist + 요청한 쿼리가 존재하지 않습니다. + + + + + This editor is not connected to a database + 편집기가 데이터베이스에 연결되지 않았습니다. + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + 쿼리가 현재 편집기 세션에서 이미 실행 중입니다. 쿼리를 취소하거나 완료 될 때까지 대기 하십시오. + + + + + Sender for OnInfoMessage event must be a SqlConnection + OnInfoMessage 이벤트 발신자는 SqlConnection 이어야 합니다. + + + + + Result cannot be saved until query execution has completed + 결과는 쿼리 실행이 완료 될 때까지 저장할 수 없습니다. + + + + + Internal error occurred while starting save task + 저장 작업을 시작 하는 동안 내부 오류가 발생 했습니다. + + + + + A save request to the same path is in progress + 동일한 경로로 저장 요청이 진행 중입니다. + + + + + Failed to save {0}: {1} + 저장 실패 {0}:{1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + 서버로부터 결과를 모두 읽기 전에는 일부 결과를 읽을 수 없습니다. + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + 시작 행은 0 미만이거나 결과 집합의 행의 갯수보다 클 수 없습니다. + + + + + Row count must be a positive integer + 행 수는 양수여야 합니다. + + + + + Could not retrieve column schema for result set + 결과 집합의 열 스키마를 검색할 수 없습니다. + + + + + Could not retrieve an execution plan from the result set + 결과 집합에서 실행 계획을 검색할 수 없습니다. + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + 현재 이 기능은 Azure SQL DB와 데이터 웨어하우스에서 지원 되지 않습니다: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + 정의 피킹을 실행하는 동안 예상치 못한 오류가 발생했습니다: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + 결과가 없습니다. + + + + + No database object was retrieved. + 검색된 데이터베이스 개체가 없습니다. + + + + + Please connect to a server. + 서버에 연결 하십시오. + + + + + Operation timed out. + 작업 제한 시간이 초과 되었습니다. + + + + + This object type is currently not supported by this feature. + 현재 이 개체 형식은 지원되지 않습니다. + + + + + Position is outside of file line range + 위치가 파일 줄 범위를 벗어났습니다. + + + + + Position is outside of column range for line {0} + 위치가 줄 {0} 의 열 범위를 벗어났습니다. + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + 시작 위치 ({0}, {1})은(는) 반드시 끝 위치 ({2}, {3}) 과 같거나 이전이어야 합니다. + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + 메시지 {0}, 수준{1}, 상태 {2}, 줄 {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + 메시지 {0}, 수준 {1}, 상태 {2}, 프로시저 {3}, 줄 {4} + + + + + Msg {0}, Level {1}, State {2} + 메시지 {0}, 수준 {1}, 상태 {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + 일괄 처리를 처리 하는 동안 하는 동안 오류가 발생 합니다. 오류 메시지: {0} + + + + + ({0} row(s) affected) + ({0} 개 행이 영향을 받음) + + + + + The previous execution is not yet complete. + 이전 실행이 아직 완료 되지 않았습니다. + + + + + A scripting error occurred. + 스크립팅 오류가 발생 했습니다. + + + + + Incorrect syntax was encountered while {0} was being parsed. + {0}에 잘못된 구문이 발견되었습니다. + + + + + A fatal error occurred. + 치명적인 오류가 발생 했습니다. + + + + + Batch execution completed {0} times... + {0}회 실행 완료... + + + + + You cancelled the query. + 쿼리를 취소 했습니다. + + + + + An error occurred while the batch was being executed. + 일괄 처리를 실행 하는 동안 오류가 발생 합니다. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + 일괄 처리를 실행 하는 동안 오류가 발생했으나 그 오류는 무시되었습니다. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + {0} 명령은 지원되지 않습니다. + + + + + The variable {0} could not be found. + {0} 변수를 찾을 수 없습니다. + + + + + SQL Execution error: {0} + SQL 실행 오류: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + 일괄처리 구문분석 래퍼 실행: {0} 발견... 줄 {1}: {2} 설명: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 메시지를 받았습니다. 메시지: {0} 자세한 메시지: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 ResultSet을 처리하고 있습니다. DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + 일괄 처리 파서 래퍼 실행 엔진 일괄 처리 ResultSet을 완료했습니다. + + + + + Canceling batch parser wrapper batch execution. + 일괄 처리 파서 래퍼 일괄 처리 실행을 취소하고 있습니다. + + + + + Scripting warning. + 스크립팅 경고. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + 이 오류에 대한 추가 정보는 제품 설명서의 문제 해결 항목을 참조하십시오. + + + + + File '{0}' recursively included. + ' {0} '이 (가) 재귀적으로 포함 된 파일입니다. + + + + + Missing end comment mark '*/'. + 주석 끝 표시 ' * /' 누락 . + + + + + Unclosed quotation mark after the character string. + 문자열에 닫히지 않은 인용 부호. + + + + + Incorrect syntax was encountered while parsing '{0}'. + '{0}'을(를) 구문 분석하는 동안 잘못된 구문을 발견했습니다. + + + + + Variable {0} is not defined. + {0} 변수가 정의되지 않았습니다. + + + + + test + 테스트 + + + + + Replacement of an empty string by an empty string. + +votes +빈 문자열을 빈 문자열로 대체. + + + + + Edit session does not exist. + 편집 세션이 존재하지 않습니다. + + + + + Query has not completed execution + 쿼리 실행이 완료되지 않았습니다. + + + + + Query did not generate exactly one result set + 쿼리가 정확히 하나의 결과 집합을 생성하지 않았습니다. + + + + + Failed to add new row to update cache + 업데이트 캐시에 새로운 행 추가를 실패했습니다. + + + + + Given row ID is outside the range of rows in the edit cache + 지정된 row ID가 수정 중인 캐시의 행 범위 밖에 있습니다. + + + + + An update is already pending for this row and must be reverted first + 이 행에 대한 업데이트가 이미 보류 중이므로 먼저 되돌려야 합니다. + + + + + Given row ID does not have pending update + 주어진 row ID에 보류 중인 업데이트가 없습니다. + + + + + Table or view metadata could not be found + 테이블이나 뷰 메타 데이터를 찾을 수 없습니다. + + + + + Invalid format for binary column + 이진 열에 형식이 잘못되었습니다. + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Boolean 열은 반드시 숫자 1이나 0 혹은 문자 true나 false여야 합니다. + + + + + The column '{0}' is defined as NOT NULL but was not given a value + 필수 셀 값이 누락되었습니다. + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + 행 삭제가 보류 중이므로, 셀을 업데이트할 수 없습니다. + + + + + Column ID must be in the range of columns for the query + 열 ID는 쿼리의 열 범위 내에 있어야 합니다. + + + + + Column cannot be edited + 열을 편집할 수 없습니다. + + + + + No key columns were found + 키 열이 없습니다. + + + + + An output filename must be provided + 출력 파일명이 필요합니다. + + + + + Database object {0} cannot be used for editing. + 데이터베이스 개체 {0} 는 편집할 수 없습니다. + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + 지정된 Uri ' {0} '에 기본 연결이 지정되지 않았습니다. + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + 커밋 작업이 진행 중입니다. 완료될 때까지 기다리세요. + + + + + Decimal column is missing numeric precision or numeric scale + Decimal 형식 열에 전체 자릿수 또는 소수 자릿수가 없습니다. + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + 결과 버퍼에 새로운 행을 추가할 수 없거나 데이터 리더에 행이 없습니다. + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + TIME 열의 값은 00:00:00.0000000과 23:59:59.9999999 사이의 값만 허용됩니다. + + + + + NULL is not allowed for this column + 이 열은 NULL을 허용하지 않습니다. + + + + + Edit session already exists. + 편집 세션이 이미 존재합니다. + + + + + Edit session has not been initialized + 편집 세션이 초기화 되지 않았습니다. + + + + + Edit session has already been initialized + 편집 세션이 이미 초기화 되었습니다. + + + + + Edit session has already been initialized or is in the process of initializing + 편집 세션이 이미 초기화 되었거나 초기화 중입니다. + + + + + Query execution failed, see messages for details + 쿼리 실행에 실패했습니다. 자세한 정보는 메시지를 참조하세요. + + + + + Result limit cannot be negative + 결과 제한은 음수가 될 수 없습니다. + + + + + NULL + NULL + + + + + A object name must be provided + 개체 이름이 필요합니다. + + + + + Explicitly specifying server or database is not supported + 서버와 데이터베이스를 명시적으로 지정할 수 없습니다. + + + + + Table metadata does not have extended properties + 테이블 메타데이터에 확장 속성이 없습니다. + + + + + Table or view requested for edit could not be found + 편집하려는 테이블이나 뷰를 찾을 수 없습니다 + + + + + Error expanding: {0} + 오류 확장: {0} + + + + + Error connecting to {0} + {0}에 연결하는 동안 오류가 발생했습니다. + + + + + Aggregates + 집계 + + + + + Server Roles + 서버 역할 + + + + + Application Roles + 응용 프로그램 역할 + + + + + Assemblies + 어셈블리 + + + + + Assembly Files + 어셈블리 파일 + + + + + Asymmetric Keys + 비대칭 키 + + + + + Asymmetric Keys + 비대칭 키 + + + + + Data Compression Options + 데이터 압축 옵션 + + + + + Certificates + 인증서 + + + + + FileTables + FileTables + + + + + Certificates + 인증서 + + + + + Check Constraints + Check 제약 조건 + + + + + Columns + + + + + + Constraints + 제약 조건 + + + + + Contracts + 계약 + + + + + Credentials + 자격 증명 + + + + + Error Messages + 오류 메시지 + + + + + Server Role Membership + 서버 역할 멤버 자격 + + + + + Database Options + 데이터베이스 옵션 + + + + + Database Roles + 데이터베이스 역할 + + + + + Role Memberships + 역할 멤버 자격 + + + + + Database Triggers + 데이터베이스 트리거 + + + + + Default Constraints + 기본 제약 조건 + + + + + Defaults + 기본값 + + + + + Sequences + 시퀀스 + + + + + Endpoints + 끝점 + + + + + Event Notifications + 이벤트 알림 + + + + + Server Event Notifications + 서버 이벤트 알림 + + + + + Extended Properties + 확장 속성 + + + + + Filegroups + 파일 그룹 + + + + + Foreign Keys + 외래 키 + + + + + Full-Text Catalogs + 전체 텍스트 카탈로그 + + + + + Full-Text Indexes + 전체 텍스트 인덱스 + + + + + Functions + 함수 + + + + + Indexes + 인덱스 + + + + + Inline Functions + 인라인 함수 + + + + + Keys + + + + + + Linked Servers + 연결된 서버 + + + + + Linked Server Logins + 연결된 서버 로그인 + + + + + Logins + 로그인 + + + + + Master Key + 마스터 키 + + + + + Master Keys + 마스터 키 + + + + + Message Types + 메시지 유형 + + + + + Table-Valued Functions + 테이블 반환 함수 + + + + + Parameters + 매개 변수 + + + + + Partition Functions + 파티션 함수 + + + + + Partition Schemes + 파티션 구성표 + + + + + Permissions + 사용 권한 + + + + + Primary Keys + 기본 키 + + + + + Programmability + 프로그래밍 기능 + + + + + Queues + + + + + + Remote Service Bindings + 원격 서비스 바인딩 + + + + + Returned Columns + 반환 열 + + + + + Roles + 역할 + + + + + Routes + 경로 + + + + + Rules + 규칙 + + + + + Schemas + 스키마 + + + + + Security + 보안 + + + + + Server Objects + 서버 개체 + + + + + Management + 관리 + + + + + Triggers + 트리거 + + + + + Service Broker + Service Broker + + + + + Services + 서비스 + + + + + Signatures + 서명 + + + + + Log Files + 로그 파일 + + + + + Statistics + 통계 + + + + + Storage + 저장소 + + + + + Stored Procedures + 저장 프로시저 + + + + + Symmetric Keys + 대칭 키 + + + + + Synonyms + 동의어 + + + + + Tables + 테이블 + + + + + Triggers + 트리거 + + + + + Types + 유형 + + + + + Unique Keys + 고유 키 + + + + + User-Defined Data Types + 사용자 정의 데이터 형식 + + + + + User-Defined Types (CLR) + 사용자 정의 형식 (CLR) + + + + + Users + 사용자 + + + + + Views + + + + + + XML Indexes + XML 인덱스 + + + + + XML Schema Collections + XML 스키마 컬렉션 + + + + + User-Defined Table Types + 사용자 정의 테이블 형식 + + + + + Files + 파일 + + + + + Missing Caption + 캡션 누락 + + + + + Broker Priorities + 브로커 우선 순위 + + + + + Cryptographic Providers + 암호화 공급자 + + + + + Database Audit Specifications + 데이터베이스 감사 사양 + + + + + Database Encryption Keys + 데이터베이스 암호화 키 + + + + + Event Sessions + 이벤트 세션 + + + + + Full Text Stoplists + 전체 텍스트 중지 목록 + + + + + Resource Pools + 리소스 풀 + + + + + Audits + 감사 + + + + + Server Audit Specifications + 서버 감사 사양 + + + + + Spatial Indexes + 공간 인덱스 + + + + + Workload Groups + 작업 그룹 + + + + + SQL Files + SQL 파일 + + + + + Server Functions + 서버 함수 + + + + + SQL Type + SQL 유형 + + + + + Server Options + 서버 옵션 + + + + + Database Diagrams + 데이터베이스 다이어그램 + + + + + System Tables + 시스템 테이블 + + + + + Databases + 데이터베이스 + + + + + System Contracts + 시스템 계약 + + + + + System Databases + 시스템 데이터베이스 + + + + + System Message Types + 시스템 메시지 유형 + + + + + System Queues + 시스템 큐 + + + + + System Services + 시스템 서비스 + + + + + System Stored Procedures + 시스템 저장 프로시저 + + + + + System Views + 시스템 뷰 + + + + + Data-tier Applications + 데이터 계층 응용 프로그램 + + + + + Extended Stored Procedures + 확장 저장 프로시저 + + + + + Aggregate Functions + 집계 함수 + + + + + Approximate Numerics + 근사치 + + + + + Binary Strings + 이진 문자열 + + + + + Character Strings + 문자열 + + + + + CLR Data Types + CLR 데이터 형식 + + + + + Configuration Functions + 구성 함수 + + + + + Cursor Functions + 커서 함수 + + + + + System Data Types + 시스템 데이터 형식 + + + + + Date and Time + 날짜 및 시간 + + + + + Date and Time Functions + 날짜 및 시간 함수 + + + + + Exact Numerics + 정확한 수치 + + + + + System Functions + 시스템 함수 + + + + + Hierarchy Id Functions + 계층 구조 ID 함수 + + + + + Mathematical Functions + 수학 함수 + + + + + Metadata Functions + 메타데이터 함수 + + + + + Other Data Types + 기타 데이터 형식 + + + + + Other Functions + 기타 함수 + + + + + Rowset Functions + 행 집합 함수 + + + + + Security Functions + 보안 함수 + + + + + Spatial Data Types + 공간 데이터 형식 + + + + + String Functions + 문자열 함수 + + + + + System Statistical Functions + 시스템 통계 함수 + + + + + Text and Image Functions + 텍스트 및 이미지 함수 + + + + + Unicode Character Strings + 유니코드 문자열 + + + + + Aggregate Functions + 집계 함수 + + + + + Scalar-valued Functions + 스칼라 반환 함수 + + + + + Table-valued Functions + 테이블 반환 함수 + + + + + System Extended Stored Procedures + 시스템 확장 저장 프로시저 + + + + + Built-in Types + 기본 제공 유형 + + + + + Built-in Server Roles + 기본 제공 서버 역할 + + + + + User with Password + 암호가 있는 사용자 + + + + + Search Property List + 검색 속성 목록 + + + + + Security Policies + 보안 정책 + + + + + Security Predicates + 보안 조건자 + + + + + Server Role + 서버 역할 + + + + + Search Property Lists + 검색 속성 목록 + + + + + Column Store Indexes + 열 저장 인덱스 + + + + + Table Type Indexes + 테이블 형식 인덱스 + + + + + Selective XML Indexes + 선택적 XML 인덱스 + + + + + XML Namespaces + XML 네임스페이스 + + + + + XML Typed Promoted Paths + XML 유형의 공유된 경로 + + + + + T-SQL Typed Promoted Paths + T-SQL 유형의 공유된 경로 + + + + + Database Scoped Credentials + 데이터베이스 범위 자격 증명 + + + + + External Data Sources + 외부 데이터 원본 + + + + + External File Formats + 외부 파일 형식 + + + + + External Resources + 외부 리소스 + + + + + External Tables + 외부 테이블 + + + + + Always Encrypted Keys + Always Encrypted 키 + + + + + Column Master Keys + 열 마스터 키 + + + + + Column Encryption Keys + 열 암호화 키 + + + + + Server + 서버 + + + + + Error parsing ScriptingParams.ConnectionString property. + ScriptingParams.ConnectionString 속성 분석을 하는 동안 오류가 발생했습니다. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + ScriptingParams.FilePath 속성에 잘못된 디렉터리 지정 + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + ScriptingListObjectsCompleteParams.ConnectionSring 속성을 분석할때 오류가 생겼습니다. + + + + + {0} ({1}, {2}, {3}) + {0}({1}, {2}, {3}) + + + + + No default + 기본값 없음 + + + + + Input + 입력 + + + + + Input/Output + 입/출력 + + + + + Input/ReadOnly + 입력/읽기 전용 + + + + + Input/Output/ReadOnly + 입/출력/읽기 전용 + + + + + Default + 기본값 + + + + + null + Null + + + + + not null + Not Null + + + + + {0} ({1}, {2}) + {0}({1}, {2}) + + + + + {0} ({1}) + {0}({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0}({1}계산됨, {2}, {3}) + + + + + {0} ({1}Computed) + {0}({1}계산됨) + + + + + {0} (Column Set, {1}) + {0}(열 집합, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0}(열 집합, {1}{2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0}(열 집합, {1}, {2}, {3}) + + + + + Unique + 고유 + + + + + Non-Unique + 고유하지 않음 + + + + + Clustered + 클러스터형 + + + + + Non-Clustered + 비클러스터형 + + + + + History + 기록 + + + + + System-Versioned + 시스템 버전 관리 + + + + + Unavailable + 사용할 수 없음 + + + + + Current default filegroup: {0} + 현재 기본 파일 그룹: {0} + + + + + New Filegroup for {0} + {0}에 대한 새 파일 그룹 + + + + + Default + 기본값 + + + + + Files + 파일 + + + + + Name + 이름 + + + + + Read-Only + 읽기 전용 + + + + + Autogrowth / Maxsize + 자동 증가 / 최대 크기 + + + + + ... + ... + + + + + <default> + <기본값> + + + + + Filegroup + 파일 그룹 + + + + + Logical Name + 논리적 이름 + + + + + File Type + 파일 형식 + + + + + Initial Size (MB) + 처음 크기 (MB) + + + + + <new filegroup> + <새 파일 그룹> + + + + + Path + 경로 + + + + + File Name + 파일 이름 + + + + + <raw device> + <원시 장치> + + + + + Bulk-logged + 대량 로그 + + + + + Full + 전체 + + + + + Simple + 단순 + + + + + Select Database Owner + 데이터베이스 소유자 선택 + + + + + None + 없음 + + + + + By {0} MB, Limited to {1} MB + {0} MB 단위로 {1} MB까지 제한됨 + + + + + By {0} percent, Limited to {1} MB + {0} % 단위로 {1} MB까지 제한됨 + + + + + By {0} MB, Unlimited + {0} MB 단위로, 제한 없음 + + + + + By {0} percent, Unlimited + {0} % 단위로, 제한 없음 + + + + + Unlimited + 제한 없음 + + + + + Limited to {0} MB + {0} MB로 제한됨 + + + + + Automatic + 자동 + + + + + Service Broker + Service Broker + + + + + Collation + 데이터 정렬 + + + + + Cursor + 커서 + + + + + Miscellaneous + 기타 + + + + + Recovery + 복구 + + + + + State + 상태 + + + + + ANSI NULL Default + ANSI NULL 기본값 + + + + + ANSI NULLS Enabled + ANSI NULLS 사용 + + + + + ANSI Padding Enabled + ANSI 패딩 설정 + + + + + ANSI Warnings Enabled + ANSI Warnings 사용 + + + + + Arithmetic Abort Enabled + 산술 연산 중단 설정 + + + + + Auto Close + 자동 닫기 + + + + + Auto Create Statistics + 통계 자동 작성 + + + + + Auto Shrink + 자동 축소 + + + + + Auto Update Statistics + 통계 자동 업데이트 + + + + + Auto Update Statistics Asynchronously + 통계를 비동기적으로 자동 업데이트 + + + + + Case Sensitive + 대/소문자 구분 + + + + + Close Cursor on Commit Enabled + 커밋 시 커서 닫기 설정 + + + + + Collation + 데이터 정렬 + + + + + Concatenate Null Yields Null + Null 연결 시 Null 생성 + + + + + Database Compatibility Level + 데이터베이스 호환성 수준 + + + + + Database State + 데이터베이스 상태 + + + + + Default Cursor + 기본 커서 + + + + + Full-Text Indexing Enabled + 전체 텍스트 인덱싱 설정 + + + + + Numeric Round-Abort + 숫자 반올림 시 중단 + + + + + Page Verify + 페이지 확인 + + + + + Quoted Identifiers Enabled + 따옴표 붙은 식별자 설정 + + + + + Database Read-Only + 데이터베이스 읽기 전용 + + + + + Recursive Triggers Enabled + 재귀적 트리거 설정 + + + + + Restrict Access + 액세스 제한 + + + + + Select Into/Bulk Copy + SELECT INTO/대량 복사 + + + + + Honor Broker Priority + Broker 우선 순위 인식 + + + + + Service Broker Identifier + Service Broker 식별자 + + + + + Broker Enabled + Broker 활성화 + + + + + Truncate Log on Checkpoint + 검사점에서 로그 자름 + + + + + Cross-database Ownership Chaining Enabled + 데이터베이스 간 소유권 체인 사용 + + + + + Trustworthy + 신뢰 + + + + + Date Correlation Optimization Enabled + 날짜 상관관계 최적화 설정 + + + + + Forced + 강제 + + + + + Simple + 단순 + + + + + ROWS Data + ROWS 데이터 + + + + + LOG + 로그 + + + + + FILESTREAM Data + FILESTREAM 데이터 + + + + + Not Applicable + 해당 사항 없음 + + + + + <default path> + <기본 경로> + + + + + Open Connections + 연결 열기 + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + 데이터베이스 속성을 변경하기 위해, SQL Server가 database_ 에  다른 연결을 모두 닫아야 합니다. 속성을 변경하고 다른 연결을 모두 닫으시겠습니까? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + 긴급 + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + 오프라인 + + + + + RECOVERING + 복구 중 + + + + + RECOVERY PENDING + 복구 보류 중 + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + VarDecimal 저장소 형식 사용 + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + 암호화 사용 + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + 배포 정책이 HASH인 경우 선행 해시 열 수는 선택 사항이지만, 선택할 경우 1개에서 16개 사이의 열로 지정해야 합니다. + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + 없음 + + + + + Partial + 부분 + + + + + FILESTREAM Files + FILESTREAM 파일 + + + + + No Applicable Filegroup + 해당 파일 그룹 없음 + + + + + The database {0} is not accessible. + {0} 데이터베이스에 액세스할 수 없습니다. + + + + + Query has no results to return + 쿼리 반환 결과 없음 + + + + + Result set has too many rows to be safely loaded + 결과 집합의 행 수가 너무 많아서 안전하게 불러들일 수 없습니다. + + + + Parameterization + 매개 변수화 + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + NORECOVERY 옵션을 사용하여 백업을 복원하는 동안 이 옵션을 지정할 수 없습니다. + + + + + Invalid path for database file: '{0}' + 데이터베이스 파일의 경로가 잘못되었습니다. '{0}' + + + + + Log + 로그 + + + + + Failed to create restore plan + 복원 계획을 만들지 못했습니다 + + + + + Restore database is not supported + 데이터베이스 복원은 지원되지 않습니다. + + + + + Restore Database + 데이터베이스 복원 + + + + + (Copy Only) + 복사 전용 + + + + + Component + 구성 요소 + + + + + Type + 형식 + + + + + Server + 서버 + + + + + Database + 데이터베이스 + + + + + Position + 위치 + + + + + First LSN + 첫 번째 LSN + + + + + Last LSN + 마지막 LSN + + + + + Checkpoint LSN + 검사점 LSN + + + + + Full LSN + 전체 LSN + + + + + Start Date + 시작 날짜 + + + + + Finish Date + 완료 날짜 + + + + + Size + 크기 + + + + + User Name + 사용자 이름 + + + + + Expiration + 만료 + + + + + Name + Name + + + + + The last backup taken ({0}) + 수행된 마지막 백업({0}) + + + + + Backup Database + 데이터베이스 백업 + + + + + In progress + 진행 중 + + + + + Completed + 완료됨 + + + + + scripting + 스크립팅 + + + + + Connection not found + 연결 없음 + + + + + Please provide a file path instead of directory path + 지정한 파일 이름은 디렉터리 이름이기도 합니다: {0} + + + + + The provided path is invalid + 백업 파일 위치를 확인할 수 없습니다: {0} + + + + + Cannot access the specified path on the server: {0} + 서버에서 지정된 경로에 액세스할 수 없습니다: {0} + + + + + No backupset selected to be restored + 복원하려는 백업 세트를 선택하지 않았습니다 + + + + + Never + 안 함 + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL 신축성 데이터베이스 + + + + + Path {0} is not a valid directory + 경로 [{0}]은(는) 올바른 디렉터리가 아닙니다. + + + + + For directory {0} a file with name {1} already exists + 디렉터리 {0}에 대한 파일{1} 이 이미 존재합니다. + + + + + Value {0} is too large to fit in column of type {1} + 값 {0}이 너무 커서 {1} 유형의 열에 들어갈 수 없습니다. + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.pt-BR.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.pt-BR.xlf new file mode 100644 index 0000000000..5a0f536707 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.pt-BR.xlf @@ -0,0 +1,2776 @@ + + + + + Connection parameters cannot be null + Parâmetros de Conexão não podem ser nulos + + + + + OwnerUri cannot be null or empty + OwnerUri não pode ser nulo ou vazio + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' não há uma conexão existente + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Valor inválido '{0}' para AuthenticationType. Os valores válidos são 'Integrada' e 'SqlLogin'. + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Valor inválido '{0}' para ApplicationIntent. Os valores válidos são 'ReadWrite' e 'Somente leitura'. + + . + Parameters: 0 - intent (string) + + + Connection canceled + Conexão cancelada + + + + + OwnerUri cannot be null or empty + OwnerUri não pode ser nulo ou vazio + + + + + Connection details object cannot be null + Objeto de detalhes de Conexão não pode ser nulo + + + + + ServerName cannot be null or empty + ServerName não pode ser nulo ou vazio + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} não pode ser nulo ou vazio quando estiver usando autenticação SqlLogin + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + A consulta já foi concluída, ela não pode ser cancelada + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Consulta cancelada com êxito, Falha ao descartar a consulta. Proprietário do URI não encontrado. + + + + + Query was canceled by user + Consulta foi cancelada pelo usuário + + + + + The batch has not completed, yet + O lote ainda não foi concluído. + + + + + Batch index cannot be less than 0 or greater than the number of batches + Índice de lote não pode ser menor que 0 ou maior que o número de lotes + + + + + Result set index cannot be less than 0 or greater than the number of result sets + Índice do conjunto de resultados não pode ser menor que 0 ou maior que o número do conjuntos de resultados + + + + + Maximum number of bytes to return must be greater than zero + Número máximo de bytes a serem retornados deve ser maior que zero + + + + + Maximum number of chars to return must be greater than zero + Número máximo de caracteres a serem retornados deve ser maior que zero + + + + + Maximum number of XML bytes to return must be greater than zero + Número máximo de bytes XML a serem retornados deve ser maior que zero + + + + + Access method cannot be write-only + Método de acesso não pode ser somente gravação + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper deve ser inicializado antes de executar operações + + + + + This FileStreamWrapper cannot be used for writing + Este FileStreamWrapper não pode ser usado para gravação + + + + + (1 row affected) + (1 linha afetada) + + + + + ({0} rows affected) + ({0} linhas afetadas) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Comandos concluídos com sucesso. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0}, Nível {1}, Estado {2}, Linha {3} {4} {5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Falha na consulta: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Nenhum nome de coluna) + + + + + The requested query does not exist + A consulta solicitada não existe. + + + + + This editor is not connected to a database + Este editor não está conectado a um banco de dados + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Uma consulta já está em andamento para esta sessão do editor. Favor cancelar esta consulta ou aguardar a sua conclusão + + + + + Sender for OnInfoMessage event must be a SqlConnection + Remetente do evento OnInfoMessage deve ser um SqlConnection + + + + + Result cannot be saved until query execution has completed + Resultado não pode ser salvo até que seja concluída a execução da consulta + + + + + Internal error occurred while starting save task + Ocorreu um erro interno ao iniciar tarefa de salvamento + + + + + A save request to the same path is in progress + Uma solicitação de salvamento para o mesmo caminho está em andamento + + + + + Failed to save {0}: {1} + Falha ao salvar {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Não é possível ler o subconjunto, a menos que os resultados tenham sido lidos do servidor + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Linha de início não pode ser menor que 0 ou maior que o número de linhas no conjunto de resultados + + + + + Row count must be a positive integer + Contagem de linhas deve ser um inteiro positivo + + + + + Could not retrieve column schema for result set + Não foi possível recuperar o esquema de colunas para o conjunto de resultados + + + + + Could not retrieve an execution plan from the result set + Não foi possível recuperar um plano de execução do conjunto de resultados + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + Esse recurso não é atualmente suportado no banco de dados de SQL Azure e Data Warehouse: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Ocorreu um erro inesperado durante a execução da inspeção da definição: + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + Nenhum resultado foi encontrado. + + + + + No database object was retrieved. + Nenhum objeto de banco de dados foi recuperado. + + + + + Please connect to a server. + Favor conectar-se a um servidor. + + + + + Operation timed out. + Tempo limite da operação esgotado. + + + + + This object type is currently not supported by this feature. + Este tipo de objeto não é suportado atualmente por esse recurso. + + + + + Position is outside of file line range + Posição está fora do intervalo de linhas do arquivo + + + + + Position is outside of column range for line {0} + A posição está fora do intervalo de colunas para linha {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Posição inicial ({0}, {1}) deve vir antes ou ser igual a posição final ({2}, {3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0}, Nível {1}, Estado {2}, Linha {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0}, Nível {1}, Estado {2}, Procedimento {3}, Linha {4} + + + + + Msg {0}, Level {1}, State {2} + Msg {0}, Nível {1}, Estado {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + Ocorreu um erro durante o processamento do lote. A mensagem de erro é: {0} + + + + + ({0} row(s) affected) + ({0} linhas afetadas) + + + + + The previous execution is not yet complete. + Execução anterior ainda não foi concluída. + + + + + A scripting error occurred. + Ocorreu um erro de script. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Sintaxe incorreta foi encontrada enquanto {0} estava sendo analisado. + + + + + A fatal error occurred. + Ocorreu um erro fatal. + + + + + Batch execution completed {0} times... + Execução concluída {0} vezes... + + + + + You cancelled the query. + Você cancelou a consulta. + + + + + An error occurred while the batch was being executed. + Ocorreu um erro enquanto o lote estava sendo executado. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + Ocorreu um erro enquanto o lote estava sendo executado, mas o erro foi ignorado. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + Comando {0} não é suportado. + + + + + The variable {0} could not be found. + A variável {0} não pôde ser encontrada. + + + + + SQL Execution error: {0} + Erro de execução de SQL: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + Execução do pacote do analisador de lotes: {0} encontrado... na linha {1}: {2} Descrição: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + Mensagem recebida do motor de execução do pacote do analisador de lotes: Mensagem: {0} Mensagem detalhada: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + Processando o conjunto de resultados no motor de execução do pacote do analisador de lotes: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + Execução do conjunto de resultados do motor de execução de pacotes do analisador de lotes terminada. + + + + + Canceling batch parser wrapper batch execution. + Cancelando execução do conjunto de resultados do motor de execução de pacotes do analisador de lotes. + + + + + Scripting warning. + Aviso de script. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Para obter mais informações sobre esse erro, consulte os tópicos de solução de problemas na documentação do produto. + + + + + File '{0}' recursively included. + Arquivo '{0}' incluído recursivamente. + + + + + Missing end comment mark '*/'. + Sem marca de comentário final ' * /'. + + + + + Unclosed quotation mark after the character string. + Aspas não fechadas depois da sequência de caracteres. + + + + + Incorrect syntax was encountered while parsing '{0}'. + Sintaxe incorreta foi encontrada enquanto {0} estava sendo analisado. + + + + + Variable {0} is not defined. + A variável {0} não está definida. + + + + + test + teste + + + + + Replacement of an empty string by an empty string. + Substituição de uma sequência vazia por uma cadeia de caracteres vazia. + + + + + Edit session does not exist. + Sessão de edição não existe. + + + + + Query has not completed execution + A consulta não completou a execução + + + + + Query did not generate exactly one result set + A consulta não gerou exatamente um conjunto de resultados + + + + + Failed to add new row to update cache + Falha ao adicionar uma nova linha ao cache de atualização + + + + + Given row ID is outside the range of rows in the edit cache + ID de linha de entrada fora da faixa de linhas no cache de edição + + + + + An update is already pending for this row and must be reverted first + Uma atualização está ainda pendente para esta linha e deve ser revertida antes + + + + + Given row ID does not have pending update + Não existem atualizações pendentes para o ID informado. + + + + + Table or view metadata could not be found + Tabela ou view de metadados não pode ser encontrada + + + + + Invalid format for binary column + Formato inválido para coluna binária + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Colunas Booleanas devem possuir o número 1 ou 0 ou a string true ou false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Um valor requerido para a célula está faltando + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + Uma exclusão está pendente para esta linha. Uma atualização desta célula não pode ser aplicada. + + + + + Column ID must be in the range of columns for the query + Um ID de coluna deve estar no intervalo de colunas para a consulta + + + + + Column cannot be edited + Coluna não pode ser editada + + + + + No key columns were found + Não foram encontradas colunas chave + + + + + An output filename must be provided + Um nome de arquivo de saída deve ser fornecido + + + + + Database object {0} cannot be used for editing. + O objecto de banco de dados {0} não pode ser usado para edição. + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + A URI especificada '{0}' não tem uma conexão padrão + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Uma tarefa de gravação está em progresso. Favor aguardar o térnino. + + + + + Decimal column is missing numeric precision or numeric scale + Coluna decimal não tem precisão numérica ou escala numérica + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + Não é possível adicionar linha ao buffer de resultados, o datareader não contém linhas + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + Os valores da coluna do tipo de dados TIME devem estar entre 00:00:00.0000000 e 23:59:59.9999999 + + + + + NULL is not allowed for this column + Nulo não é permitido para esta coluna. + + + + + Edit session already exists. + Sessão de edição já existe. + + + + + Edit session has not been initialized + Sessão de edição não foi inicializada + + + + + Edit session has already been initialized + Sessão de edição já foi inicializada + + + + + Edit session has already been initialized or is in the process of initializing + Sessão de edição já foi inicializada ou está em processo de inicialização + + + + + Query execution failed, see messages for details + A execução da consulta falhou, veja as mensagens para detalhes + + + + + Result limit cannot be negative + Limite de resultados não pode ser negativo + + + + + NULL + NULL + + + + + A object name must be provided + O nome do objeto deve ser fornecido. + + + + + Explicitly specifying server or database is not supported + O servidor ou banco de dados especificado não é suportado. + + + + + Table metadata does not have extended properties + Metadados da tabela não possuem propriedades extendidas + + + + + Table or view requested for edit could not be found + Tabela ou view requisitada para edição não foi encontrada + + + + + Error expanding: {0} + Erro expandindo: {0} + + + + + Error connecting to {0} + Erro conectando a {0} + + + + + Aggregates + Agregados + + + + + Server Roles + Funcões de Servidor + + + + + Application Roles + Funções de Aplicação + + + + + Assemblies + Assemblies + + + + + Assembly Files + Arquivos de Assemblies + + + + + Asymmetric Keys + Chaves Assimétricas + + + + + Asymmetric Keys + Chaves Assimétricas + + + + + Data Compression Options + Opções de Compressão de Dados + + + + + Certificates + Certificados + + + + + FileTables + Tabelas de Arquivos + + + + + Certificates + Certificados + + + + + Check Constraints + Verificação de Restrições + + + + + Columns + Colunas + + + + + Constraints + Restrições + + + + + Contracts + Contratos + + + + + Credentials + Credenciais + + + + + Error Messages + Mensagens de Erro + + + + + Server Role Membership + Adesão às Funções de Servidor + + + + + Database Options + Opções de Banco de Dados + + + + + Database Roles + Funções de Bancos de Dados + + + + + Role Memberships + Adesão às Funções + + + + + Database Triggers + Gatilhos de Bancos de Dados + + + + + + Default Constraints + Restrições Padrão + + + + + Defaults + Padrões + + + + + Sequences + Sequências + + + + + Endpoints + Pontos finais + + + + + Event Notifications + Notificações de Eventos + + + + + Server Event Notifications + Notificações de Eventos de Servidor + + + + + Extended Properties + Propriedades Extendidas + + + + + Filegroups + Grupos de Arquivos + + + + + Foreign Keys + Chaves Estrangeiras + + + + + Full-Text Catalogs + Catálogos Full-Text + + + + + Full-Text Indexes + Índices Full-Text + + + + + Functions + Funções + + + + + Indexes + Índices + + + + + Inline Functions + Funções em Linha + + + + + Keys + Chaves + + + + + Linked Servers + Servidores vinculados + + + + + Linked Server Logins + Logins de servidores vinculados + + + + + Logins + Logins + + + + + Master Key + Master key + + + + + Master Keys + Master Keys + + + + + Message Types + Tipos de Mensagens + + + + + Table-Valued Functions + Funções de Valor de Tabelas + + + + + Parameters + Parâmetros + + + + + Partition Functions + Funções de Partição + + + + + Partition Schemes + Esquemas de Partição + + + + + Permissions + Permissões + + + + + Primary Keys + Chaves Primárias + + + + + Programmability + Programabilidade + + + + + Queues + Filas + + + + + Remote Service Bindings + Ligações de Serviço Remoto + + + + + Returned Columns + Colunas Retornadas + + + + + Roles + Funções + + + + + Routes + Rotas + + + + + Rules + Regras + + + + + Schemas + Esquemas + + + + + Security + Segurança + + + + + Server Objects + Objetos de Servidor + + + + + Management + Gerenciamento + + + + + Triggers + Gatilhos + + + + + Service Broker + Service Broker + + + + + Services + Serviços + + + + + Signatures + Assinaturas + + + + + Log Files + Arquivos de Log + + + + + Statistics + Estatísticas + + + + + Storage + Armazenamento + + + + + Stored Procedures + Stored Procedures + + + + + Symmetric Keys + Chaves Simétricas + + + + + Synonyms + Sinônimos + + + + + Tables + Tabelas + + + + + Triggers + Gatilhos + + + + + Types + Tipos + + + + + Unique Keys + Chaves Únicas + + + + + User-Defined Data Types + Tipos de Dados Definidos pelo Usuário + + + + + User-Defined Types (CLR) + Tipos Definidos pelo Usuário (CLR) + + + + + Users + Usuários + + + + + Views + Visualizações + + + + + XML Indexes + Índices XML + + + + + XML Schema Collections + Coleções de Esquemas XML + + + + + User-Defined Table Types + Tipos de Tabelas Definidas pelo Usuário + + + + + Files + Arquivos + + + + + Missing Caption + Título Faltando + + + + + Broker Priorities + Prioridades do Agente + + + + + Cryptographic Providers + Provedores de Criptografia + + + + + Database Audit Specifications + Especificações de Auditoria de Banco de Dados + + + + + Database Encryption Keys + Chaves de Criptografia de Banco de Dados + + + + + Event Sessions + Sessões de Evento + + + + + Full Text Stoplists + Listas de Parada Full Text + + + + + Resource Pools + Pool de Recursos + + + + + Audits + Auditorias + + + + + Server Audit Specifications + Especificações de Auditoria de Servidor + + + + + Spatial Indexes + Índices Espaciais + + + + + Workload Groups + Grupos de Trabalho + + + + + SQL Files + Arquivos SQL + + + + + Server Functions + Funções de Servidor + + + + + SQL Type + Tipo SQL + + + + + Server Options + Opções de Servidor + + + + + Database Diagrams + Diagramas de Banco de Dados + + + + + System Tables + Tabelas do Sistema + + + + + Databases + Bancos de Dados + + + + + System Contracts + Contratos do Sistema + + + + + System Databases + Bancos de Dados do Sistema + + + + + System Message Types + Tipos de Mensagens do Sistema + + + + + System Queues + Filas do Sistema + + + + + System Services + Serviços do Sistema + + + + + System Stored Procedures + Stored Procedures do Sistema + + + + + System Views + Visualizações do Sistema + + + + + Data-tier Applications + Aplicações da Camada de Dados + + + + + Extended Stored Procedures + Stored Procedures Estendidas + + + + + Aggregate Functions + Funções Agregadas + + + + + Approximate Numerics + Numéricos Aproximados + + + + + Binary Strings + Cadeias de Caracteres Binárias + + + + + Character Strings + Cadeias de Caracteres + + + + + CLR Data Types + Tipos de Dados CLR + + + + + Configuration Functions + Funções de Configuração + + + + + Cursor Functions + Funções de Cursor + + + + + System Data Types + Tipos de Dados do Sistema + + + + + Date and Time + Data e Hora + + + + + Date and Time Functions + Funções de Data e Hora + + + + + Exact Numerics + Numéricos Exatos + + + + + System Functions + Funções do Sistema + + + + + Hierarchy Id Functions + Funções de ID de Hierarquia + + + + + Mathematical Functions + Funções Matemáticas + + + + + Metadata Functions + Funções de Metadados + + + + + Other Data Types + Outros tipos de Dados + + + + + Other Functions + Outras Funções + + + + + Rowset Functions + Funções de Conjuntos de Linhas + + + + + Security Functions + Funções de Segurança + + + + + Spatial Data Types + Tipos de Dados Espaciais + + + + + String Functions + Funções de Cadeias de Caracteres + + + + + System Statistical Functions + Funções Estatísticas do Sistema + + + + + Text and Image Functions + Funções de Texto e Imagem + + + + + Unicode Character Strings + Cadeias de Caracteres Unicode + + + + + Aggregate Functions + Funções Agregadas + + + + + Scalar-valued Functions + Funções de Valores Escalares + + + + + Table-valued Functions + Funções de Valores Baseadas em Tabelas + + + + + System Extended Stored Procedures + Stored Procedures do Sistema Estendidas + + + + + Built-in Types + Tipos Intrínsecos + + + + + Built-in Server Roles + Funções de Servidor Intrínsecas + + + + + User with Password + Usuário com Senha + + + + + Search Property List + Pesquisar Lista de Propriedades + + + + + Security Policies + Políticas de Segurança + + + + + Security Predicates + Predicados de Segurança + + + + + Server Role + Função de Servidor + + + + + Search Property Lists + Pesquisar Listas de Propriedades + + + + + Column Store Indexes + Índices de Colunas + + + + + Table Type Indexes + Índices de Tipos de Tabelas + + + + + Selective XML Indexes + Índices XML Seletivos + + + + + XML Namespaces + Namespaces XML + + + + + XML Typed Promoted Paths + Caminhos Promovidos de Tipos XML + + + + + T-SQL Typed Promoted Paths + Caminhos Promovidos de Tipos T-SQL + + + + + Database Scoped Credentials + Credenciais de Escopo de Banco de Dados + + + + + External Data Sources + Fontes de Dados Externas + + + + + External File Formats + Formatos de Arquivos Externos + + + + + External Resources + Recursos Externos + + + + + External Tables + Tabelas Externas + + + + + Always Encrypted Keys + Chaves Sempre Criptografadas + + + + + Column Master Keys + Chaves Mestras de Colunas + + + + + Column Encryption Keys + Chaves de Criptografia de Colunas + + + + + Server + Servidor + + + + + Error parsing ScriptingParams.ConnectionString property. + Erro ao analisar a propriedade ScriptingParams.ConnectionString. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + Diretório inválido especificado pela propriedade ScriptingParams.FilePath. + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Erro ao analisar a propriedade ScriptingListObjectsCompleteParams.ConnectionString. + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Nenhum padrão + + + + + Input + Entrada + + + + + Input/Output + Entrada/Saída + + + + + Input/ReadOnly + Entrada/SomenteLeitura + + + + + Input/Output/ReadOnly + Entrada/Saída/SomenteLeitura + + + + + Default + Padrão + + + + + null + nulo + + + + + not null + não nulo + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1} Computado, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1}Computado) + + + + + {0} (Column Set, {1}) + {0} (Conjunto de Colunas, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (Conjunto de Colunas, {1}{2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (Conjunto de Colunas, {1}, {2}, {3}) + + + + + Unique + Exclusivo + + + + + Non-Unique + Não Exclusivo + + + + + Clustered + Clusterizado + + + + + Non-Clustered + Não Clusterizado + + + + + History + Histórico + + + + + System-Versioned + Versionado pelo sistema + + + + + Unavailable + Indisponível + + + + + Current default filegroup: {0} + Grupo de arquivos padrão atual: {0} + + + + + New Filegroup for {0} + Novo Grupo de Arquivos para {0} + + + + + Default + Padrão + + + + + Files + Arquivos + + + + + Name + Nome + + + + + Read-Only + Somente Leitura + + + + + Autogrowth / Maxsize + Auto crescimento / Tamanho máximo + + + + + ... + ... + + + + + <default> + <padrão> + + + + + Filegroup + Grupo de Arquivos + + + + + Logical Name + Nome Lógico + + + + + File Type + Tipo de Arquivo + + + + + Initial Size (MB) + Tamanho Inicial (MB) + + + + + <new filegroup> + <novo grupo de arquivos> + + + + + Path + Caminho + + + + + File Name + Nome do Arquivo + + + + + <raw device> + <dispositivo bruto> + + + + + Bulk-logged + Logado em massa + + + + + Full + Completo + + + + + Simple + Simples + + + + + Select Database Owner + Selecionar o proprietário do banco de dados + + + + + None + Nenhum + + + + + By {0} MB, Limited to {1} MB + Por {0} MB, limitado a {1} MB + + + + + By {0} percent, Limited to {1} MB + Por {0}%, Limitado a {1} mb + + + + + By {0} MB, Unlimited + Por {0} MB, Ilimitado + + + + + By {0} percent, Unlimited + Por {0}%, Ilimitado + + + + + Unlimited + Ilimitado + + + + + Limited to {0} MB + Limitado a {0} MB + + + + + Automatic + Automático + + + + + Service Broker + Service Broker + + + + + Collation + Agrupamento + + + + + Cursor + Cursor + + + + + Miscellaneous + Diversos + + + + + Recovery + Recuperação + + + + + State + Estado + + + + + ANSI NULL Default + Padrão ANSI NULL + + + + + ANSI NULLS Enabled + ANSI NULLS Habilitado + + + + + ANSI Padding Enabled + Preenchimento ANSI habilitado + + + + + ANSI Warnings Enabled + ANSI Warnings Habilitados + + + + + Arithmetic Abort Enabled + Arithmetic Abortar habilitado + + + + + Auto Close + Fechamento automático + + + + + Auto Create Statistics + Criar Estatísticas Automaticamente + + + + + Auto Shrink + Reduzir Automaticamente + + + + + Auto Update Statistics + Estatísticas Atualizadas Automaticamente + + + + + Auto Update Statistics Asynchronously + Atualizar estatísticas automaticamente de forma assíncrona + + + + + Case Sensitive + Sensível à Caixa + + + + + Close Cursor on Commit Enabled + Fechar Cursor na Confirmação Habilitado + + + + + Collation + Agrupamento + + + + + Concatenate Null Yields Null + Concatenar Nulo Produz Nulo + + + + + Database Compatibility Level + Nível de Compatibilidade do Banco de Dados + + + + + Database State + Estado do Banco de Dados + + + + + Default Cursor + Cursor Padrão + + + + + Full-Text Indexing Enabled + Indexação Full-Text Habilitada + + + + + Numeric Round-Abort + Anular arredondamento numérico. + + + + + Page Verify + Verificação de Página + + + + + Quoted Identifiers Enabled + Identificadores Entre Aspas Habilitados + + + + + Database Read-Only + Banco de Dados Somente Leitura + + + + + Recursive Triggers Enabled + Gatilhos Recursivos Habilitados + + + + + Restrict Access + Acesso Restrito + + + + + Select Into/Bulk Copy + Selecionar Cópia Into/Em Massa + + + + + Honor Broker Priority + Respeitar a Prioridade do Broker + + + + + Service Broker Identifier + Identificador de agente de serviço + + + + + Broker Enabled + Agente habilitado + + + + + Truncate Log on Checkpoint + Truncar o Log no Ponto de Verificação + + + + + Cross-database Ownership Chaining Enabled + Encadeamento de Propriedades de Bancos de Dados Habilitado + + + + + Trustworthy + Confiável + + + + + Date Correlation Optimization Enabled + Otimizaçao da Correlação de Data Enabledprototype_db_prop_parameterization = Parametrização + + + + + Forced + Forçado + + + + + Simple + Simples + + + + + ROWS Data + Dados ROWS + + + + + LOG + LOG + + + + + FILESTREAM Data + Dados FILESTREAM + + + + + Not Applicable + Não aplicável + + + + + <default path> + <caminho padrão> + + + + + Open Connections + Conexões Abertas + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Para modificar as propriedades do banco de dados, o SQL Server deve fechar todas as outras conexões ao banco de dados_ Tem certeza que você quer modificar as propriedades e fechar todas as outras conexões? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGÊNCIA + + + + + INACCESSIBLE + INACESSÍVEL + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFF-LINE + + + + + RECOVERING + RECUPERANDO + + + + + RECOVERY PENDING + RECUPERAÇÃO PENDENTE + + + + + RESTORING + RESTAURANDO + + + + + SHUTDOWN + DESLIGAMENTO + + + + + STANDBY + MODO DE ESPERA + + + + + SUSPECT + SUSPEITO + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USUÁRIO + + + + + RESTRICTED_USER + USUÁRIO_RESTRITO + + + + + SINGLE_USER + MONO_USUÁRIO + + + + + CHECKSUM + SOMA DE VERIFICAÇÃO + + + + + NONE + NENHUM + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + Formato de Armazenamento VarDecimal Habilitado + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Criptografia Habilitada + + + + + OFF + DESLIGADO + + + + + ON + LIGADO + + + + + PRIMARY + PRIMÁRIO + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Para a política de distribuição de HASH, o número de colunas hash principais é opcional, mas deve ser de 1 a 16 colunas + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Nenhum + + + + + Partial + Parcial + + + + + FILESTREAM Files + Arquivos FILESTREAM + + + + + No Applicable Filegroup + Nenhum grupo de arquivos aplicável + + + + + The database {0} is not accessible. + O banco de dados {0} não está acessível. + + + + + Query has no results to return + A consulta não tem resultado para retornar + + + + + Result set has too many rows to be safely loaded + Conjunto de resultados tem muitas linhas para ser carregado com segurança + + + + Parameterization + Parametrização + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + Não é permitido especificar essa opção ao restaurar um backup com a opção NORECOVERY. + + + + + Invalid path for database file: '{0}' + Caminho inválido para o arquivo de banco de dados: '{0}' + + + + + Log + Log + + + + + Failed to create restore plan + Falha ao criar o plano de restauração + + + + + Restore database is not supported + Restauração de banco de dados não é suportado + + + + + Restore Database + Restaurar o banco de dados + + + + + (Copy Only) + (Apenas cópia) + + + + + Component + Componente + + + + + Type + Tipo + + + + + Server + Servidor + + + + + Database + Banco de dados + + + + + Position + Posição + + + + + First LSN + Primeiro LSN + + + + + Last LSN + Último LSN + + + + + Checkpoint LSN + Checkpoint LSN + + + + + Full LSN + LSN completo + + + + + Start Date + Data de Início + + + + + Finish Date + Data de Término + + + + + Size + Tamanho + + + + + User Name + Nome do usuário + + + + + Expiration + Expiração + + + + + Name + Nome + + + + + The last backup taken ({0}) + O último backup feito ({0}) + + + + + Backup Database + Backup do Banco de Dados + + + + + In progress + Em andamento + + + + + Completed + Concluído + + + + + scripting + Gerando script + + + + + Connection not found + Conexão não encontrada + + + + + Please provide a file path instead of directory path + O nome do arquivo especificado também é um nome de diretório: {0} + + + + + The provided path is invalid + Não foi possível verificar a existência do local do arquivo de backup: {0} + + + + + Cannot access the specified path on the server: {0} + Não foi possível acessar o diretório especificado no servidor: {0} + + + + + No backupset selected to be restored + Nenhum conjunto de backup selecionado para ser restaurado + + + + + Never + Nunca + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + Caminho {0} não é um diretório válido + + + + + For directory {0} a file with name {1} already exists + Já existe um arquivo com nome {1} para o diretório {0} + + + + + Value {0} is too large to fit in column of type {1} + Valor {0} é muito grande para caber em uma coluna do tipo {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ru.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ru.xlf new file mode 100644 index 0000000000..b9c3143492 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.ru.xlf @@ -0,0 +1,2769 @@ + + + + + Connection parameters cannot be null + Параметры подключения должны быть указаны, значение не может быть неопределенным (null) + + + + + OwnerUri cannot be null or empty + OwnerUri не может быть неопределенным или пустым + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri «{0}» не имеет существующего подключения + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + Значение «{0}» недопустимо для AuthenticationType. Ожидается значение «Integrated» или «SqlLogin». + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + Значение «{0}» недопустимо для ApplicationIntent. Ожидается значение «ReadWrite» или «ReadOnly». + + . + Parameters: 0 - intent (string) + + + Connection canceled + Подключение к серверу отменено. + + + + + OwnerUri cannot be null or empty + OwnerUri не может быть неопределенным или пустым + + + + + Connection details object cannot be null + Параметры подключения не могут быть неопределенными + + + + + ServerName cannot be null or empty + Имя сервера не может быть неопределенным или пустым + + + + + {0} cannot be null or empty when using SqlLogin authentication + {0} не может быть неопределенным или пустым при использовании проверки подлинности SqlLogin + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + Запрос уже был выполнен, отмена невозможна + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + Запрос успешно отменен, но удалить запрос не удалось. Владелец URI не найден. + + + + + Query was canceled by user + Выполнение запроса отменено пользователем + + + + + The batch has not completed, yet + Пакет еще не завершен + + + + + Batch index cannot be less than 0 or greater than the number of batches + Индекс пакета не может быть меньше нуля или больше числа пакетов + + + + + Result set index cannot be less than 0 or greater than the number of result sets + Индекс не может быть меньше нуля или больше количества записей в наборе + + + + + Maximum number of bytes to return must be greater than zero + Максимальное количество возвращаемых байтов должно быть больше нуля + + + + + Maximum number of chars to return must be greater than zero + Максимальное количество возвращаемых символов должно быть больше нуля + + + + + Maximum number of XML bytes to return must be greater than zero + Максимальное количество возвращаемых из XML байтов должно быть больше нуля + + + + + Access method cannot be write-only + Метод доступа не может быть только для записи. + + + + + FileStreamWrapper must be initialized before performing operations + FileStreamWrapper должен быть инициализирован перед выполнением операций + + + + + This FileStreamWrapper cannot be used for writing + Этот экземпляр FileStreamWrapper не может быть использован для записи + + + + + (1 row affected) + (одна строка затронута) + + + + + ({0} rows affected) + ({0} строк затронуто) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + Выполнение команд успешно завершено. + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Сообщение {0}, Уровень {1}, Состояние {2}, Строка {3}{4}{5} + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + Не удалось выполнить запрос: {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (Нет имени столбца) + + + + + The requested query does not exist + Указанный запрос не найден + + + + + This editor is not connected to a database + Этот редактор не подключен к базе данных + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + Запрос уже выполняется для данного сеанса редактора. Отмените запрос или дождитесь завершения его выполнения. + + + + + Sender for OnInfoMessage event must be a SqlConnection + В качестве отправителя (sender) для события OnInfoMessage ожидается экземпляр SqlConnection + + + + + Result cannot be saved until query execution has completed + Результат не может быть сохранен до завершения выполнения запроса + + + + + Internal error occurred while starting save task + При запуске задачи сохранения произошла внутренняя ошибка + + + + + A save request to the same path is in progress + По указанному пути уже выполняется сохранение результатов + + + + + Failed to save {0}: {1} + Не удалось сохранить {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + Невозможно прочитать подмножество, поскольку результаты еще не были получены с сервера + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + Индекс начальной строки не может быть меньше нуля или больше количества строк, находящихся в результирующем наборе + + + + + Row count must be a positive integer + Число строк должно быть положительным целым числом + + + + + Could not retrieve column schema for result set + Не удалось получить столбец схемы для результирующего набора + + + + + Could not retrieve an execution plan from the result set + Не удалось получить план выполнения из результирующего набора + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + В настоящее время эта функция не поддерживается Azure SQL DB и Data Warehouse: {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + Произошла непредвиденная ошибка во время выполнения Peek Definition: {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + Результаты не найдены. + + + + + No database object was retrieved. + Объект базы данных не был получен. + + + + + Please connect to a server. + Подключитесь к серверу. + + + + + Operation timed out. + Истекло время ожидания операции. + + + + + This object type is currently not supported by this feature. + В настоящее время этот тип объекта не поддерживается этим средством. + + + + + Position is outside of file line range + Позиция выходит за пределы диапазона строк файла + + + + + Position is outside of column range for line {0} + Позиция выходит за пределы диапазона столбцов строки {0} + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + Начальная позиция ({0}, {1}) должна быть меньше либо равна конечной ({2}, {3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Сообщение {0}, уровень {1}, состояние {2}, строка {3} + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Сообщение {0}, уровень {1}, состояние {2}, процедура {3}, строка {4} + + + + + Msg {0}, Level {1}, State {2} + Сообщение {0}, уровень {1}, состояние {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + При обработке пакета произошла ошибка: {0} + + + + + ({0} row(s) affected) + ({0} строк затронуто) + + + + + The previous execution is not yet complete. + Предыдущее выполнение еще не завершено. + + + + + A scripting error occurred. + Произошла ошибка сценария. + + + + + Incorrect syntax was encountered while {0} was being parsed. + Обнаружен неправильный синтаксис при обработке {0}. + + + + + A fatal error occurred. + Произошла неустранимая ошибка. + + + + + Batch execution completed {0} times... + Выполнение завершено такое количество раз: {0}... + + + + + You cancelled the query. + Пользователь отменил запрос. + + + + + An error occurred while the batch was being executed. + При выполнении пакета произошла ошибка. + + + + + An error occurred while the batch was being executed, but the error has been ignored. + В процессе выполнения пакета произошла ошибка, но она была проигнорирована. + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + Команда {0} не поддерживается. + + + + + The variable {0} could not be found. + Переменная {0} не найдена. + + + + + SQL Execution error: {0} + Ошибка выполнения SQL: {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + BatchParserWrapper: {0} найдено; строка {1}: {2}; описание: {3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + BatchParserWrapper получено сообщение: {0}. Детали: {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + BatchParserWrapper выполнение пакетной обработки ResultSet. DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + BatchParserWrapper: обработка завершена. + + + + + Canceling batch parser wrapper batch execution. + BatchParserWrapper: выполнение пакета отменено. + + + + + Scripting warning. + Сценарий содержит предупреждения. + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + Для получения дополнительной информации об этой ошибке, обратитесь к разделам по устранению неполадок в документации по продукту. + + + + + File '{0}' recursively included. + Обнаружена рекурсивная ссылка на файл «{0}». + + + + + Missing end comment mark '*/'. + Отсутствует обозначение конца комментария - «*/». + + + + + Unclosed quotation mark after the character string. + Незакрытые кавычки в конце символьной строки. + + + + + Incorrect syntax was encountered while parsing '{0}'. + При разборе «{0}» обнаружен неправильный синтаксис. + + + + + Variable {0} is not defined. + Переменная {0} не определена. + + + + + test + тест + + + + + Replacement of an empty string by an empty string. + Замена пустой строки на пустую строку. + + + + + Edit session does not exist. + Сеанс не найден. + + + + + Query has not completed execution + Выполнение запроса не завершено + + + + + Query did not generate exactly one result set + Запрос должен содержать только один набор результатов + + + + + Failed to add new row to update cache + Не удалось добавить новую строку в кэш обновлений + + + + + Given row ID is outside the range of rows in the edit cache + Указанный идентификатор строки находится за пределами диапазона строк в кэше редактирования + + + + + An update is already pending for this row and must be reverted first + Обновление уже отправлено для этой строки и должно быть отменено первым + + + + + Given row ID does not have pending update + Для указанной строки нет обновлений в очереди + + + + + Table or view metadata could not be found + Не удалось найти метаданные таблицы или представления + + + + + Invalid format for binary column + Недопустимый формат данных для двоичного столбца + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Логические столбцы должны содержать число 1 или 0, либо строку true или false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + Недопустимое значение ячейки + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + Обновление ячейки не может быть применено, поскольку для данной строки ожидается удаление. + + + + + Column ID must be in the range of columns for the query + Идентификатор столбца должен находиться в диапазоне столбцов запроса + + + + + Column cannot be edited + Столбец не может быть изменен + + + + + No key columns were found + Ключевые поля не найдены + + + + + An output filename must be provided + Должно быть указано имя выходного файла + + + + + Database object {0} cannot be used for editing. + Объект базы данных {0} не может использоваться для редактирования. + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + Указанный URI '{0}' не имеет соединения по умолчанию + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + Выполняется фиксация. Пожалуйста, дождитесь завершения. + + + + + Decimal column is missing numeric precision or numeric scale + В десятичном столбце отсутствует числовая точность или масштаб + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + Невозможно добавить строку в файл буфера, поток не содержит строк + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + Значение столбца TIME должно находиться в диапазоне между 00:00:00.0000000 и 23:59:59.9999999 + + + + + NULL is not allowed for this column + Значение NULL недопустимо в этом столбце. + + + + + Edit session already exists. + Сеанс редактирования уже существует. + + + + + Edit session has not been initialized + Сеанс редактирования не был инициализирован. + + + + + Edit session has already been initialized + Сеанс редактирования уже был инициализирован. + + + + + Edit session has already been initialized or is in the process of initializing + Сеанс редактирования уже был инициализирован или находится в процессе инициализации + + + + + Query execution failed, see messages for details + Не удалось выполнить запрос, см. сообщения для получения подробностей + + + + + Result limit cannot be negative + Значение, определяющее ограничение числа записей, не может быть отрицательным + + + + + NULL + NULL + + + + + A object name must be provided + Должно быть указано имя объекта + + + + + Explicitly specifying server or database is not supported + Явное указание сервера или базы данных не поддерживается + + + + + Table metadata does not have extended properties + Метаданные таблицы не имеют расширенных свойств + + + + + Table or view requested for edit could not be found + Запрошенная таблица или представление не найдены. + + + + + Error expanding: {0} + Ошибка при расширении: {0} + + + + + Error connecting to {0} + Ошибка при подключении к {0} + + + + + Aggregates + Статистические выражения + + + + + Server Roles + Роли сервера + + + + + Application Roles + Роли приложения + + + + + Assemblies + Сборки + + + + + Assembly Files + Файлы сборки + + + + + Asymmetric Keys + Асимметричные ключи + + + + + Asymmetric Keys + Асимметричные ключи + + + + + Data Compression Options + Параметры сжатия данных + + + + + Certificates + Сертификаты + + + + + FileTables + Объекты FileTable + + + + + Certificates + Сертификаты + + + + + Check Constraints + Проверочные ограничения + + + + + Columns + Столбцы + + + + + Constraints + Ограничения + + + + + Contracts + Контракты + + + + + Credentials + Учетные данные + + + + + Error Messages + Сообщения об ошибках + + + + + Server Role Membership + Участие в роли сервера + + + + + Database Options + Параметры базы данных + + + + + Database Roles + Роли базы данных + + + + + Role Memberships + Членства в роли + + + + + Database Triggers + Триггеры базы данных + + + + + Default Constraints + Ограничения по умолчанию + + + + + Defaults + Значения по умолчанию + + + + + Sequences + Последовательности + + + + + Endpoints + Конечные точки + + + + + Event Notifications + Уведомления о событиях + + + + + Server Event Notifications + Уведомления о событиях сервера + + + + + Extended Properties + Расширенные свойства + + + + + Filegroups + Файловые группы + + + + + Foreign Keys + Внешние ключи + + + + + Full-Text Catalogs + Полнотекстовые каталоги + + + + + Full-Text Indexes + Полнотекстовые индексы + + + + + Functions + Функции + + + + + Indexes + Индексы + + + + + Inline Functions + Встроенная функции + + + + + Keys + Ключи + + + + + Linked Servers + Связанные серверы + + + + + Linked Server Logins + Имена входа на связанный сервер + + + + + Logins + Имена входа + + + + + Master Key + Главный ключ + + + + + Master Keys + Главные ключи + + + + + Message Types + Типы сообщений + + + + + Table-Valued Functions + Функция с табличным значением + + + + + Parameters + Параметры + + + + + Partition Functions + Функции секционирования + + + + + Partition Schemes + Схемы секционирования + + + + + Permissions + Разрешения + + + + + Primary Keys + Первичные ключи + + + + + Programmability + Программируемость + + + + + Queues + Списки ожидания + + + + + Remote Service Bindings + Привязки удаленных служб + + + + + Returned Columns + Возвращенные столбцы + + + + + Roles + Роли + + + + + Routes + Маршруты + + + + + Rules + Правила + + + + + Schemas + Схемы + + + + + Security + Безопасность + + + + + Server Objects + Объекты сервера + + + + + Management + Управление + + + + + Triggers + Триггеры + + + + + Service Broker + Компонент Service Broker + + + + + Services + Службы + + + + + Signatures + Сигнатуры + + + + + Log Files + Файлы журнала + + + + + Statistics + Статистика + + + + + Storage + Хранилище + + + + + Stored Procedures + Хранимые процедуры + + + + + Symmetric Keys + Симметричные ключи + + + + + Synonyms + Синонимы + + + + + Tables + Таблицы + + + + + Triggers + Триггеры + + + + + Types + Типы + + + + + Unique Keys + Уникальные ключи + + + + + User-Defined Data Types + Определяемые пользователем типы данных + + + + + User-Defined Types (CLR) + Определяемые пользователем типы (CLR) + + + + + Users + Пользователи + + + + + Views + Представления + + + + + XML Indexes + XML-индексы + + + + + XML Schema Collections + Коллекция схем XML + + + + + User-Defined Table Types + Определяемые пользователем типы таблиц + + + + + Files + Файлы + + + + + Missing Caption + Отсутствует заголовок + + + + + Broker Priorities + Приоритеты брокера + + + + + Cryptographic Providers + Поставщики служб шифрования + + + + + Database Audit Specifications + Спецификации аудита базы данных + + + + + Database Encryption Keys + Ключи шифрования базы данных + + + + + Event Sessions + Сеансы событий + + + + + Full Text Stoplists + Полнотекстовые списки стоп-слов + + + + + Resource Pools + Пулы ресурсов + + + + + Audits + Аудит + + + + + Server Audit Specifications + Спецификации аудита сервера + + + + + Spatial Indexes + Пространственные индексы + + + + + Workload Groups + Группы рабочей нагрузки + + + + + SQL Files + Файлы SQL + + + + + Server Functions + Функции сервера + + + + + SQL Type + Тип SQL + + + + + Server Options + Параметры сервера + + + + + Database Diagrams + Диаграммы базы данных + + + + + System Tables + Системные таблицы + + + + + Databases + Базы данных + + + + + System Contracts + Системные контракты + + + + + System Databases + Системные базы данных + + + + + System Message Types + Системные типы сообщений + + + + + System Queues + Системные очереди + + + + + System Services + Системные службы + + + + + System Stored Procedures + Системные хранимые процедуры + + + + + System Views + Системные представления + + + + + Data-tier Applications + Приложения уровня данных + + + + + Extended Stored Procedures + Расширенные хранимые процедуры + + + + + Aggregate Functions + Агрегатные функции + + + + + Approximate Numerics + Приблизительные числовые значения + + + + + Binary Strings + Двоичные строки + + + + + Character Strings + Символьные строки + + + + + CLR Data Types + Типы данных CLR + + + + + Configuration Functions + Функции конфигурации + + + + + Cursor Functions + Функции работы с курсорами + + + + + System Data Types + Системные типы данных + + + + + Date and Time + Дата и время + + + + + Date and Time Functions + Функции даты и времени + + + + + Exact Numerics + Точные числовые значения + + + + + System Functions + Системные функции + + + + + Hierarchy Id Functions + Функции идентификаторов иерархии + + + + + Mathematical Functions + Математические функции + + + + + Metadata Functions + Функции метаданных + + + + + Other Data Types + Другие типы данных + + + + + Other Functions + Другие функции + + + + + Rowset Functions + Функции набора строк + + + + + Security Functions + Функции безопасности + + + + + Spatial Data Types + Пространственные типы данных + + + + + String Functions + Строковые функции + + + + + System Statistical Functions + Системные статистические функции + + + + + Text and Image Functions + Функции для работы с изображениями и текстом + + + + + Unicode Character Strings + Строки символов в Юникоде + + + + + Aggregate Functions + Агрегатные функции + + + + + Scalar-valued Functions + Скалярные функции + + + + + Table-valued Functions + Функции с табличным значением + + + + + System Extended Stored Procedures + Системные расширенные хранимые процедуры + + + + + Built-in Types + Встроенные типы + + + + + Built-in Server Roles + Встроенные роли сервера + + + + + User with Password + Пользователь с паролем + + + + + Search Property List + Список свойств поиска + + + + + Security Policies + Политики безопасности + + + + + Security Predicates + Предикаты безопасности + + + + + Server Role + Роль сервера + + + + + Search Property Lists + Списки свойств поиска + + + + + Column Store Indexes + Индексы хранилища столбцов + + + + + Table Type Indexes + Индексы типов таблиц + + + + + Selective XML Indexes + Селективные XML-индексы + + + + + XML Namespaces + Пространства имен XML + + + + + XML Typed Promoted Paths + Типизированные повышенные пути XML + + + + + T-SQL Typed Promoted Paths + Типизированные повышенные пути T-SQL + + + + + Database Scoped Credentials + Учетные данные для базы данных + + + + + External Data Sources + Внешние источники данных + + + + + External File Formats + Внешние форматы файлов + + + + + External Resources + Внешние ресурсы + + + + + External Tables + Внешние таблицы + + + + + Always Encrypted Keys + Ключи Always Encrypted + + + + + Column Master Keys + Главные ключи столбца + + + + + Column Encryption Keys + Ключи шифрования столбца + + + + + Server + Сервер + + + + + Error parsing ScriptingParams.ConnectionString property. + Ошибка при анализе свойства ScriptingParams.ConnectionString. + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + Недопустимый каталог указан в свойстве ScriptingParams.FilePath. + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + Ошибка при анализе свойства ScriptingListObjectsCompleteParams.ConnectionString. + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + Нет значения по умолчанию + + + + + Input + Входной + + + + + Input/Output + Входной/выходной + + + + + Input/ReadOnly + Входной/только для чтения + + + + + Input/Output/ReadOnly + Входной/выходной/только для чтения + + + + + Default + Значение по умолчанию + + + + + null + null + + + + + not null + not null + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} (вычислено {1}, {2}, {3}) + + + + + {0} ({1}Computed) + {0} (вычислено {1}) + + + + + {0} (Column Set, {1}) + {0} (набор столбцов, {1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (набор столбцов, {1}{2}, {3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (набор столбцов, {1}, {2}, {3}) + + + + + Unique + UNIQUE + + + + + Non-Unique + Неуникальный + + + + + Clustered + Кластеризованный + + + + + Non-Clustered + Некластеризованный + + + + + History + Журнал + + + + + System-Versioned + Системно-версионный + + + + + Unavailable + Недоступно + + + + + Current default filegroup: {0} + Текущая файловая группа по умолчанию: {0} + + + + + New Filegroup for {0} + Создание файловой группы для {0} + + + + + Default + Значение по умолчанию + + + + + Files + Файлы + + + + + Name + Имя + + + + + Read-Only + Только для чтения + + + + + Autogrowth / Maxsize + Автоувеличение/максимальный размер + + + + + ... + ... + + + + + <default> + <по умолчанию> + + + + + Filegroup + Группа файлов + + + + + Logical Name + Логическое имя + + + + + File Type + Тип файла + + + + + Initial Size (MB) + Начальный размер (МБ) + + + + + <new filegroup> + <создать файловую группу> + + + + + Path + Путь + + + + + File Name + Имя файла + + + + + <raw device> + <неформатированный носитель> + + + + + Bulk-logged + С неполным протоколированием + + + + + Full + Полная + + + + + Simple + Простая + + + + + Select Database Owner + Выбор владельца базы данных + + + + + None + Нет + + + + + By {0} MB, Limited to {1} MB + С шагом по {0} МБ до {1} МБ + + + + + By {0} percent, Limited to {1} MB + С шагом по {0}% до {1} МБ + + + + + By {0} MB, Unlimited + С шагом по {0} МБ, без ограничений + + + + + By {0} percent, Unlimited + С шагом по {0} %, без ограничений + + + + + Unlimited + Без ограничений + + + + + Limited to {0} MB + Ограничено {0} МБ + + + + + Automatic + Автоматически + + + + + Service Broker + Service Broker + + + + + Collation + Параметры сортировки + + + + + Cursor + Курсор + + + + + Miscellaneous + Прочее + + + + + Recovery + Восстановление + + + + + State + Состояние + + + + + ANSI NULL Default + По умолчанию ANSI NULL + + + + + ANSI NULLS Enabled + Значения ANSI NULLS включены + + + + + ANSI Padding Enabled + Включено заполнение ANSI + + + + + ANSI Warnings Enabled + Включены предупреждения ANSI + + + + + Arithmetic Abort Enabled + Включено прерывание при делении на ноль + + + + + Auto Close + Auto Close + + + + + Auto Create Statistics + Автоматическое создание статистики + + + + + Auto Shrink + Автоматическое сжатие + + + + + Auto Update Statistics + Автоматическое обновление статистики + + + + + Auto Update Statistics Asynchronously + Асинхронное автообновление статистики + + + + + Case Sensitive + Case Sensitive + + + + + Close Cursor on Commit Enabled + Закрывать курсор при разрешении фиксации + + + + + Collation + Параметры сортировки + + + + + Concatenate Null Yields Null + Объединение со значением NULL дает NULL + + + + + Database Compatibility Level + Уровень совместимости базы данных + + + + + Database State + Состояние базы данных + + + + + Default Cursor + Курсор по умолчанию + + + + + Full-Text Indexing Enabled + Полнотекстовое индексирование включено + + + + + Numeric Round-Abort + Автоокругление чисел + + + + + Page Verify + Проверка страниц + + + + + Quoted Identifiers Enabled + Включены заключенные в кавычки идентификаторы + + + + + Database Read-Only + База данных только для чтения + + + + + Recursive Triggers Enabled + Включены рекурсивные триггеры + + + + + Restrict Access + Ограничение доступа + + + + + Select Into/Bulk Copy + Выбор/Массовое копирование + + + + + Honor Broker Priority + Учитывать приоритет компонента Honor Broker + + + + + Service Broker Identifier + Идентификатор компонента Service Broker + + + + + Broker Enabled + Включен компонент Broker + + + + + Truncate Log on Checkpoint + Усечение журнала на контрольной точке + + + + + Cross-database Ownership Chaining Enabled + Межбазовые цепочки владения включены + + + + + Trustworthy + Заслуживает доверия + + + + + Date Correlation Optimization Enabled + Date Correlation Optimization Enabledprototype_db_prop_parameterization = Parameterization + + + + + Forced + Принудительное + + + + + Simple + Простая + + + + + ROWS Data + Данные СТРОК + + + + + LOG + ЖУРНАЛ + + + + + FILESTREAM Data + Данные FILESTREAM + + + + + Not Applicable + Неприменимо + + + + + <default path> + <default path> + + + + + Open Connections + Открытые соединения + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + Чтобы изменить свойства базы данных, SQL Server должен закрыть все остальные соединения с этой базой данных. Изменить свойства и закрыть остальные соединения? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + Нет + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + Включен формат хранения VarDecimal + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + Шифрование включено + + + + + OFF + ОТКЛ. + + + + + ON + ВКЛ. + + + + + PRIMARY + ПЕРВИЧНЫЙ + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + Для политики распространения HASH количество начальных хэш-столбцов указывать не обязательно. Оно может составлять от 1 до 16 столбцов + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + Нет + + + + + Partial + Частично + + + + + FILESTREAM Files + Файлы FILESTREAM + + + + + No Applicable Filegroup + Применимая файловая группа отсутствует + + + + + The database {0} is not accessible. + База данных {0} недоступна. + + + + + Query has no results to return + запрос не имеет результатов + + + + + Result set has too many rows to be safely loaded + Pезультатов слишком много строк для безопасной загрузки + + + + Parameterization + Параметризация + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + Не разрешается указывать этот параметр при восстановлении резервной копии с параметром NORECOVERY. + + + + + Invalid path for database file: '{0}' + Недопустимый путь к файлу базы данных: {0}"""" + + + + + Log + Журнал + + + + + Failed to create restore plan + Не удалось создать план восстановления + + + + + Restore database is not supported + Восстановление базы данных не поддерживается + + + + + Restore Database + Восстановление базы данных + + + + + (Copy Only) + (Копировать только) + + + + + Component + Тип копии + + + + + Type + Тип + + + + + Server + Сервер + + + + + Database + База данных + + + + + Position + Положение + + + + + First LSN + Первый номер LSN + + + + + Last LSN + Последний номер LSN + + + + + Checkpoint LSN + Номер LSN для контрольной точки + + + + + Full LSN + Полный номер LSN + + + + + Start Date + Дата начала + + + + + Finish Date + Дата завершения + + + + + Size + Размер + + + + + User Name + Имя пользователя + + + + + Expiration + Истечение срока + + + + + Name + Имя + + + + + The last backup taken ({0}) + Последняя созданная резервная копия ({0}) + + + + + Backup Database + Создание резервной копии базы данных + + + + + In progress + Выполняется + + + + + Completed + Завершен + + + + + scripting + Скрипты + + + + + Connection not found + Соединение не найдено + + + + + Please provide a file path instead of directory path + Указанное имя файла является также именем каталога: {0} + + + + + The provided path is invalid + Невозможно проверить существование расположения файла резервной копии: {0} + + + + + Cannot access the specified path on the server: {0} + Указанный путь на сервере недоступен: {0} + + + + + No backupset selected to be restored + Для восстановления не выбран резервный набор данных + + + + + Never + Никогда + + + + + Azure SQL DB + + + + + Azure SQL Data Warehouse + + + + + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + + + + + For directory {0} a file with name {1} already exists + + + + + Value {0} is too large to fit in column of type {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hans.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hans.xlf new file mode 100644 index 0000000000..81a698a4a0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hans.xlf @@ -0,0 +1,2775 @@ + + + + + Connection parameters cannot be null + 连接参数不能为 null + + + + + OwnerUri cannot be null or empty + OwnerUri 不能为 null 或为空 + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' 没有已有的连接 + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + AuthenticationType 值"{0}" 无效。 有效值为 'Integrated' 和 'SqlLogin'。 + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + '{0}' 为无效的ApplicationIntent值。 有效值为 'ReadWrite' 和 'ReadOnly'。 + + . + Parameters: 0 - intent (string) + + + Connection canceled + 连接已取消 + + + + + OwnerUri cannot be null or empty + OwnerUri 不能为 null 或为空 + + + + + Connection details object cannot be null + 连接详细信息的对象不能为 null + + + + + ServerName cannot be null or empty + ServerName 不能是 null 或是空白 + + + + + {0} cannot be null or empty when using SqlLogin authentication + 使用 SqlLogin 身份验证时,{0} 不可是 null 或是空 + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + 查询已完成,无法取消 + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + 查询成功取消,无法处理查询。找不到 URI 的所有者。 + + + + + Query was canceled by user + 查询已被用户取消 + + + + + The batch has not completed, yet + 该批处理尚未完成 + + + + + Batch index cannot be less than 0 or greater than the number of batches + 批量索引不能小于 0 或大于批量的总数 + + + + + Result set index cannot be less than 0 or greater than the number of result sets + 结果集索引不能小于 0 或大于结果集的总数 + + + + + Maximum number of bytes to return must be greater than zero + 返回的最大字节数必须大于零 + + + + + Maximum number of chars to return must be greater than zero + 返回的最大字符数必须大于零 + + + + + Maximum number of XML bytes to return must be greater than zero + 返回的 XML 最大字节数必须大于零 + + + + + Access method cannot be write-only + 访问方法不能设置为”只写“ + + + + + FileStreamWrapper must be initialized before performing operations + 在执行操作之前,必须初始化 FileStreamWrapper + + + + + This FileStreamWrapper cannot be used for writing + 该 FileStreamWrapper 不能用于写入 + + + + + (1 row affected) + (1 行受到影响) + + + + + ({0} rows affected) + (影响 {0} 行) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + 命令已成功完成。 + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + Msg {0},级别 {1},状态 {2},第 {3} {4} {5} 行 + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + 查询失败︰ {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (没有列名称) + + + + + The requested query does not exist + 请求的查询不存在。 + + + + + This editor is not connected to a database + 此编辑器未连接到数据库 + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + 此编辑器会话已有正在进行中的查询。请取消这项查询,或等待它完成 + + + + + Sender for OnInfoMessage event must be a SqlConnection + OnInfoMessage 事件的发送者必须是 SqlConnection + + + + + Result cannot be saved until query execution has completed + 查询完成前,不能保存结果 + + + + + Internal error occurred while starting save task + 保存任务时发生内部错误 + + + + + A save request to the same path is in progress + 相同路径的保存请求正在进行中 + + + + + Failed to save {0}: {1} + 未能保存 {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + 没有从服务器读取结果之前,无法读取子数据集 + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + 起始行不能小于 0 或大于结果集中的行数 + + + + + Row count must be a positive integer + 行数必须是一个正整数 + + + + + Could not retrieve column schema for result set + 未能从结果集获取列架构 + + + + + Could not retrieve an execution plan from the result set + 未能从结果集获取执行计划 + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + 这功能目前不支持 Azure SQL DB 和数据仓库︰ {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + 查看定义的执行过程中出现意外的错误︰ {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + 未找到结果。 + + + + + No database object was retrieved. + 检索不到任何数据库对象。 + + + + + Please connect to a server. + 请连接到服务器。 + + + + + Operation timed out. + 操作超时。 + + + + + This object type is currently not supported by this feature. + 此功能当前不支持此对象类型。 + + + + + Position is outside of file line range + 位置超出文件行范围 + + + + + Position is outside of column range for line {0} + 第 {0} 行位置超出数据列范围 + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + 起始位置 ({0},{1}) 必须先于或等于结束位置 ({2},{3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + Msg {0},级别 {1} ,状态 {2},第 {3} 行 + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + Msg {0},级别 {1},状态 {2},过程 {3},第 {4} 行 + + + + + Msg {0}, Level {1}, State {2} + Msg {0},级别 {1},状态 {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + 执行批处理时发生错误。错误消息︰ {0} + + + + + ({0} row(s) affected) + ({0} 行受到影响) + + + + + The previous execution is not yet complete. + 前一次执行尚未完成。 + + + + + A scripting error occurred. + 出现脚本错误。 + + + + + Incorrect syntax was encountered while {0} was being parsed. + 正在分析 {0} 时发现语法错误。 + + + + + A fatal error occurred. + 出现严重错误。 + + + + + Batch execution completed {0} times... + 已执行完 {0} 次... + + + + + You cancelled the query. + 您已取消查询。 + + + + + An error occurred while the batch was being executed. + 执行批次处理时发生错误。 + + + + + An error occurred while the batch was being executed, but the error has been ignored. + 执行批次处理时发生错误,但该错误已被忽略。 + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + 不支持命令 {0}。 + + + + + The variable {0} could not be found. + 找不到变量 {0}。 + + + + + SQL Execution error: {0} + SQL 执行错误︰ {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + 批处理解析封装器执行︰{0} 找到位于第 {1} 行: {2} 描述︰{3} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + 批处理解析封装器执行引擎所收到的消息︰ 消息︰ {0},详细的消息︰ {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 批处理解析封装器执行引擎批次结果集处理︰ DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + 批处理解析封装器执行引擎批次处理结果集已完成。 + + + + + Canceling batch parser wrapper batch execution. + 正在取消批处理解析封装器的批处理执行。 + + + + + Scripting warning. + 脚本警告。 + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + 有关此错误的详细信息,请参阅产品文档中的疑难解答主题。 + + + + + File '{0}' recursively included. + 文件 '{0}' 被递归方式包含。 + + + + + Missing end comment mark '*/'. + 缺少结束注释标记 '*/'。 + + + + + Unclosed quotation mark after the character string. + 未闭合的引号后的字符字串。 + + + + + Incorrect syntax was encountered while parsing '{0}'. + '{0}' 在分析时发现语法错误。 + + + + + Variable {0} is not defined. + 未定义变量 {0}。 + + + + + test + 测试 + + + + + Replacement of an empty string by an empty string. + 用空字符串取代空字符串。 + + + + + Edit session does not exist. + 编辑会话不存在 + + + + + Query has not completed execution + 查询尚未完成 + + + + + Query did not generate exactly one result set + 查询并非产生单一结果集 + + + + + Failed to add new row to update cache + 无法添加新数据行以更新缓存,操作失败 + + + + + Given row ID is outside the range of rows in the edit cache + 给定数据行 ID 已超出 edit cache 中数据行的范围 + + + + + An update is already pending for this row and must be reverted first + 这个数据行已经有一个更新正在等待使用,因此它必须先恢复原状。 + + + + + Given row ID does not have pending update + 给定行 ID 没有正在等待的更新操作 + + + + + Table or view metadata could not be found + 找不到表格或视图的元数据 + + + + + Invalid format for binary column + 二进制列格示错误 + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Boolean 列必须填入数字 1 或 0, 或字符串 true 或 false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + 必填单元格的值缺失 + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + 这行即将被删除,其中的单元格无法被更新 + + + + + Column ID must be in the range of columns for the query + 列 ID 必须在数据列总数內才可被查询 + + + + + Column cannot be edited + 列无法被编辑 + + + + + No key columns were found + 找不到键列 + + + + + An output filename must be provided + 必须提供输出文件名 + + + + + Database object {0} cannot be used for editing. + 数据库对象 {0} 无法被编辑 + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + 指定的 URI '{0}' 没有默认的连接 + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + 提交的任务正在进行,请等待它完成 + + + + + Decimal column is missing numeric precision or numeric scale + 十进制列缺少数值精度或小数位数 + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + 无法在结果缓冲区添加行,数据读取器不包含任何行 + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + TIME 列的取值范围必须在 00:00:00.0000000 至 23:59:59.9999999 之间 + + + + + NULL is not allowed for this column + 该列不允许Null 值 + + + + + Edit session already exists. + 编辑会话已存在 + + + + + Edit session has not been initialized + 编辑会话尚未初始化 + + + + + Edit session has already been initialized + 编辑会话已被初始化 + + + + + Edit session has already been initialized or is in the process of initializing + 编辑会话已被初始化或正在初始化中 + + + + + Query execution failed, see messages for details + 执行查询失败,查看消息了解更多详情 + + + + + Result limit cannot be negative + 结果集的限制值不能为负数 + + + + + NULL + + + + + + A object name must be provided + 必须提供对象名称 + + + + + Explicitly specifying server or database is not supported + 不支持显式指定服务器或者数据库 + + + + + Table metadata does not have extended properties + 数据表的元数据没有扩展属性 + + + + + Table or view requested for edit could not be found + 找不到请求编辑的数据表或视图 + + + + + Error expanding: {0} + 扩展数据库时出错: {0} + + + + + Error connecting to {0} + 连接到 {0} 时出错 + + + + + Aggregates + 聚合 + + + + + Server Roles + 服务器角色 + + + + + Application Roles + 应用程序角色 + + + + + Assemblies + 程序集 + + + + + Assembly Files + 程序集文件 + + + + + Asymmetric Keys + 非对称密钥 + + + + + Asymmetric Keys + 非对称密钥 + + + + + Data Compression Options + 数据压缩选项 + + + + + Certificates + 证书 + + + + + FileTables + 文件表 + + + + + Certificates + 证书 + + + + + Check Constraints + CHECK 约束 + + + + + Columns + + + + + + Constraints + 约束 + + + + + Contracts + 协定 + + + + + Credentials + 凭据 + + + + + Error Messages + 错误消息 + + + + + Server Role Membership + 服务器角色成员资格 + + + + + Database Options + 数据库选项 + + + + + Database Roles + 数据库角色 + + + + + Role Memberships + 角色成员资格 + + + + + Database Triggers + 数据库触发器 + + + + + Default Constraints + 默认约束 + + + + + Defaults + 默认值 + + + + + Sequences + 序列 + + + + + Endpoints + 终结点 + + + + + Event Notifications + 事件通知 + + + + + Server Event Notifications + 服务器事件通知 + + + + + Extended Properties + 扩展属性 + + + + + Filegroups + 文件组 + + + + + Foreign Keys + 外键 + + + + + Full-Text Catalogs + 全文目录 + + + + + Full-Text Indexes + 全文检索 + + + + + Functions + 函数 + + + + + Indexes + 索引 + + + + + Inline Functions + 内联函数 + + + + + Keys + + + + + + Linked Servers + 链接的服务器 + + + + + Linked Server Logins + 链接的服务器登录名 + + + + + Logins + 登录名 + + + + + Master Key + 主密钥 + + + + + Master Keys + 主密钥 + + + + + Message Types + 消息类型 + + + + + Table-Valued Functions + 表值函数 + + + + + Parameters + 参数 + + + + + Partition Functions + 分区函数 + + + + + Partition Schemes + 分区方案 + + + + + Permissions + 权限 + + + + + Primary Keys + 主键 + + + + + Programmability + 可编程性 + + + + + Queues + 队列 + + + + + Remote Service Bindings + 远程服务绑定 + + + + + Returned Columns + 返回列 + + + + + Roles + 角色 + + + + + Routes + 路由 + + + + + Rules + 规则 + + + + + Schemas + 架构 + + + + + Security + 安全性 + + + + + Server Objects + 服务器对象 + + + + + Management + 管理 + + + + + Triggers + 触发器 + + + + + Service Broker + Service Broker + + + + + Services + 服务 + + + + + Signatures + 签名 + + + + + Log Files + 日志文件 + + + + + Statistics + 统计信息 + + + + + Storage + 存储 + + + + + Stored Procedures + 存储过程 + + + + + Symmetric Keys + 对称密钥 + + + + + Synonyms + 同义词 + + + + + Tables + + + + + + Triggers + 触发器 + + + + + Types + 类型 + + + + + Unique Keys + 唯一键 + + + + + User-Defined Data Types + 用户定义的数据类型 + + + + + User-Defined Types (CLR) + 用户定义的类型(CLR) + + + + + Users + 用户 + + + + + Views + 视图 + + + + + XML Indexes + XML 索引 + + + + + XML Schema Collections + XML 架构集合 + + + + + User-Defined Table Types + 用户定义的表类型 + + + + + Files + 文件 + + + + + Missing Caption + 缺少标题 + + + + + Broker Priorities + Broker 优先级 + + + + + Cryptographic Providers + 加密提供程序 + + + + + Database Audit Specifications + 数据库审核规范 + + + + + Database Encryption Keys + 数据库加密密钥 + + + + + Event Sessions + 事件会话 + + + + + Full Text Stoplists + 全文非索引字表 + + + + + Resource Pools + 资源池 + + + + + Audits + 审核 + + + + + Server Audit Specifications + 服务器审核规范 + + + + + Spatial Indexes + 空间索引 + + + + + Workload Groups + 工作负荷组 + + + + + SQL Files + SQL 文件 + + + + + Server Functions + 服务器函数 + + + + + SQL Type + SQL 类型 + + + + + Server Options + 服务器选项 + + + + + Database Diagrams + 数据库关系图 + + + + + System Tables + 系统表 + + + + + Databases + 数据库 + + + + + System Contracts + 系统约定 + + + + + System Databases + 系统数据库 + + + + + System Message Types + 系统消息类型 + + + + + System Queues + 系统队列 + + + + + System Services + 系统服务 + + + + + System Stored Procedures + 系统存储过程 + + + + + System Views + 系统视图 + + + + + Data-tier Applications + 数据层应用程序 + + + + + Extended Stored Procedures + 扩展存储过程 + + + + + Aggregate Functions + 聚合函数 + + + + + Approximate Numerics + 近似数字 + + + + + Binary Strings + 二进制字符串 + + + + + Character Strings + 字符串 + + + + + CLR Data Types + CLR 数据类型 + + + + + Configuration Functions + 配置函数 + + + + + Cursor Functions + 游标函数 + + + + + System Data Types + 系统数据类型 + + + + + Date and Time + 日期和时间 + + + + + Date and Time Functions + 日期和时间函数 + + + + + Exact Numerics + 精确数字 + + + + + System Functions + 系统函数 + + + + + Hierarchy Id Functions + 层次结构 ID 函数 + + + + + Mathematical Functions + 数学函数 + + + + + Metadata Functions + 元数据函数 + + + + + Other Data Types + 其他数据类型 + + + + + Other Functions + 其他函数 + + + + + Rowset Functions + 行集函数 + + + + + Security Functions + 安全函数 + + + + + Spatial Data Types + 空间数据类型 + + + + + String Functions + 字符串函数 + + + + + System Statistical Functions + 系统统计函数 + + + + + Text and Image Functions + 文本和图像函数 + + + + + Unicode Character Strings + Unicode 字符串 + + + + + Aggregate Functions + 聚合函数 + + + + + Scalar-valued Functions + 标量值函数 + + + + + Table-valued Functions + 表值函数 + + + + + System Extended Stored Procedures + 系统扩展存储过程 + + + + + Built-in Types + 内置类型 + + + + + Built-in Server Roles + 内置服务器角色 + + + + + User with Password + 具有密码的用户 + + + + + Search Property List + 搜索属性列表 + + + + + Security Policies + 安全策略 + + + + + Security Predicates + 安全谓词 + + + + + Server Role + 服务器角色 + + + + + Search Property Lists + 搜索属性列表 + + + + + Column Store Indexes + 列存储索引 + + + + + Table Type Indexes + 表类型索引 + + + + + Selective XML Indexes + 选择性 XML 索引 + + + + + XML Namespaces + XML 命名空间 + + + + + XML Typed Promoted Paths + XML 特型提升路径 + + + + + T-SQL Typed Promoted Paths + T-SQL 特型提升路径 + + + + + Database Scoped Credentials + 数据库范围的凭据 + + + + + External Data Sources + 外部数据源 + + + + + External File Formats + 外部文件格式 + + + + + External Resources + 外部资源 + + + + + External Tables + 外部表 + + + + + Always Encrypted Keys + Always Encrypted 密钥 + + + + + Column Master Keys + 列主密钥 + + + + + Column Encryption Keys + 列加密密钥 + + + + + Server + 服务器 + + + + + Error parsing ScriptingParams.ConnectionString property. + 解析属性 ScriptingParams.ConnectionString 时出错 + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + ScriptingParams.FilePath 属性指定的路径是无效目录 + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + 解析属性 ScriptingListObjectsCompleteParams.ConnectionString 时出错 + + + + + {0} ({1}, {2}, {3}) + {0} ({1}, {2}, {3}) + + + + + No default + 无默认值 + + + + + Input + 输入 + + + + + Input/Output + 输入/输出 + + + + + Input/ReadOnly + 输入/只读 + + + + + Input/Output/ReadOnly + 输入/输出/只读 + + + + + Default + 默认值 + + + + + null + Null + + + + + not null + 非 Null + + + + + {0} ({1}, {2}) + {0} ({1}, {2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1}Computed, {2}, {3}) + + + + + {0} ({1}Computed) + {0} ({1}Computed) + + + + + {0} (Column Set, {1}) + {0} (列集,{1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (列集,{1}{2},{3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (列集,{1},{2},{3}) + + + + + Unique + 唯一 + + + + + Non-Unique + 非唯一 + + + + + Clustered + 聚集 + + + + + Non-Clustered + 非聚集 + + + + + History + 历史记录 + + + + + System-Versioned + 带有系统版本 + + + + + Unavailable + 不可用 + + + + + Current default filegroup: {0} + 当前默认文件组: {0} + + + + + New Filegroup for {0} + {0} 的新文件组 + + + + + Default + 默认值 + + + + + Files + 文件 + + + + + Name + 名称 + + + + + Read-Only + 只读 + + + + + Autogrowth / Maxsize + 自动增长/最大大小 + + + + + ... + ... + + + + + <default> + <默认值> + + + + + Filegroup + 文件组 + + + + + Logical Name + 逻辑名 + + + + + File Type + 文件类型 + + + + + Initial Size (MB) + 初始大小 (MB) + + + + + <new filegroup> + <新文件组> + + + + + Path + 路径 + + + + + File Name + 文件名 + + + + + <raw device> + <原始设备> + + + + + Bulk-logged + 批量记录的 + + + + + Full + + + + + + Simple + 简单 + + + + + Select Database Owner + 选择数据库所有者 + + + + + None + + + + + + By {0} MB, Limited to {1} MB + 增量为 {0} MB,限制为 {1} MB + + + + + By {0} percent, Limited to {1} MB + 增量为 {0}%,限制为 {1} MB + + + + + By {0} MB, Unlimited + 增量为 {0} MB,增长无限制 + + + + + By {0} percent, Unlimited + 增量为 {0}%,增长无限制 + + + + + Unlimited + 无限制 + + + + + Limited to {0} MB + 不超过{0} MB + + + + + Automatic + 自动 + + + + + Service Broker + Service Broker + + + + + Collation + 排序规则 + + + + + Cursor + 游标 + + + + + Miscellaneous + 杂项 + + + + + Recovery + 恢复 + + + + + State + 状态 + + + + + ANSI NULL Default + ANSI NULL 默认值 + + + + + ANSI NULLS Enabled + 启用 ANSI NULLS + + + + + ANSI Padding Enabled + ANSI 填充已启用 + + + + + ANSI Warnings Enabled + 启用 ANSI 警告 + + + + + Arithmetic Abort Enabled + 算术中止已启用 + + + + + Auto Close + 自动关闭 + + + + + Auto Create Statistics + 自动创建统计信息 + + + + + Auto Shrink + 自动收缩 + + + + + Auto Update Statistics + 自动更新统计信息 + + + + + Auto Update Statistics Asynchronously + 自动异步更新统计信息 + + + + + Case Sensitive + 区分大小写的 + + + + + Close Cursor on Commit Enabled + 已启用“提交时关闭游标” + + + + + Collation + 排序规则 + + + + + Concatenate Null Yields Null + 串联 Null 时得到 Null + + + + + Database Compatibility Level + 数据库兼容级别 + + + + + Database State + 数据库状态 + + + + + Default Cursor + 默认游标 + + + + + Full-Text Indexing Enabled + 已启用全文索引 + + + + + Numeric Round-Abort + 数值舍入 —— 中止 + + + + + Page Verify + 页验证 + + + + + Quoted Identifiers Enabled + 已启用 Quoted Identifiers + + + + + Database Read-Only + 数据库为只读的 + + + + + Recursive Triggers Enabled + 已启用 Recursive Triggers + + + + + Restrict Access + 限制访问 + + + + + Select Into/Bulk Copy + Select Into/Bulk Copy + + + + + Honor Broker Priority + 优先处理 Broker 优先级 + + + + + Service Broker Identifier + Service Broker Identifier + + + + + Broker Enabled + 已启用 Broker + + + + + Truncate Log on Checkpoint + 在检查点删除日志 + + + + + Cross-database Ownership Chaining Enabled + 启用跨数据库所有权链接 + + + + + Trustworthy + 可信 + + + + + Date Correlation Optimization Enabled + Date Correlation Optimization 已启用 prototype_db_prop_parameterization = Parameterization + + + + + Forced + 强迫的 + + + + + Simple + 简单 + + + + + ROWS Data + 行数据 + + + + + LOG + 日志 + + + + + FILESTREAM Data + FILESTREAM 数据 + + + + + Not Applicable + 不适用 + + + + + <default path> + <默认路径> + + + + + Open Connections + 开着的连接 + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + SQL Server 需要关闭所有其它连接来改变数据库属性——你确认要改变属性并关闭所有其它连接吗? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + 紧急 + + + + + INACCESSIBLE + 不可访问 + + + + + NORMAL + 一般 + + + + + OFFLINE + 离线 + + + + + RECOVERING + 恢复中 + + + + + RECOVERY PENDING + 等待恢复 + + + + + RESTORING + 恢复中 + + + + + SHUTDOWN + 关机 + + + + + STANDBY + 待机 + + + + + SUSPECT + 怀疑 + + + + + GLOBAL + 全局 + + + + + LOCAL + ju + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + 校验码 + + + + + NONE + 没有 + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + 启用 VarDecimal 存储格式 + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + 启用加密 + + + + + OFF + + + + + + ON + + + + + + PRIMARY + 首要的 + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + 对于分配政策HASH,开始的哈希列的数量是可选的,但是应在1到16之间 + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + + + + + + Partial + 部分 + + + + + FILESTREAM Files + FILESTREAM 文件 + + + + + No Applicable Filegroup + 没有可用的文件组 + + + + + The database {0} is not accessible. + 数据库 {0} 无法访问。 + + + + + Query has no results to return + 无查询结果 + + + + + Result set has too many rows to be safely loaded + 资料行因结果集太长而可能无法加载 + + + + Parameterization + 参数化 + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + 当使用 NORECOVERY 选项还原备份时,不允许指定此选项。 + + + + + Invalid path for database file: '{0}' + 数据库文件的路径无效:“{0}” + + + + + Log + 日志 + + + + + Failed to create restore plan + 制订还原计划失败 + + + + + Restore database is not supported + 不支持还原数据库 + + + + + Restore Database + 还原数据库 + + + + + (Copy Only) + (仅复制) + + + + + Component + 组件 + + + + + Type + 类型 + + + + + Server + 服务器 + + + + + Database + 数据库 + + + + + Position + 位置 + + + + + First LSN + 第一个 LSN + + + + + Last LSN + 最后一个 LSN + + + + + Checkpoint LSN + 检查点 LSN + + + + + Full LSN + 完整 LSN + + + + + Start Date + 开始日期 + + + + + Finish Date + 完成日期 + + + + + Size + 大小 + + + + + User Name + 用户名 + + + + + Expiration + 过期 + + + + + Name + 名称 + + + + + The last backup taken ({0}) + 上次执行的备份({0}) + + + + + Backup Database + 备份数据库 + + + + + In progress + 正在进行 + + + + + Completed + 已完成 + + + + + scripting + 开始执行脚本操作 + + + + + Connection not found + 找不到连接 + + + + + Please provide a file path instead of directory path + 所指定的文件名同时也是一个文件目录名: {0} + + + + + The provided path is invalid + 无法验证备份文件的位置是否存在: {0} + + + + + Cannot access the specified path on the server: {0} + 无法访问服务器上的指定路径: {0} + + + + + No backupset selected to be restored + 未选择用于还原的备份集 + + + + + Never + 从不 + + + + + Azure SQL DB + Azure SQL 数据库 + + + + + Azure SQL Data Warehouse + Azure SQL 数据仓库 + + + + + Azure SQL Stretch Database + Azure SQL Stretch Database + + + + + Path {0} is not a valid directory + 路径 {0} 不是有效的目录 + + + + + For directory {0} a file with name {1} already exists + {0} 文件夹中已存在名为 {1} 的文件 + + + + + Value {0} is too large to fit in column of type {1} + 值 {0} 太大,无法放入类型为 {1} 的列 + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hant.xlf b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hant.xlf new file mode 100644 index 0000000000..f5956cc647 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Localization/transXliff/sr.zh-hant.xlf @@ -0,0 +1,2777 @@ + + + + + Connection parameters cannot be null + 連接參數不可為 null + + + + + OwnerUri cannot be null or empty + OwnerUri 不能為 null 或空白 + + + + + SpecifiedUri '{0}' does not have existing connection + SpecifiedUri '{0}' 沒有現有的連線 + + . + Parameters: 0 - uri (string) + + + Invalid value '{0}' for AuthenticationType. Valid values are 'Integrated' and 'SqlLogin'. + AuthenticationType 值 "{0}" 無效。 有效值為 'Integrated' 和 'SqlLogin'。 + + . + Parameters: 0 - authType (string) + + + Invalid value '{0}' for ApplicationIntent. Valid values are 'ReadWrite' and 'ReadOnly'. + '{0}' 為無效的ApplicationIntent值。 有效值為 'ReadWrite' 和 'ReadOnly'。 + + . + Parameters: 0 - intent (string) + + + Connection canceled + 已取消連線 + + + + + OwnerUri cannot be null or empty + OwnerUri 不能是 null 或空白 + + + + + Connection details object cannot be null + 連線詳細資料物件不能是 null + + + + + ServerName cannot be null or empty + ServerName 不能是 null 或空白 + + + + + {0} cannot be null or empty when using SqlLogin authentication + 使用 SqlLogin 驗證時,{0} 不可為 null 或是空白 + + . + Parameters: 0 - component (string) + + + The query has already completed, it cannot be cancelled + 查詢已完成,無法取消 + + + + + Query successfully cancelled, failed to dispose query. Owner URI not found. + 成功地取消查詢,無法處置查詢。找不到擁有者 URI 。 + + + + + Query was canceled by user + 使用者已取消查詢 + + + + + The batch has not completed, yet + 批次尚未完成 + + + + + Batch index cannot be less than 0 or greater than the number of batches + 批次索引不能小於 0 或大於批次的總數 + + + + + Result set index cannot be less than 0 or greater than the number of result sets + 結果集的索引不能小於 0 或大於結果集的總數 + + + + + Maximum number of bytes to return must be greater than zero + 傳回的最大位元組數目必須大於零 + + + + + Maximum number of chars to return must be greater than zero + 傳回的最大字元數目必須大於零 + + + + + Maximum number of XML bytes to return must be greater than zero + 傳回的最大 XML 位元組數目必須大於零 + + + + + Access method cannot be write-only + 存取方法不可以設為唯寫 + + + + + FileStreamWrapper must be initialized before performing operations + 執行前,必須先初始化 FileStreamWrapper + + + + + This FileStreamWrapper cannot be used for writing + 這個 FileStreamWrapper 不能用於寫入 + + + + + (1 row affected) + (1 列受影響) + + + + + ({0} rows affected) + ({0} 個資料列受到影響) + + . + Parameters: 0 - rows (long) + + + Commands completed successfully. + 命令已順利完成。 + + + + + Msg {0}, Level {1}, State {2}, Line {3}{4}{5} + 訊息 {0},層級 {1} ,狀態 {2},第 {3} {4} {5} 行 + + . + Parameters: 0 - msg (int), 1 - lvl (int), 2 - state (int), 3 - line (int), 4 - newLine (string), 5 - message (string) + + + Query failed: {0} + 查詢失敗︰ {0} + + . + Parameters: 0 - message (string) + + + (No column name) + (沒有資料行名稱) + + + + + The requested query does not exist + 所要求的查詢不存在 + + + + + This editor is not connected to a database + 這個編輯器尚未連接到資料庫 + + + + + A query is already in progress for this editor session. Please cancel this query or wait for its completion. + 一個查詢已在這個編輯器工作階段。請取消這項查詢,或等待其完成。 + + + + + Sender for OnInfoMessage event must be a SqlConnection + OnInfoMessage 事件的寄件者必須是一個 SqlConnection。 + + + + + Result cannot be saved until query execution has completed + 完成查詢執行前無法儲存結果 + + + + + Internal error occurred while starting save task + 在儲存工作啟動時,發生內部錯誤 + + + + + A save request to the same path is in progress + 相同路徑的儲存要求正在進行中 + + + + + Failed to save {0}: {1} + 無法儲存 {0}: {1} + + . + Parameters: 0 - fileName (string), 1 - message (string) + + + Cannot read subset unless the results have been read from the server + 從伺服器讀取結果前,無法讀取子集 + + + + + Start row cannot be less than 0 or greater than the number of rows in the result set + 開始資料列不能小於 0 或大於結果集中的資料列總數 + + + + + Row count must be a positive integer + 資料列計數必須是正整數 + + + + + Could not retrieve column schema for result set + 無法從結果集擷取資料行結構描述 + + + + + Could not retrieve an execution plan from the result set + 無法從結果集擷取執行計劃 + + + + + This feature is currently not supported on Azure SQL DB and Data Warehouse: {0} + 這項功能目前不支援 Azure SQL 資料庫和資料倉儲︰ {0} + + . + Parameters: 0 - errorMessage (string) + + + An unexpected error occurred during Peek Definition execution: {0} + 查看定義執行過程中發生未預期的錯誤︰ {0} + + . + Parameters: 0 - errorMessage (string) + + + No results were found. + 找不到任何結果。 + + + + + No database object was retrieved. + 沒有資料庫物件被擷取。 + + + + + Please connect to a server. + 請連線到伺服器。 + + + + + Operation timed out. + 作業逾時。 + + + + + This object type is currently not supported by this feature. + 此功能目前不支援這種物件類型。 + + + + + Position is outside of file line range + 位置超出檔案行範圍 + + + + + Position is outside of column range for line {0} + 第 {0} 行位置超出資料行範圍 + + . + Parameters: 0 - line (int) + + + Start position ({0}, {1}) must come before or be equal to the end position ({2}, {3}) + 開始位置 ({0},{1}) 必須先於或等於結束位置 ({2},{3}) + + . + Parameters: 0 - sLine (int), 1 - sCol (int), 2 - eLine (int), 3 - eCol (int) + + + Msg {0}, Level {1}, State {2}, Line {3} + 訊息 {0},層級 {1} ,狀態 {2},第 {3} 行 + + + + + Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4} + 訊息 {0} ,層級 {1}, 狀態 {2}, 程序 {3},第 {4} 行 + + + + + Msg {0}, Level {1}, State {2} + 訊息 {0},層級 {1} ,狀態 {2} + + + + + An error occurred while the batch was being processed. The error message is: {0} + 處理批次時,發生錯誤。錯誤訊息是︰ {0} + + + + + ({0} row(s) affected) + ({0} 個資料列受到影響) + + + + + The previous execution is not yet complete. + 前一個執行尚未完成。 + + + + + A scripting error occurred. + 發生指令碼的錯誤。 + + + + + Incorrect syntax was encountered while {0} was being parsed. + 正在剖析 {0} 時遇到不正確的語法。 + + + + + A fatal error occurred. + 發生嚴重的錯誤。 + + + + + Batch execution completed {0} times... + 已執行完成 {0} 次... + + + + + You cancelled the query. + 您已取消查詢。 + + + + + An error occurred while the batch was being executed. + 執行此批次時發生錯誤。 + + + + + An error occurred while the batch was being executed, but the error has been ignored. + 執行此批次時發生錯誤,但錯誤以忽略。 + + + + + Beginning execution loop + Beginning execution loop + + + + + Command {0} is not supported. + 不支援命令 {0}。 + + + + + The variable {0} could not be found. + 找不到變數 {0}。 + + + + + SQL Execution error: {0} + SQL 執行錯誤︰ {0} + + + + + Batch parser wrapper execution: {0} found... at line {1}: {2} Description: {3} + 批次剖析器包裝函式執行︰位於第 {1} 行: {2} 描述︰{3} 找到 {0} + + + + + Batch parser wrapper execution engine batch message received: Message: {0} Detailed message: {1} + 批次剖析器包裝函式執行引擎批次所收到的訊息︰ 訊息︰ {0},詳細的訊息︰ {1} + + + + + Batch parser wrapper execution engine batch ResultSet processing: DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + 批次剖析器包裝函式執行引擎批次結果集處理︰ DataReader.FieldCount: {0} DataReader.RecordsAffected: {1} + + + + + Batch parser wrapper execution engine batch ResultSet finished. + 批次剖析器包裝函式執行引擎批次結果集已完成。 + + + + + Canceling batch parser wrapper batch execution. + 正在取消批次剖析器包裝函式的批次執行。 + + + + + Scripting warning. + 指令碼警告。 + + + + + For more information about this error, see the troubleshooting topics in the product documentation. + 有關此錯誤的詳細資訊,請參閱產品文件中的疑難排解主題。 + + + + + File '{0}' recursively included. + 檔案 '{0}' 具有遞迴。 + + + + + Missing end comment mark '*/'. + 遺漏結束的註解記號 ' * /'。 + + + + + Unclosed quotation mark after the character string. + 字元字串後有未封閉的雙引號 + + + + + Incorrect syntax was encountered while parsing '{0}'. + 正在剖析 {0} 時遇到不正確的語法。 + + + + + Variable {0} is not defined. + 未定義變數 {0}。 + + + + + test + 測試 + + + + + Replacement of an empty string by an empty string. + 用空白字串取代空白字串。 + + + + + Edit session does not exist. + 編輯工作階段不存在 + + + + + Query has not completed execution + 查詢尚未完成 + + + + + Query did not generate exactly one result set + 查詢並非產生單一結果集 + + + + + Failed to add new row to update cache + 在 cashe 裡更新資料列失敗 + + + + + Given row ID is outside the range of rows in the edit cache + 提供的資料列識別碼已超出 edit cashe 中資料列的範圍 + + + + + An update is already pending for this row and must be reverted first + 這個資料列已經有一個更新正在等待使用,因此它必須先恢復原狀。 + + + + + Given row ID does not have pending update + 這個資料列識別碼並沒有正在等待更新 + + + + + Table or view metadata could not be found + 找不到資料表或檢視表中繼資料 + + + + + Invalid format for binary column + 二進位資料欄格示錯誤 + + + + + Allowed values for boolean columns are 0, 1, "true", or "false" + Boolean 欄位必須填入數字 1 或 0, 或字串 true 或 false + + + + + The column '{0}' is defined as NOT NULL but was not given a value + 必填儲存格未填 + + . + Parameters: 0 - colName (string) + + + A delete is pending for this row, a cell update cannot be applied. + 這個資料列即將被刪除,其中的儲存格無法被更新 + + + + + Column ID must be in the range of columns for the query + 資料行識別碼必須在資料行總數內才可被查詢 + + + + + Column cannot be edited + 資料行無法被編輯 + + + + + No key columns were found + 找不到索引鍵資料行 + + + + + An output filename must be provided + 必須提供輸出檔名 + + + + + Database object {0} cannot be used for editing. + 資料庫物件 {0} 無法被編輯 + + . + Parameters: 0 - typeName (string) + + + Specified URI '{0}' does not have a default connection + 指定的 URI '{0}' 沒有預設的連線 + + . + Parameters: 0 - uri (string) + + + A commit task is in progress. Please wait for completion. + 認可的工作正在進行,請等待它完成 + + + + + Decimal column is missing numeric precision or numeric scale + 十進位資料行缺少數值有效位數或小數位數 + + + + + <TBD> + <TBD> + + + + + Cannot add row to result buffer, data reader does not contain rows + 無法在結果緩衝區加資料列,資料讀取器不包含資料列 + + + + + TIME column values must be between 00:00:00.0000000 and 23:59:59.9999999 + TIME 欄的值範圍必須在 00:00:00.0000000 至 23:59:59.9999999 之間 + + + + + NULL is not allowed for this column + 這欄不允許填入 NULL 值 + + + + + Edit session already exists. + 編輯工作階段已存在 + + + + + Edit session has not been initialized + 編輯工作階段尚未初始化 + + + + + Edit session has already been initialized + 編輯工作階段已初始化 + + + + + Edit session has already been initialized or is in the process of initializing + 編輯工作階段已完成初始化或正在初始化 + + + + + Query execution failed, see messages for details + 查詢執行失敗, 請查看詳細資訊 + + + + + Result limit cannot be negative + 結果限制不能為負 + + + + + NULL + NULL + + + + + A object name must be provided + 必須提供物件名稱 + + + + + Explicitly specifying server or database is not supported + 不支援明確指定的伺服器或資料庫 + + + + + Table metadata does not have extended properties + 資料表中繼資料無擴充屬性 + + + + + Table or view requested for edit could not be found + 找不到要編輯的資料表或檢視表 + + + + + Error expanding: {0} + 擴充資料庫時發生錯誤:{0} + + + + + Error connecting to {0} + 連接到 {0} 時發生錯誤 + + + + + Aggregates + 彙總 + + + + + Server Roles + 伺服器角色 + + + + + Application Roles + 應用程式角色 + + + + + Assemblies + 組件 + + + + + Assembly Files + 組件檔 + + + + + Asymmetric Keys + 非對稱金鑰 + + + + + Asymmetric Keys + 非對稱金鑰 + + + + + Data Compression Options + 資料壓縮選項 + + + + + Certificates + 憑證 + + + + + FileTables + FileTable + + + + + Certificates + 憑證 + + + + + Check Constraints + 檢查條件約束 + + + + + Columns + 資料行 + + + + + Constraints + 條件約束 + + + + + Contracts + 合約 + + + + + Credentials + 認證 + + + + + Error Messages + 錯誤訊息 + + + + + Server Role Membership + 伺服器角色成員資格 + + + + + Database Options + 資料庫選項 + + + + + Database Roles + 資料庫角色 + + + + + Role Memberships + 角色成員資格 + + + + + Database Triggers + 資料庫觸發程序 + + + + + Default Constraints + 預設條件約束 + + + + + Defaults + 預設 + + + + + Sequences + 序列 + + + + + Endpoints + 端點 + + + + + Event Notifications + 事件告知 + + + + + Server Event Notifications + 伺服器事件通知 + + + + + Extended Properties + 擴充屬性 + + + + + Filegroups + 檔案群組 + + + + + Foreign Keys + 外部索引鍵 + + + + + Full-Text Catalogs + 全文檢索目錄 + + + + + Full-Text Indexes + 全文檢索索引 + + + + + Functions + 函式 + + + + + Indexes + 索引 + + + + + Inline Functions + 內嵌函式 + + + + + Keys + 索引鍵 + + + + + Linked Servers + 連結的伺服器 + + + + + Linked Server Logins + 連結的伺服器登入 + + + + + Logins + 登入 + + + + + Master Key + 主要金鑰 + + + + + Master Keys + 主要金鑰 + + + + + Message Types + 訊息類型 + + + + + Table-Valued Functions + 資料表值函式 + + + + + Parameters + 參數 + + + + + Partition Functions + 資料分割函式 + + + + + Partition Schemes + 資料分割配置 + + + + + Permissions + 權限 + + + + + Primary Keys + 主索引鍵 + + + + + Programmability + 可程式性 + + + + + Queues + 佇列 + + + + + Remote Service Bindings + 遠端服務繫結 + + + + + Returned Columns + 傳回的資料行 + + + + + Roles + 角色 + + + + + Routes + 路由 + + + + + Rules + 規則 + + + + + Schemas + 結構描述 + + + + + Security + 安全性 + + + + + Server Objects + 伺服器物件 + + + + + Management + 管理 + + + + + Triggers + 觸發程序 + + + + + Service Broker + Service Broker + + + + + Services + 服務 + + + + + Signatures + 簽章 + + + + + Log Files + 記錄檔 + + + + + Statistics + 統計資料 + + + + + Storage + 儲存體 + + + + + Stored Procedures + 預存程序 + + + + + Symmetric Keys + 對稱金鑰 + + + + + Synonyms + 同義資料表 + + + + + Tables + 資料表 + + + + + Triggers + 觸發程序 + + + + + Types + 型別 + + + + + Unique Keys + 唯一索引鍵 + + + + + User-Defined Data Types + 使用者定義資料類型 + + + + + User-Defined Types (CLR) + 使用者定義型別 (CLR) + + + + + Users + 使用者 + + + + + Views + 檢視 + + + + + XML Indexes + XML 索引 + + + + + XML Schema Collections + XML 結構描述集合 + + + + + User-Defined Table Types + 使用者定義資料表類型 + + + + + Files + 檔案 + + + + + Missing Caption + 遺漏標題 + + + + + Broker Priorities + Broker 優先權 + + + + + Cryptographic Providers + 密碼編譯提供者 + + + + + Database Audit Specifications + 資料庫稽核規格 + + + + + Database Encryption Keys + 資料庫加密金鑰 + + + + + Event Sessions + 事件工作階段 + + + + + Full Text Stoplists + 全文檢索停用字詞表 + + + + + Resource Pools + 資源集區 + + + + + Audits + 稽核 + + + + + Server Audit Specifications + 伺服器稽核規格 + + + + + Spatial Indexes + 空間索引 + + + + + Workload Groups + 工作負載群組 + + + + + SQL Files + SQL 檔案 + + + + + Server Functions + 伺服器函式 + + + + + SQL Type + SQL 類型 + + + + + Server Options + 伺服器選項 + + + + + Database Diagrams + 資料庫圖表 + + + + + System Tables + 系統資料表 + + + + + Databases + 資料庫 + + + + + System Contracts + 系統合約 + + + + + System Databases + 系統資料庫 + + + + + System Message Types + 系統訊息類型 + + + + + System Queues + 系統佇列 + + + + + System Services + 系統服務 + + + + + System Stored Procedures + 系統預存程序 + + + + + System Views + 系統檢視表 + + + + + Data-tier Applications + 資料層應用程式 + + + + + Extended Stored Procedures + 擴充預存程序 + + + + + Aggregate Functions + 彙總函式 + + + + + Approximate Numerics + 近似數值 + + + + + Binary Strings + 二進位字串 + + + + + Character Strings + 字元字串 + + + + + CLR Data Types + CLR 資料型別 + + + + + Configuration Functions + 組態函式 + + + + + Cursor Functions + 資料指標函式 + + + + + System Data Types + 系統資料型別 + + + + + Date and Time + 日期和時間 + + + + + Date and Time Functions + 日期和時間函式 + + + + + Exact Numerics + 精確數值 + + + + + System Functions + 系統函式 + + + + + Hierarchy Id Functions + 階層識別碼函式 + + + + + Mathematical Functions + 數學函式 + + + + + Metadata Functions + 中繼資料函式 + + + + + Other Data Types + 其他資料型別 + + + + + Other Functions + 其他函式 + + + + + Rowset Functions + 資料列集函式 + + + + + Security Functions + 安全性函式 + + + + + Spatial Data Types + 空間資料型別 + + + + + String Functions + 字串函式 + + + + + System Statistical Functions + 系統統計函式 + + + + + Text and Image Functions + 文字和影像函式 + + + + + Unicode Character Strings + Unicode 字元字串 + + + + + Aggregate Functions + 彙總函式 + + + + + Scalar-valued Functions + 純量值函式 + + + + + Table-valued Functions + 資料表值函式 + + + + + System Extended Stored Procedures + 系統擴充預存程序 + + + + + Built-in Types + 內建型別 + + + + + Built-in Server Roles + 內建伺服器角色 + + + + + User with Password + 有密碼的使用者 + + + + + Search Property List + 搜尋屬性清單 + + + + + Security Policies + 安全性原則 + + + + + Security Predicates + 安全性述詞 + + + + + Server Role + 伺服器角色 + + + + + Search Property Lists + 搜尋屬性清單 + + + + + Column Store Indexes + 資料行儲存索引 + + + + + Table Type Indexes + 資料表類型索引 + + + + + Selective XML Indexes + 選擇性 XML 索引 + + + + + XML Namespaces + XML 命名空間 + + + + + XML Typed Promoted Paths + XML 具類型的升級路徑 + + + + + T-SQL Typed Promoted Paths + T-SQL 具類型的升級路徑 + + + + + Database Scoped Credentials + 資料庫範圍認證 + + + + + External Data Sources + 外部資料來源 + + + + + External File Formats + 外部檔案格式 + + + + + External Resources + 外部資源 + + + + + External Tables + 外部資料表 + + + + + Always Encrypted Keys + Always Encrypted 金鑰 + + + + + Column Master Keys + 資料行主要金鑰 + + + + + Column Encryption Keys + 資料行加密金鑰 + + + + + Server + 伺服器 + + + + + Error parsing ScriptingParams.ConnectionString property. + 剖析屬性 ScriptingParams.ConnectionString 時發生錯誤 + + + + + Invalid directory specified by the ScriptingParams.FilePath property. + ScriptingParams.FilePath 屬性指定的路径是無效目錄 + + + + + Error parsing ScriptingListObjectsCompleteParams.ConnectionString property. + 剖析屬性 ScriptingListObjectsCompleteParams.ConnectionString 時發生錯誤 + + + + + {0} ({1}, {2}, {3}) + {0} ({1},{2},{3}) + + + + + No default + 無預設值 + + + + + Input + 輸入 + + + + + Input/Output + 輸入/輸出 + + + + + Input/ReadOnly + 輸入/唯讀 + + + + + Input/Output/ReadOnly + 輸入/輸出/唯讀 + + + + + Default + 預設值 + + + + + null + Null + + + + + not null + 非 Null + + + + + {0} ({1}, {2}) + {0} ({1},{2}) + + + + + {0} ({1}) + {0} ({1}) + + + + + {0} ({1}Computed, {2}, {3}) + {0} ({1} 已計算,{2},{3}) + + + + + {0} ({1}Computed) + {0} ({1} 已計算) + + + + + {0} (Column Set, {1}) + {0} (資料行集,{1}) + + + + + {0} (Column Set, {1}{2}, {3}) + {0} (資料行集,{1}{2},{3}) + + + + + {0} (Column Set, {1}, {2}, {3}) + {0} (資料行集,{1},{2},{3}) + + + + + Unique + 唯一 + + + + + Non-Unique + 非唯一 + + + + + Clustered + 叢集 + + + + + Non-Clustered + 非叢集 + + + + + History + 歷程記錄 + + + + + System-Versioned + 系統建立版本 + + + + + Unavailable + 無法使用 + + + + + Current default filegroup: {0} + 當前預設檔案群組: {0} + + + + + New Filegroup for {0} + {0} 的新檔案群組 + + + + + Default + 預設值 + + + + + Files + 檔案 + + + + + Name + 名稱 + + + + + Read-Only + 唯讀 + + + + + Autogrowth / Maxsize + 自動成長 / 大小上限 + + + + + ... + ... + + + + + <default> + <預設> + + + + + Filegroup + 檔案群組 + + + + + Logical Name + 邏輯名稱 + + + + + File Type + 檔案類型 + + + + + Initial Size (MB) + 初始大小 (MB) + + + + + <new filegroup> + <新增檔案群組> + + + + + Path + 路徑 + + + + + File Name + 檔案名稱 + + + + + <raw device> + <未經處理的裝置> + + + + + Bulk-logged + 大量記錄 + + + + + Full + Full + + + + + Simple + Simple + + + + + Select Database Owner + 選取資料庫擁有者 + + + + + None + + + + + + By {0} MB, Limited to {1} MB + 以 {0} MB 為單位,限制為 {1} MB + + + + + By {0} percent, Limited to {1} MB + 以百分之 {0} 為單位,限制為 {1} MB + + + + + By {0} MB, Unlimited + 以 {0} MB 為單位,無限制 + + + + + By {0} percent, Unlimited + 以百分之 {0} 為單位,無限制 + + + + + Unlimited + 無限制 + + + + + Limited to {0} MB + 限制為 {0} MB + + + + + Automatic + 自動 + + + + + Service Broker + Service Broker + + + + + Collation + 定序 + + + + + Cursor + 資料指標 + + + + + Miscellaneous + 其他 + + + + + Recovery + 復原 + + + + + State + 狀態 + + + + + ANSI NULL Default + ANSI NULL 預設值 + + + + + ANSI NULLS Enabled + ANSI NULLS 已啟用 + + + + + ANSI Padding Enabled + +ANSI Padding 已啟用 + + + + + ANSI Warnings Enabled + ANSI Warnings 已啟用 + + + + + Arithmetic Abort Enabled + Arithmetic Abort 已啟用 + + + + + Auto Close + 自動關閉 + + + + + Auto Create Statistics + 自動建立統計資料 + + + + + Auto Shrink + 自動壓縮 + + + + + Auto Update Statistics + 自動更新統計資料 + + + + + Auto Update Statistics Asynchronously + 自動非同步更新統計資料 + + + + + Case Sensitive + 區分大小寫 + + + + + Close Cursor on Commit Enabled + 認可時關閉資料指標已啟用 + + + + + Collation + 定序 + + + + + Concatenate Null Yields Null + 串連 Null 產生 Null + + + + + Database Compatibility Level + 資料庫相容性層級 + + + + + Database State + 資料庫狀態 + + + + + Default Cursor + 預設資料指標 + + + + + Full-Text Indexing Enabled + 全文檢索索引已啟用 + + + + + Numeric Round-Abort + 數值捨入中止 + + + + + Page Verify + 頁面確認 + + + + + Quoted Identifiers Enabled + 引號識別碼已啟用 + + + + + Database Read-Only + 資料庫唯讀 + + + + + Recursive Triggers Enabled + 遞迴觸發程序已啟用 + + + + + Restrict Access + 限制存取 + + + + + Select Into/Bulk Copy + 選取/大量複製 + + + + + Honor Broker Priority + 接受 Broker 優先權 + + + + + Service Broker Identifier + Service Broker 識別碼 + + + + + Broker Enabled + Broker 已啟用 + + + + + Truncate Log on Checkpoint + 在檢查點截斷記錄 + + + + + Cross-database Ownership Chaining Enabled + 已啟用跨資料庫擁有權鏈結 + + + + + Trustworthy + 可信任 + + + + + Date Correlation Optimization Enabled + 已啟用日期相互關聯最佳化 prototype_db_prop_parameterization = 參數化 + + + + + Forced + 強制 + + + + + Simple + 簡易 + + + + + ROWS Data + 資料列資料 + + + + + LOG + LOG + + + + + FILESTREAM Data + FILESTREAM 資料 + + + + + Not Applicable + 不適用 + + + + + <default path> + <預設路徑> + + + + + Open Connections + 開啟連接 + + + + + To change the database properties, SQL Server must close all other connections to the database_ Are you sure you want to change the properties and close all other connections? + 為了變更資料庫屬性,SQL Server必須關閉所有其他與資料庫的連線。 +確定要變更屬性並關閉所有其他連線嗎? + + + + + AUTO_CLOSED + AUTO_CLOSED + + + + + EMERGENCY + EMERGENCY + + + + + INACCESSIBLE + INACCESSIBLE + + + + + NORMAL + NORMAL + + + + + OFFLINE + OFFLINE + + + + + RECOVERING + RECOVERING + + + + + RECOVERY PENDING + RECOVERY PENDING + + + + + RESTORING + RESTORING + + + + + SHUTDOWN + SHUTDOWN + + + + + STANDBY + STANDBY + + + + + SUSPECT + SUSPECT + + + + + GLOBAL + GLOBAL + + + + + LOCAL + LOCAL + + + + + MULTI_USER + MULTI_USER + + + + + RESTRICTED_USER + RESTRICTED_USER + + + + + SINGLE_USER + SINGLE_USER + + + + + CHECKSUM + CHECKSUM + + + + + NONE + NONE + + + + + TORN_PAGE_DETECTION + TORN_PAGE_DETECTION + + + + + VarDecimal Storage Format Enabled + VarDecimal 儲存格式已啟用 + + + + + SQL Server 2008 (100) + SQL Server 2008 (100) + + + + + Encryption Enabled + 加密已啟用 + + + + + OFF + OFF + + + + + ON + ON + + + + + PRIMARY + PRIMARY + + + + + For the distribution policy HASH, the number of leading hash columns is optional but should be from 1 to 16 columns + 散發原則 HASH 的前置雜湊資料行是選擇性的,但應該介於 1 到 16 個資料行之間。 + + + + + SQL Server 2012 (110) + SQL Server 2012 (110) + + + + + SQL Server 2014 (120) + SQL Server 2014 (120) + + + + + SQL Server 2016 (130) + SQL Server 2016 (130) + + + + + SQL Server vNext (140) + SQL Server vNext (140) + + + + + None + + + + + + Partial + Partial + + + + + FILESTREAM Files + FILESTREAM 檔案 + + + + + No Applicable Filegroup + 沒有適用的檔案群組 + + + + + The database {0} is not accessible. + 無法存取資料庫 {0}。 + + + + + Query has no results to return + 沒有查詢結果可以回傳 + + + + + Result set has too many rows to be safely loaded + 資料列因結果集太長而無法載入 + + + + Parameterization + 參數化 + + + + + Specifying this option when restoring a backup with the NORECOVERY option is not permitted. + 不允許使用 NORECOVERY 選項還原備份時,請指定這個選項。 + + + + + Invalid path for database file: '{0}' + 資料庫檔案的路徑無效: '{0}' + + + + + Log + 記錄檔 + + + + + Failed to create restore plan + 無法建立還原計畫 + + + + + Restore database is not supported + 不支援還原資料庫 + + + + + Restore Database + 還原資料庫 + + + + + (Copy Only) + (僅複製) + + + + + Component + 元件 + + + + + Type + 型別 + + + + + Server + 伺服器 + + + + + Database + 資料庫 + + + + + Position + 位置 + + + + + First LSN + 第一個 LSN + + + + + Last LSN + 最後一個 LSN + + + + + Checkpoint LSN + 檢查點 LSN + + + + + Full LSN + 完整 LSN + + + + + Start Date + 開始日期 + + + + + Finish Date + 完成日期 + + + + + Size + 大小 + + + + + User Name + 使用者名稱 + + + + + Expiration + 逾期 + + + + + Name + 名稱 + + + + + The last backup taken ({0}) + 上次建立的備份 ({0}) + + + + + Backup Database + 備份資料庫 + + + + + In progress + 進行中 + + + + + Completed + 已完成 + + + + + scripting + 指令碼 + + + + + Connection not found + 找不到連接 + + + + + Please provide a file path instead of directory path + 指定的檔案名稱也是目錄名稱: {0} + + + + + The provided path is invalid + 無法確認備份檔案位置的存在: {0} + + + + + Cannot access the specified path on the server: {0} + 無法存取伺服器上指定的路徑: {0} + + + + + No backupset selected to be restored + 無選擇的備份集可還原 + + + + + Never + 永不 + + + + + Azure SQL DB + Azure SQL DB + + + + + Azure SQL Data Warehouse + Azure SQL 資料倉儲 + + + + + Azure SQL Stretch Database + Azure SQL 延展資料庫 + + + + + Path {0} is not a valid directory + 路徑 {0} 不是有效的目錄 + + + + + For directory {0} a file with name {1} already exists + 因目錄 {0} 中已有存在的檔案名稱 {1} + + + + + Value {0} is too large to fit in column of type {1} + 數值 {0} 太大以致於無法符合欄位型態 {1} + + . + Parameters: 0 - value (string), 1 - columnType (string) + + + + \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/MetadataListRequest.cs b/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/MetadataListRequest.cs new file mode 100644 index 0000000000..a53fbafa54 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/MetadataListRequest.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.Metadata.Contracts +{ + public class MetadataQueryParams + { + public string OwnerUri { get; set; } + } + + public class MetadataQueryResult + { + public ObjectMetadata[] Metadata { get; set; } + } + + public class MetadataListRequest + { + public static readonly + RequestType Type = + RequestType.Create("metadata/list"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs b/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs new file mode 100644 index 0000000000..494b397560 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Metadata/Contracts/ObjectMetadata.cs @@ -0,0 +1,33 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.Metadata.Contracts +{ + public enum MetadataType + { + Table = 0, + View = 1, + SProc = 2, + Function = 3, + Schema = 4, + Database = 5 + } + + /// + /// Object metadata information + /// + public class ObjectMetadata + { + public MetadataType MetadataType { get; set; } + + public string MetadataTypeName { get; set; } + + public string Schema { get; set; } + + public string Name { get; set; } + + public string Urn { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Metadata/MetadataService.cs b/src/Microsoft.Kusto.ServiceLayer/Metadata/MetadataService.cs new file mode 100644 index 0000000000..36015f55cf --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Metadata/MetadataService.cs @@ -0,0 +1,109 @@ +// +// 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.Linq; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.Kusto.ServiceLayer.Metadata.Contracts; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.Metadata +{ + /// + /// Main class for Metadata Service functionality + /// + public sealed class MetadataService + { + private static readonly Lazy LazyInstance = new Lazy(() => new MetadataService()); + + public static MetadataService Instance => LazyInstance.Value; + + private static ConnectionService connectionService = null; + + /// + /// Internal for testing purposes only + /// + internal static ConnectionService ConnectionServiceInstance + { + get + { + if (connectionService == null) + { + connectionService = ConnectionService.Instance; + } + return connectionService; + } + + set + { + connectionService = value; + } + } + + /// + /// Initializes the Metadata Service instance + /// + /// + /// + public void InitializeService(ServiceHost serviceHost) + { + serviceHost.SetRequestHandler(MetadataListRequest.Type, HandleMetadataListRequest); + } + + /// + /// Handle a metadata query request + /// + internal async Task HandleMetadataListRequest( + MetadataQueryParams metadataParams, + RequestContext requestContext) + { + try + { + Func requestHandler = async () => + { + ConnectionInfo connInfo; + MetadataService.ConnectionServiceInstance.TryFindConnection(metadataParams.OwnerUri, out connInfo); + + var metadata = new List(); + if (connInfo != null) + { + ReliableDataSourceConnection connection; + connInfo.TryGetConnection("Default", out connection); + IDataSource dataSource = connection.GetUnderlyingConnection(); + + DataSourceObjectMetadata objectMetadata = DataSourceFactory.CreateClusterMetadata(connInfo.ConnectionDetails.ServerName); + DataSourceObjectMetadata databaseMetadata = DataSourceFactory.CreateDatabaseMetadata(objectMetadata, connInfo.ConnectionDetails.DatabaseName); + + IEnumerable databaseChildMetadataInfo = dataSource.GetChildObjects(databaseMetadata, true); + metadata = DataSourceFactory.ConvertToObjectMetadata(databaseChildMetadataInfo); + } + + await requestContext.SendResult(new MetadataQueryResult + { + Metadata = metadata.ToArray() + }); + }; + + Task task = Task.Run(async () => await requestHandler()).ContinueWithOnFaulted(async t => + { + await requestContext.SendError(t.Exception.ToString()); + }); + MetadataListTask = task; + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + internal Task MetadataListTask { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj b/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj new file mode 100644 index 0000000000..2d5d038bc0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Microsoft.Kusto.ServiceLayer.csproj @@ -0,0 +1,43 @@ + + + $(ServiceLayerTargetFramework) + MicrosoftKustoServiceLayer + Exe + false + false + false + false + false + false + $(DefineConstants);NETCOREAPP1_0;TRACE + true + true + portable + win7-x64;win7-x86;ubuntu.14.04-x64;ubuntu.16.04-x64;centos.7-x64;rhel.7.2-x64;debian.8-x64;fedora.23-x64;opensuse.13.2-x64;osx.10.11-x64;linux-x64 + + + + true + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CloseSessionRequest.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CloseSessionRequest.cs new file mode 100644 index 0000000000..4b3e98c4da --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CloseSessionRequest.cs @@ -0,0 +1,86 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Information returned from a . + /// Contains success information, a to be used when + /// requesting closing an existing session. + /// + public class CloseSessionResponse + { + /// + /// Boolean indicating if the session was closed successfully + /// + public bool Success { get; set; } + + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + } + + /// + /// Parameters to the . + /// + public class CloseSessionParams + { + /// + /// The Id returned from a . This + /// is used to disambiguate between different trees. + /// + public string SessionId { get; set; } + } + + /// + /// Information returned when a session is disconnected. + /// Contains success information and a + /// + public class SessionDisconnectedParameters + { + /// + /// Boolean indicating if the connection was successful + /// + public bool Success { get; set; } + + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + + /// + /// Error message returned from the engine for a object explorer session failure reason, if any. + /// + public string ErrorMessage { get; set; } + } + + /// + /// Establishes an Object Explorer tree session for a specific connection. + /// This will create a connection to a specific server or database, register + /// it for use in the + /// + public class CloseSessionRequest + { + public static readonly + RequestType Type = + RequestType.Create("objectexplorer/closesession"); + } + + /// + /// Session disconnected notification + /// + public class SessionDisconnectedNotification + { + public static readonly + EventType Type = + EventType.Create("objectexplorer/sessiondisconnected"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CreateSessionRequest.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CreateSessionRequest.cs new file mode 100644 index 0000000000..99cfa65fa9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/CreateSessionRequest.cs @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Information returned from a . + /// Contains success information, a to be used when + /// requesting expansion of nodes, and a root node to display for this area. + /// + public class CreateSessionResponse + { + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + + } + + /// + /// Information returned from a . + /// Contains success information, a to be used when + /// requesting expansion of nodes, and a root node to display for this area. + /// + public class SessionCreatedParameters + { + /// + /// Boolean indicating if the connection was successful + /// + public bool Success { get; set; } + + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + + /// + /// Information describing the base node in the tree + /// + public NodeInfo RootNode { get; set; } + + + /// + /// Error message returned from the engine for a object explorer session failure reason, if any. + /// + public string ErrorMessage { get; set; } + } + /// + /// Establishes an Object Explorer tree session for a specific connection. + /// This will create a connection to a specific server or database, register + /// it for use in the + /// + public class CreateSessionRequest + { + public static readonly + RequestType Type = + RequestType.Create("objectexplorer/createsession"); + } + + /// + /// Session notification mapping entry + /// + public class CreateSessionCompleteNotification + { + public static readonly + EventType Type = + EventType.Create("objectexplorer/sessioncreated"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs new file mode 100644 index 0000000000..08816d870d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/ExpandRequest.cs @@ -0,0 +1,76 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Information returned from a . + /// + public class ExpandResponse + { + /// + /// Unique ID to use when sending any requests for objects in the + /// tree under the node + /// + public string SessionId { get; set; } + + /// + /// Information describing the expanded nodes in the tree + /// + public NodeInfo[] Nodes { get; set; } + + /// + /// Path identifying the node to expand. See for details + /// + public string NodePath { get; set; } + + /// + /// Error message returned from the engine for a object explorer expand failure reason, if any. + /// + public string ErrorMessage { get; set; } + } + + /// + /// Parameters to the . + /// + public class ExpandParams + { + /// + /// The Id returned from a . This + /// is used to disambiguate between different trees. + /// + public string SessionId { get; set; } + + /// + /// Path identifying the node to expand. See for details + /// + public string NodePath { get; set; } + } + + /// + /// A request to expand a + /// + public class ExpandRequest + { + /// + /// Returns children of a given node as a array. + /// + public static readonly + RequestType Type = + RequestType.Create("objectexplorer/expand"); + } + + /// + /// Expand notification mapping entry + /// + public class ExpandCompleteNotification + { + public static readonly + EventType Type = + EventType.Create("objectexplorer/expandCompleted"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/FindNodesRequest.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/FindNodesRequest.cs new file mode 100644 index 0000000000..fa50747037 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/FindNodesRequest.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Information returned from a . + /// + public class FindNodesResponse + { + /// + /// Information describing the matching nodes in the tree + /// + public List Nodes { get; set; } + } + + /// + /// Parameters to the . + /// + public class FindNodesParams + { + /// + /// The Id returned from a . This + /// is used to disambiguate between different trees. + /// + public string SessionId { get; set; } + + public string Type { get; set; } + + public string Schema { get; set; } + + public string Name { get; set; } + + public string Database { get; set; } + + public List ParentObjectNames { get; set; } + + } + + /// + /// TODO + /// + public class FindNodesRequest + { + public static readonly + RequestType Type = + RequestType.Create("objectexplorer/findnodes"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs new file mode 100644 index 0000000000..7170681e48 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/NodeInfo.cs @@ -0,0 +1,62 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Information describing a Node in the Object Explorer tree. + /// Contains information required to display the Node to the user and + /// to know whether actions such as expanding children is possible + /// the node + /// + public class NodeInfo + { + /// + /// Path identifying this node: for example a table will be at ["server", "database", "tables", "tableName"]. + /// This enables rapid navigation of the tree without the need for a global registry of elements. + /// The path functions as a unique ID and is used to disambiguate the node when sending requests for expansion. + /// A common ID is needed since processes do not share address space and need a unique identifier + /// + public string NodePath { get; set; } + + /// + /// The type of the node - for example Server, Database, Folder, Table + /// + public string NodeType { get; set; } + + /// + /// Label to display to the user, describing this node. + /// + public string Label { get; set; } + + /// + /// Node Sub type - for example a key can have type as "Key" and sub type as "PrimaryKey" + /// + public string NodeSubType { get; set; } + + /// + /// Node status - for example login can be disabled/enabled + /// + public string NodeStatus { get; set; } + + /// + /// Is this a leaf node (in which case no children can be generated) or + /// is it expandable? + /// + public bool IsLeaf { get; set; } + + /// + /// Object Metadata for smo objects to be used for scripting + /// + public DataSourceObjectMetadata Metadata { get; set; } + + /// + /// Error message returned from the engine for a object explorer node failure reason, if any. + /// + public string ErrorMessage { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs new file mode 100644 index 0000000000..5d13ca15c1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Contracts/RefreshRequest.cs @@ -0,0 +1,29 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts +{ + /// + /// Parameters to the . + /// + public class RefreshParams: ExpandParams + { + } + + /// + /// A request to expand a + /// + public class RefreshRequest + { + /// + /// Returns children of a given node as a array. + /// + public static readonly + RequestType Type = + RequestType.Create("objectexplorer/refresh"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs new file mode 100644 index 0000000000..0ee8ca0acc --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/ChildFactory.cs @@ -0,0 +1,74 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.Threading; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// A supports creation of children + /// for a class of objects in the tree. The + /// + public abstract class ChildFactory + { + /// + /// The set of applicable parents for which the factory can create children. + /// + /// + /// the string names for each that + /// this factory can create children for + /// + public abstract IEnumerable ApplicableParents(); + + /// + /// Expands an element in the + /// + /// Parent Node + /// force to refresh + /// name of the sql object to filter + /// + public abstract IEnumerable Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken); + + /// + /// The list of filters that should be applied on the smo object list + /// + public abstract IEnumerable Filters { get; } + + /// + /// The list of properties to be loaded with the object + /// + public abstract IEnumerable SmoProperties { get; } + + /// + /// Returns the node sub type if the object can have sub types otehr wise returns empty string + /// + public abstract string GetNodeSubType(object objectMetadata, QueryContext oeContext); + + /// + /// Returns the status of the object assigned to node. If the object doesn't spport status returns empty string + /// + public abstract string GetNodeStatus(object objectMetadata, QueryContext oeContext); + + /// + /// Returns the custom name of the object assigned to the node. If the object doesn't have custom name, returns empty string + /// + public abstract string GetNodeCustomName(object objectMetadata, QueryContext oeContext); + + /// + /// Returns the name of the object as shown in its Object Explorer node path + /// + public abstract string GetNodePathName(object objectMetadata); + + public abstract bool CanCreateChild(TreeNode parent, object context); // TODOKusto: Can this context be changed to DataSourceObjectMetadata + public abstract TreeNode CreateChild(TreeNode parent, DataSourceObjectMetadata childMetadata); + + // TODO Consider whether Remove operations need to be supported + //public abstract bool CanRemoveChild(TreeNode parent, object context); + //public abstract int GetChildIndexToRemove(TreeNode parent, object context); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeFilter.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeFilter.cs new file mode 100644 index 0000000000..96f1c9dc7c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeFilter.cs @@ -0,0 +1,107 @@ +// +// 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; +using System.Collections.Generic; +using System.Linq; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// Has information for filtering a SMO object by properties + /// + public class NodeFilter + { + /// + /// Property name + /// + public string Property { get; set; } + + /// + /// Filter values + /// + public List Values { get; set; } + + /// + /// Type of the filter values + /// + public Type Type { get; set; } + + /// + /// Indicates which platforms a filter is valid for + /// + public ValidForFlag ValidFor { get; set; } + + /// + /// The type of the Querier the filter can be applied to + /// + public Type TypeToReverse { get; set; } + + /// + /// Returns true if the filter can be apply to the given type and Server type + /// + /// Type of the querier + /// Server Type + /// + public bool CanApplyFilter(Type type, ValidForFlag validForFlag) + { + bool canApplyFilter = false; + canApplyFilter = TypeToReverse == null || TypeToReverse == type; + canApplyFilter = canApplyFilter && (ValidFor == 0 || ValidFor.HasFlag(validForFlag)); + + return canApplyFilter; + } + + /// + /// Creates a string from the filter property and values to be used in the Urn to query the SQL objects + /// Example of the output:[@ IsSystemObject = 0] + /// + /// + public string ToPropertyFilterString() + { + string filter = ""; + List values = Values; + if (values != null) + { + for (int i = 0; i < values.Count; i++) + { + var value = values[i]; + object propertyValue = value; + if (Type == typeof(string)) + { + propertyValue = $"'{propertyValue}'"; + } + if (Type == typeof(Enum)) + { + propertyValue = (int)Convert.ChangeType(value, Type); + + } + string orPrefix = i == 0 ? string.Empty : "or"; + filter = $"{filter} {orPrefix} @{Property} = {propertyValue}"; + } + } + filter = $"({filter})"; + + return filter; + } + + public static string ConcatProperties(IEnumerable filters) + { + string filter = ""; + var list = filters.ToList(); + for (int i = 0; i < list.Count; i++) + { + var value = list[i]; + + string andPrefix = i == 0 ? string.Empty : "and"; + filter = $"{filter} {andPrefix} {value.ToPropertyFilterString()}"; + } + filter = $"[{filter}]"; + + return filter; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs new file mode 100644 index 0000000000..bd2d005e88 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeObservableCollection.cs @@ -0,0 +1,190 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// A collection class for + /// + public sealed class NodeObservableCollection : ObservableCollection + { + public event EventHandler Initialized; + private int? numInits; + private static int cleanupBlocker; + + public bool IsInitialized + { + get { return numInits.HasValue && numInits == 0; } + } + + public bool IsPopulating + { + get { return numInits.HasValue && numInits != 0; } + } + + public bool IsSorted + { + get + { + // SMO objects are already sorted so no need to sort them again + return this.FirstOrDefault() is DataSourceTreeNode; + } + } + + public void BeginInit() + { + if (!numInits.HasValue) + { + numInits = 1; + } + else + { + numInits = numInits + 1; + } + } + + public void EndInit() + { + IList empty = null; + EndInit(null, ref empty); + } + + public void EndInit(TreeNode parent, ref IList deferredChildren) + { + if (numInits.HasValue && + numInits.Value == 1) + { + try + { + if (!IsSorted) + { + DoSort(); + } + + if (deferredChildren != null) + { + // Set the parents so the children know how to sort themselves + foreach (var item in deferredChildren) + { + item.Parent = parent; + } + + deferredChildren = deferredChildren.OrderBy(x => x).ToList(); + + // Add the deferredChildren + foreach (var item in deferredChildren) + { + this.Add(item); + } + } + } + finally + { + if (deferredChildren != null) + { + deferredChildren.Clear(); + } + numInits = numInits - 1; + } + + Initialized?.Invoke(this, EventArgs.Empty); + } + else + { + numInits = numInits - 1; + } + } + + + /// + /// Repositions this child in the list + /// + public void ReSortChild(TreeNode child) + { + if (child == null) + return; + + List sorted = this.OrderBy(x => x).ToList(); + + // Remove without cleanup + try + { + cleanupBlocker++; + Remove(child); + } + finally + { + cleanupBlocker--; + } + + // Then insert + for (int i = 0; i < sorted.Count; i++) + { + if (sorted[i] == child) + { + Insert(i, child); + return; + } + } + } + + protected override void RemoveItem(int index) + { + // Cleanup all the children + Cleanup(this[index]); + + base.RemoveItem(index); + } + + protected override void ClearItems() + { + // Cleanup all the children + foreach (var child in this) + { + Cleanup(child); + } + + base.ClearItems(); + } + + private static void Cleanup(TreeNode parent) + { + if (cleanupBlocker > 0 || + parent.Parent == null) + return; + + // TODO implement cleanup policy / pattern + //ICleanupPattern parentAsCleanup = parent as ICleanupPattern; + //if (parentAsCleanup != null) + // parentAsCleanup.DoCleanup(); + + //foreach (var child in parent.Children) + //{ + // Cleanup(child); + //} + + parent.Parent = null; + } + + private void DoSort() + { + List sorted = this.OrderBy(x => x).ToList(); + for (int i = 0; i < sorted.Count(); i++) + { + int index = IndexOf(sorted[i]); + if (index != i) + { + Move(IndexOf(sorted[i]), i); + } + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeSmoProperty.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeSmoProperty.cs new file mode 100644 index 0000000000..448d436f9f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeSmoProperty.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// Has information for SMO object properties to be loaded with the SMO object + /// + public class NodeSmoProperty + { + /// + /// Property name + /// + public string Name { get; set; } + + /// + /// Indicates which platforms a filter is valid for + /// + public ValidForFlag ValidFor { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeTypes.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeTypes.cs new file mode 100644 index 0000000000..80b35a9387 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/NodeTypes.cs @@ -0,0 +1,144 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// Enum listing possible node types in the object explorer tree + /// + // TODO Consider replacing this with an auto-gen'd version + public enum NodeTypes + { + None, + SqlServersRoot, + Database, + Server, + ScalarValuedFunction, + TableValuedFunction, + AggregateFunction, + FileGroup, + StoredProcedure, + UserDefinedTableType, + View, + Table, + HistoryTable, + Folder, + Databases, + ExternalResources, + ServerLevelSecurity, + ServerLevelServerObjects, + ServerLevelManagement, + SystemDatabases, + ServerLevelLinkedServerLogins, + ServerLevelServerAudits, + ServerLevelCryptographicProviders, + ServerLevelCredentials, + ServerLevelServerRoles, + ServerLevelLogins, + ServerLevelEventSessions, + ServerLevelServerAuditSpecifications, + ServerLevelEventNotifications, + ServerLevelErrorMessages, + ServerLevelServerTriggers, + ServerLevelLinkedServers, + ServerLevelEndpoints, + SystemScalarValuedFunctions, + SystemTableValuedFunctions, + SystemFunctions, + DacInstancesFolder, + Tables, + Views, + Synonyms, + Programmability, + ServiceBroker, + Storage, + Security, + SystemTables, + FileTables, + SystemViews, + StoredProcedures, + Functions, + ExtendedStoredProcedures, + DatabaseTriggers, + Defaults, + Rules, + Types, + Assemblies, + MessageTypes, + Contracts, + Queues, + Services, + Routes, + DatabaseAndQueueEventNotifications, + RemoteServiceBindings, + BrokerPriorities, + FileGroups, + FullTextCatalogs, + FullTextStopLists, + SqlLogFiles, + PartitionFunctions, + PartitionSchemes, + SearchPropertyLists, + Users, + Roles, + Schemas, + AsymmetricKeys, + Certificates, + SymmetricKeys, + DatabaseEncryptionKeys, + MasterKeys, + Signatures, + DatabaseAuditSpecifications, + Columns, + Keys, + Constraints, + Triggers, + Indexes, + Statistics, + TableValuedFunctions, + ScalarValuedFunctions, + AggregateFunctions, + SystemDataTypes, + UserDefinedDataTypes, + UserDefinedTableTypes, + UserDefinedTypes, + XmlSchemaCollections, + SystemExactNumerics, + SystemApproximateNumerics, + SystemDateAndTimes, + SystemCharacterStrings, + SystemUnicodeCharacterStrings, + SystemBinaryStrings, + SystemOtherDataTypes, + SystemClrDataTypes, + SystemSpatialDataTypes, + UserDefinedTableTypeColumns, + UserDefinedTableTypeKeys, + UserDefinedTableTypeConstraints, + SystemStoredProcedures, + StoredProcedureParameters, + TableValuedFunctionParameters, + ScalarValuedFunctionParameters, + AggregateFunctionParameters, + DatabaseRoles, + ApplicationRoles, + FileGroupFiles, + SystemMessageTypes, + SystemContracts, + SystemServices, + SystemQueues, + Sequences, + SecurityPolicies, + DatabaseScopedCredentials, + ExternalTables, + ExternalResource, + ExternalDataSources, + ExternalFileFormats, + ExternalTable, + AlwaysEncryptedKeys, + ColumnMasterKeys, + ColumnEncryptionKeys + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs new file mode 100644 index 0000000000..b3be72d56a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNode.cs @@ -0,0 +1,539 @@ +// +// 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.Collections.ObjectModel; +using System.Diagnostics; +using System.Globalization; +using System.Threading; +using System.Linq; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + /// + /// Base class for elements in the object explorer tree. Provides common methods for tree navigation + /// and other core functionality + /// + public class TreeNode : IComparable + { + private NodeObservableCollection children = new NodeObservableCollection(); + private TreeNode parent; + private string nodePath; + private string label; + private string nodePathName; + public const char PathPartSeperator = '/'; + + /// + /// Object metadata + /// + public DataSourceObjectMetadata ObjectMetadata { get; set; } + + /// + /// The DataSource this tree node is representing + /// + public IDataSource DataSource { get; set; } + + /// + /// Constructor with no required inputs + /// + public TreeNode(IDataSource dataSource, DataSourceObjectMetadata objectMetadata) + { + DataSource = dataSource; + ObjectMetadata = objectMetadata; + NodeValue = objectMetadata.Name; + } + + /// + /// Constructor that accepts a label to identify the node + /// + /// Label identifying the node + public TreeNode(string value, IDataSource dataSource, DataSourceObjectMetadata objectMetadata) + : this(dataSource, objectMetadata) + { + // We intentionally do not valid this being null or empty since + // some nodes may need to set it + NodeValue = value; + } + + private object buildingMetadataLock = new object(); + + /// + /// Event which tells if MetadataProvider is built fully or not + /// + public object BuildingMetadataLock + { + get { return this.buildingMetadataLock; } + } + + /// + /// Value describing this node + /// + public string NodeValue { get; set; } + + /// + /// The name of this object as included in its node path + /// + public string NodePathName { + get + { + if (string.IsNullOrEmpty(nodePathName)) + { + return NodeValue; + } + return nodePathName; + } + set + { + nodePathName = value; + } + } + + /// + /// The type of the node - for example Server, Database, Folder, Table + /// + public string NodeType { get; set; } + + /// + // True if the node includes system object + /// + public bool IsSystemObject { get; set; } + + /// + /// Enum defining the type of the node - for example Server, Database, Folder, Table + /// + public NodeTypes NodeTypeId { get; set; } + + /// + /// Node Sub type - for example a key can have type as "Key" and sub type as "PrimaryKey" + /// + public string NodeSubType { get; set; } + + /// + /// Error message returned from the engine for a object explorer node failure reason, if any. + /// + public string ErrorMessage { get; set; } + + /// + /// Node status - for example login can be disabled/enabled + /// + public string NodeStatus { get; set; } + + /// + /// Label to display to the user, describing this node. + /// If not explicitly set this will fall back to the but + /// for many nodes such as the server, the display label will be different + /// to the value. + /// + public string Label { + get + { + if(label == null) + { + return NodeValue; + } + return label; + } + set + { + label = value; + } + } + + /// + /// Is this a leaf node (in which case no children can be generated) or + /// is it expandable? + /// + public bool IsAlwaysLeaf { get; set; } + + /// + /// Message to show if this Node is in an error state. This indicates + /// that children could be retrieved + /// + public string ErrorStateMessage { get; set; } + + /// + /// Parent of this node + /// + public TreeNode Parent + { + get + { + return parent; + } + set + { + parent = value; + // Reset the node path since it's no longer valid + nodePath = null; + } + } + + /// + /// Path identifying this node: for example a table will be at ["server", "database", "tables", "tableName"]. + /// This enables rapid navigation of the tree without the need for a global registry of elements. + /// The path functions as a unique ID and is used to disambiguate the node when sending requests for expansion. + /// A common ID is needed since processes do not share address space and need a unique identifier + /// + public string GetNodePath() + { + if (nodePath == null) + { + GenerateNodePath(); + } + return nodePath; + } + + private void GenerateNodePath() + { + string path = ""; + ObjectExplorerUtils.VisitChildAndParents(this, node => + { + if (string.IsNullOrEmpty(node.NodeValue)) + { + // Hit a node with no NodeValue. This indicates we need to stop traversing + return false; + } + // Otherwise add this value to the beginning of the path and keep iterating up + path = string.Format(CultureInfo.InvariantCulture, + "{0}{1}{2}", node.NodePathName, string.IsNullOrEmpty(path) ? "" : PathPartSeperator.ToString(), path); + return true; + }); + nodePath = path; + } + + public TreeNode FindNodeByPath(string path, bool expandIfNeeded = false) + { + TreeNode nodeForPath = ObjectExplorerUtils.FindNode(this, node => + { + return node.GetNodePath() == path; + }, nodeToFilter => + { + return path.StartsWith(nodeToFilter.GetNodePath()); + }, expandIfNeeded); + + return nodeForPath; + } + + /// + /// Converts to a object for serialization with just the relevant properties + /// needed to identify the node + /// + /// + public NodeInfo ToNodeInfo() + { + return new NodeInfo() + { + IsLeaf = this.IsAlwaysLeaf, + Label = this.Label, + NodePath = this.GetNodePath(), + NodeType = this.NodeType, + Metadata = this.ObjectMetadata, + NodeStatus = this.NodeStatus, + NodeSubType = this.NodeSubType, + ErrorMessage = this.ErrorMessage + }; + } + + /// + /// Expands this node and returns its children + /// + /// Children as an IList. This is the raw children collection, not a copy + public IList Expand(string name, CancellationToken cancellationToken) + { + // TODO consider why solution explorer has separate Children and Items options + if (children.IsInitialized) + { + return children; + } + PopulateChildren(false, name, cancellationToken); + return children; + } + + /// + /// Expands this node and returns its children + /// + /// Children as an IList. This is the raw children collection, not a copy + public IList Expand(CancellationToken cancellationToken) + { + return Expand(null, cancellationToken); + } + + /// + /// Refresh this node and returns its children + /// + /// Children as an IList. This is the raw children collection, not a copy + public virtual IList Refresh(CancellationToken cancellationToken) + { + // TODO consider why solution explorer has separate Children and Items options + PopulateChildren(true, null, cancellationToken); + return children; + } + + /// + /// Gets a readonly view of the currently defined children for this node. + /// This does not expand the node at all + /// Since the tree needs to keep track of parent relationships, directly + /// adding to the list is not supported. + /// + /// containing all children for this node + public IList GetChildren() + { + return new ReadOnlyCollection(children); + } + + /// + /// Adds a child to the list of children under this node + /// + /// + public void AddChild(TreeNode newChild) + { + Validate.IsNotNull(nameof(newChild), newChild); + children.Add(newChild); + newChild.Parent = this; + } + + /// + /// Optional context to help with lookup of children + /// + public virtual object GetContext() + { + return null; + } + + /// + /// Helper method to convert context to expected format + /// + /// Type to convert to + /// context as expected type of null if it doesn't match + public T GetContextAs() + where T : class + { + return GetContext() as T; + } + + public T ParentAs() + where T : TreeNode + { + return Parent as T; + } + + protected virtual void PopulateChildren(bool refresh, string name, CancellationToken cancellationToken) + { + Logger.Write(TraceEventType.Verbose, string.Format(CultureInfo.InvariantCulture, "Populating oe node :{0}", this.GetNodePath())); + Debug.Assert(IsAlwaysLeaf == false); + + QueryContext context = this.GetContextAs(); + + if (children.IsPopulating || context == null) + { + return; + } + + children.Clear(); + BeginChildrenInit(); + + try + { + ErrorMessage = null; + cancellationToken.ThrowIfCancellationRequested(); + IEnumerable items = ExpandChildren(this, refresh, name, true, cancellationToken); + if (items != null) + { + foreach (TreeNode item in items) + { + children.Add(item); + item.Parent = this; + } + } + } + catch (Exception ex) + { + string error = string.Format(CultureInfo.InvariantCulture, "Failed populating oe children. error:{0} inner:{1} stacktrace:{2}", + ex.Message, ex.InnerException != null ? ex.InnerException.Message : "", ex.StackTrace); + Logger.Write(TraceEventType.Error, error); + ErrorMessage = ex.Message; + } + finally + { + EndChildrenInit(); + } + } + + protected IEnumerable ExpandChildren(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken) + { + List allChildren = new List(); + + try + { + OnExpandPopulateNonFolders(allChildren, parent, refresh, name, cancellationToken); + } + catch(Exception ex) + { + string error = string.Format(CultureInfo.InvariantCulture, "Failed expanding oe children. parent:{0} error:{1} inner:{2} stacktrace:{3}", + parent != null ? parent.GetNodePath() : "", ex.Message, ex.InnerException != null ? ex.InnerException.Message : "", ex.StackTrace); + Logger.Write(TraceEventType.Error, error); + throw ex; + } + finally + { + } + return allChildren; + } + + /// + /// Populates any non-folder nodes such as specific items in the tree. + /// + /// List to which nodes should be added + /// Parent the nodes are being added to + private void OnExpandPopulateNonFolders(IList allChildren, TreeNode parent, bool refresh, string name, CancellationToken cancellationToken) + { + Logger.Write(TraceEventType.Verbose, string.Format(CultureInfo.InvariantCulture, "child factory parent :{0}", parent.GetNodePath())); + + cancellationToken.ThrowIfCancellationRequested(); + + try + { + var objectMetadataList = Enumerable.Empty(); + + if (parent.DataSource != null) + { + objectMetadataList = parent.DataSource.GetChildObjects(parent.ObjectMetadata); + } + + foreach (var objectMetadata in objectMetadataList) + { + cancellationToken.ThrowIfCancellationRequested(); + if (objectMetadata == null) + { + Logger.Write(TraceEventType.Error, "kustoMetadata should not be null"); + } + TreeNode childNode = CreateChild(parent, objectMetadata); + if (childNode != null) + { + allChildren.Add(childNode); + } + } + + } + catch (Exception ex) + { + string error = string.Format(CultureInfo.InvariantCulture, "Failed getting child objects. parent:{0} error:{1} inner:{2} stacktrace:{3}", + parent != null ? parent.GetNodePath() : "", ex.Message, ex.InnerException != null ? ex.InnerException.Message : "", ex.StackTrace); + Logger.Write(TraceEventType.Error, error); + throw ex; + } + } + + /// + /// The glue between the DataSource and the Object Explorer models. Creates the right tree node for each data source type + /// + protected TreeNode CreateChild(TreeNode parent, DataSourceObjectMetadata childMetadata) + { + ValidationUtils.IsNotNull(parent, nameof(parent)); + ValidationUtils.IsNotNull(childMetadata, nameof(childMetadata)); + + switch(childMetadata.MetadataType) + { + case DataSourceMetadataType.Database: + return new DataSourceTreeNode(parent.DataSource, childMetadata) { + Parent = parent as ServerNode, + NodeType = "Database", + NodeTypeId = NodeTypes.Database + }; + + case DataSourceMetadataType.Table: + return new DataSourceTreeNode(parent.DataSource, childMetadata) { + NodeType = "Table", + NodeTypeId = NodeTypes.Table + }; + + case DataSourceMetadataType.Column: + return new DataSourceTreeNode(parent.DataSource, childMetadata) { + IsAlwaysLeaf = true, + NodeType = "Column", + SortPriority = DataSourceTreeNode.NextSortPriority + }; + + case DataSourceMetadataType.Folder: + return new DataSourceTreeNode(parent.DataSource, childMetadata) + { + Parent = parent, + NodeType = "Folder", + NodeTypeId = NodeTypes.Folder + }; + + case DataSourceMetadataType.Function: + return new DataSourceTreeNode(parent.DataSource, childMetadata) + { + parent = parent, + NodeType = "Function", + NodeTypeId = NodeTypes.Functions, + IsAlwaysLeaf = true, + }; + + default: + throw new ArgumentException($"Unexpected type {childMetadata.MetadataType}."); + } + } + + public void BeginChildrenInit() + { + children.BeginInit(); + } + + public void EndChildrenInit() + { + children.EndInit(); + // TODO consider use of deferred children and if it's necessary + // children.EndInit(this, ref deferredChildren); + } + + + /// + /// Sort Priority to help when ordering elements in the tree + /// + public int? SortPriority { get; set; } + + protected virtual int CompareSamePriorities(TreeNode thisItem, TreeNode otherItem) + { + return string.Compare(thisItem.NodeValue, otherItem.NodeValue, StringComparison.OrdinalIgnoreCase); + } + + public int CompareTo(TreeNode other) + { + + if (!this.SortPriority.HasValue && + !other.SortPriority.HasValue) + { + return CompareSamePriorities(this, other); + } + + if (this.SortPriority.HasValue && + !other.SortPriority.HasValue) + { + return -1; // this is above other + } + if (!this.SortPriority.HasValue) + { + return 1; // this is below other + } + + // Both have sort priority + int priDiff = this.SortPriority.Value - other.SortPriority.Value; + if (priDiff < 0) + return -1; // this is below other + if (priDiff == 0) + return 0; + return 1; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNodeWithContext.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNodeWithContext.cs new file mode 100644 index 0000000000..4844b45e5c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/Nodes/TreeNodeWithContext.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes +{ + public class TreeNodeWithContext + { + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs new file mode 100644 index 0000000000..b16677cde9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerService.cs @@ -0,0 +1,839 @@ +// +// 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.Concurrent; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Composition; +using System.Diagnostics; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlServer.Management.Common; // For ServerConnection +using Microsoft.SqlTools.Extensibility; +using Microsoft.SqlTools.Hosting; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.LanguageServices; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Contracts; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.Workspace; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer +{ + /// + /// A Service to support querying server and database information as an Object Explorer tree. + /// The APIs used for this are modeled closely on the VSCode TreeExplorerNodeProvider API. + /// + [Export(typeof(IHostedService))] + public class ObjectExplorerService : HostedService, IComposableService, IHostedService, IDisposable + { + internal const string uriPrefix = "objectexplorer://"; + + // Instance of the connection service, used to get the connection info for a given owner URI + private ConnectionService connectionService; + private IProtocolEndpoint serviceHost; + private ConcurrentDictionary sessionMap; + private readonly Lazy>> applicableNodeChildFactories; + private IMultiServiceProvider serviceProvider; + private ConnectedBindingQueue bindingQueue = new ConnectedBindingQueue(needsMetadata: false); + private string connectionName = "ObjectExplorer"; + + /// + /// This timeout limits the amount of time that object explorer tasks can take to complete + /// + private ObjectExplorerSettings settings; + + /// + /// Singleton constructor + /// + public ObjectExplorerService() + { + sessionMap = new ConcurrentDictionary(); + applicableNodeChildFactories = new Lazy>>(() => PopulateFactories()); + NodePathGenerator.Initialize(); + } + + internal ConnectedBindingQueue ConnectedBindingQueue + { + get + { + return bindingQueue; + } + set + { + this.bindingQueue = value; + } + } + + /// + /// Internal for testing only + /// + internal ObjectExplorerService(ExtensionServiceProvider serviceProvider) + : this() + { + SetServiceProvider(serviceProvider); + } + + private Dictionary> ApplicableNodeChildFactories + { + get + { + return applicableNodeChildFactories.Value; + } + } + + /// + /// Returns the session ids + /// + internal IReadOnlyCollection SessionIds + { + get + { + return new ReadOnlyCollection(sessionMap.Keys.ToList()); + } + } + + /// + /// As an , this will be set whenever the service is initialized + /// via an + /// + /// + public override void SetServiceProvider(IMultiServiceProvider provider) + { + Validate.IsNotNull(nameof(provider), provider); + serviceProvider = provider; + connectionService = provider.GetService(); + try + { + connectionService.RegisterConnectedQueue(connectionName, bindingQueue); + + } + catch(Exception ex) + { + Logger.Write(TraceEventType.Error, ex.Message); + } + } + + /// + /// Initializes the service with the service host and registers request handlers. + /// + /// The service host instance to register with + public override void InitializeService(IProtocolEndpoint serviceHost) + { + Logger.Write(TraceEventType.Verbose, "ObjectExplorer service initialized"); + this.serviceHost = serviceHost; + + this.ConnectedBindingQueue.OnUnhandledException += OnUnhandledException; + + // Register handlers for requests + serviceHost.SetRequestHandler(CreateSessionRequest.Type, HandleCreateSessionRequest); + serviceHost.SetRequestHandler(ExpandRequest.Type, HandleExpandRequest); + serviceHost.SetRequestHandler(RefreshRequest.Type, HandleRefreshRequest); + serviceHost.SetRequestHandler(CloseSessionRequest.Type, HandleCloseSessionRequest); + serviceHost.SetRequestHandler(FindNodesRequest.Type, HandleFindNodesRequest); + WorkspaceService workspaceService = WorkspaceService; + if (workspaceService != null) + { + workspaceService.RegisterConfigChangeCallback(HandleDidChangeConfigurationNotification); + } + + } + + /// + /// Gets the workspace service. Note: should handle case where this is null in cases where unit tests do not set this up + /// + private WorkspaceService WorkspaceService + { + get { return serviceProvider.GetService>(); } + } + + + /// + /// Ensure formatter settings are always up to date + /// + public Task HandleDidChangeConfigurationNotification( + SqlToolsSettings newSettings, + SqlToolsSettings oldSettings, + EventContext eventContext) + { + // update the current settings to reflect any changes (assuming formatter settings exist) + settings = newSettings?.SqlTools?.ObjectExplorer ?? settings; + return Task.FromResult(true); + } + + + internal async Task HandleCreateSessionRequest(ConnectionDetails connectionDetails, RequestContext context) + { + try + { + Logger.Write(TraceEventType.Verbose, "HandleCreateSessionRequest"); + Func> doCreateSession = async () => + { + Validate.IsNotNull(nameof(connectionDetails), connectionDetails); + Validate.IsNotNull(nameof(context), context); + return await Task.Factory.StartNew(() => + { + string uri = GenerateUri(connectionDetails); + + return new CreateSessionResponse { SessionId = uri }; + }); + }; + + CreateSessionResponse response = await HandleRequestAsync(doCreateSession, context, "HandleCreateSessionRequest"); + if (response != null) + { + RunCreateSessionTask(connectionDetails, response.SessionId); + } + } + catch (Exception ex) + { + await context.SendError(ex.ToString()); + } + + } + + internal async Task HandleExpandRequest(ExpandParams expandParams, RequestContext context) + { + Logger.Write(TraceEventType.Verbose, "HandleExpandRequest"); + + Func> expandNode = async () => + { + Validate.IsNotNull(nameof(expandParams), expandParams); + Validate.IsNotNull(nameof(context), context); + + string uri = expandParams.SessionId; + ObjectExplorerSession session = null; + if (!sessionMap.TryGetValue(uri, out session)) + { + Logger.Write(TraceEventType.Verbose, $"Cannot expand object explorer node. Couldn't find session for uri. {uri} "); + await serviceHost.SendEvent(ExpandCompleteNotification.Type, new ExpandResponse + { + SessionId = expandParams.SessionId, + NodePath = expandParams.NodePath, + ErrorMessage = $"Couldn't find session for session: {uri}" + }); + return false; + } + else + { + RunExpandTask(session, expandParams); + return true; + } + }; + await HandleRequestAsync(expandNode, context, "HandleExpandRequest"); + } + + internal async Task HandleRefreshRequest(RefreshParams refreshParams, RequestContext context) + { + try + { + Logger.Write(TraceEventType.Verbose, "HandleRefreshRequest"); + Validate.IsNotNull(nameof(refreshParams), refreshParams); + Validate.IsNotNull(nameof(context), context); + + string uri = refreshParams.SessionId; + ObjectExplorerSession session = null; + if (!sessionMap.TryGetValue(uri, out session)) + { + Logger.Write(TraceEventType.Verbose, $"Cannot expand object explorer node. Couldn't find session for uri. {uri} "); + await serviceHost.SendEvent(ExpandCompleteNotification.Type, new ExpandResponse + { + SessionId = refreshParams.SessionId, + NodePath = refreshParams.NodePath, + ErrorMessage = $"Couldn't find session for session: {uri}" + }); + } + else + { + RunExpandTask(session, refreshParams, true); + } + await context.SendResult(true); + } + catch (Exception ex) + { + await context.SendError(ex.ToString()); + } + } + + internal async Task HandleCloseSessionRequest(CloseSessionParams closeSessionParams, RequestContext context) + { + + Logger.Write(TraceEventType.Verbose, "HandleCloseSessionRequest"); + Func> closeSession = () => + { + Validate.IsNotNull(nameof(closeSessionParams), closeSessionParams); + Validate.IsNotNull(nameof(context), context); + return Task.Factory.StartNew(() => + { + string uri = closeSessionParams.SessionId; + ObjectExplorerSession session = null; + bool success = false; + if (!sessionMap.TryGetValue(uri, out session)) + { + Logger.Write(TraceEventType.Verbose, $"Cannot close object explorer session. Couldn't find session for uri. {uri} "); + } + + if (session != null) + { + // refresh the nodes for given node path + CloseSession(uri); + success = true; + } + + var response = new CloseSessionResponse() { Success = success, SessionId = uri }; + return response; + }); + }; + + await HandleRequestAsync(closeSession, context, "HandleCloseSessionRequest"); + } + + internal async Task HandleFindNodesRequest(FindNodesParams findNodesParams, RequestContext context) + { + var foundNodes = FindNodes(findNodesParams.SessionId, findNodesParams.Type, findNodesParams.Schema, findNodesParams.Name, findNodesParams.Database, findNodesParams.ParentObjectNames); + if (foundNodes == null) + { + foundNodes = new List(); + } + await context.SendResult(new FindNodesResponse { Nodes = foundNodes.Select(node => node.ToNodeInfo()).ToList() }); + } + + internal void CloseSession(string uri) + { + ObjectExplorerSession session; + if (sessionMap.TryGetValue(uri, out session)) + { + // Remove the session from active sessions and disconnect + if(sessionMap.TryRemove(session.Uri, out session)) + { + if (session != null && session.ConnectionInfo != null) + { + bindingQueue.RemoveBindigContext(session.ConnectionInfo); + } + } + connectionService.Disconnect(new DisconnectParams() + { + OwnerUri = uri + }); + } + } + + private void RunCreateSessionTask(ConnectionDetails connectionDetails, string uri) + { + Logger.Write(TraceEventType.Information, "Creating OE session"); + CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); + if (connectionDetails != null && !string.IsNullOrEmpty(uri)) + { + Task task = CreateSessionAsync(connectionDetails, uri, cancellationTokenSource.Token); + CreateSessionTask = task; + Task.Run(async () => + { + ObjectExplorerTaskResult result = await RunTaskWithTimeout(task, + settings?.CreateSessionTimeout ?? ObjectExplorerSettings.DefaultCreateSessionTimeout); + + if (result != null && !result.IsCompleted) + { + cancellationTokenSource.Cancel(); + SessionCreatedParameters response = new SessionCreatedParameters + { + Success = false, + SessionId = uri, + ErrorMessage = result.Exception != null ? result.Exception.Message : $"Failed to create session for session id {uri}" + + }; + await serviceHost.SendEvent(CreateSessionCompleteNotification.Type, response); + } + return result; + }).ContinueWithOnFaulted(null); + } + } + + /// + /// For tests only + /// + internal Task CreateSessionTask + { + get; + private set; + } + + private async Task CreateSessionAsync(ConnectionDetails connectionDetails, string uri, CancellationToken cancellationToken) + { + ObjectExplorerSession session; + if (!sessionMap.TryGetValue(uri, out session)) + { + // Establish a connection to the specified server/database + session = await DoCreateSession(connectionDetails, uri); + } + + SessionCreatedParameters response; + if (session != null && !cancellationToken.IsCancellationRequested) + { + // Else we have a session available, response with existing session information + response = new SessionCreatedParameters + { + Success = true, + RootNode = session.Root.ToNodeInfo(), + SessionId = uri, + ErrorMessage = session.ErrorMessage + }; + await serviceHost.SendEvent(CreateSessionCompleteNotification.Type, response); + return response; + } + return null; + + } + + internal async Task ExpandNode(ObjectExplorerSession session, string nodePath, bool forceRefresh = false) + { + return await Task.Factory.StartNew(() => + { + return QueueExpandNodeRequest(session, nodePath, forceRefresh); + }); + } + internal ExpandResponse QueueExpandNodeRequest(ObjectExplorerSession session, string nodePath, bool forceRefresh = false) + { + NodeInfo[] nodes = null; + TreeNode node = session.Root.FindNodeByPath(nodePath); + ExpandResponse response = null; + + // This node was likely returned from a different node provider. Ignore expansion and return an empty array + // since we don't need to add any nodes under this section of the tree. + if (node == null) + { + response = new ExpandResponse { Nodes = new NodeInfo[] { }, ErrorMessage = string.Empty, SessionId = session.Uri, NodePath = nodePath }; + response.Nodes = new NodeInfo[0]; + return response; + } + else + { + response = new ExpandResponse { Nodes = new NodeInfo[] { }, ErrorMessage = node.ErrorMessage, SessionId = session.Uri, NodePath = nodePath }; + } + + if (node != null && Monitor.TryEnter(node.BuildingMetadataLock, LanguageService.OnConnectionWaitTimeout)) + { + try + { + int timeout = (int)TimeSpan.FromSeconds(settings?.ExpandTimeout ?? ObjectExplorerSettings.DefaultExpandTimeout).TotalMilliseconds; + QueueItem queueItem = bindingQueue.QueueBindingOperation( + key: bindingQueue.AddConnectionContext(session.ConnectionInfo, connectionName), + bindingTimeout: timeout, + waitForLockTimeout: timeout, + bindOperation: (bindingContext, cancelToken) => + { + if (forceRefresh) + { + nodes = node.Refresh(cancelToken).Select(x => x.ToNodeInfo()).ToArray(); + } + else + { + nodes = node.Expand(cancelToken).Select(x => x.ToNodeInfo()).ToArray(); + } + response.Nodes = nodes; + response.ErrorMessage = node.ErrorMessage; + try + { + // SMO changes the database when getting sql objects. Make sure the database is changed back to the original one + if (bindingContext.ServerConnection.CurrentDatabase != bindingContext.ServerConnection.DatabaseName) + { + bindingContext.ServerConnection.SqlConnectionObject.ChangeDatabase(bindingContext.ServerConnection.DatabaseName); + } + } + catch(Exception ex) + { + Logger.Write(TraceEventType.Warning, $"Failed to change the database in OE connection. error: {ex.Message}"); + // We should just try to change the connection. If it fails, there's not much we can do + } + return response; + }); + + queueItem.ItemProcessed.WaitOne(); + if (queueItem.GetResultAsT() != null) + { + response = queueItem.GetResultAsT(); + } + } + catch + { + } + finally + { + Monitor.Exit(node.BuildingMetadataLock); + } + } + return response; + } + + /// + /// Establishes a new session and stores its information + /// + /// object if successful, null if unsuccessful + internal async Task DoCreateSession(ConnectionDetails connectionDetails, string uri) + { + try + { + ObjectExplorerSession session = null; + connectionDetails.PersistSecurityInfo = true; + ConnectParams connectParams = new ConnectParams() { OwnerUri = uri, Connection = connectionDetails, Type = Connection.ConnectionType.ObjectExplorer }; + bool isDefaultOrSystemDatabase = DatabaseUtils.IsSystemDatabaseConnection(connectionDetails.DatabaseName) || string.IsNullOrWhiteSpace(connectionDetails.DatabaseDisplayName); + + ConnectionInfo connectionInfo; + ConnectionCompleteParams connectionResult = await Connect(connectParams, uri); + if (!connectionService.TryFindConnection(uri, out connectionInfo)) + { + return null; + } + + if (connectionResult == null) + { + // Connection failed and notification is already sent + return null; + } + + int timeout = (int)TimeSpan.FromSeconds(settings?.CreateSessionTimeout ?? ObjectExplorerSettings.DefaultCreateSessionTimeout).TotalMilliseconds; + QueueItem queueItem = bindingQueue.QueueBindingOperation( + key: bindingQueue.AddConnectionContext(connectionInfo, connectionName), + bindingTimeout: timeout, + waitForLockTimeout: timeout, + bindOperation: (bindingContext, cancelToken) => + { + session = ObjectExplorerSession.CreateSession(connectionResult, serviceProvider, bindingContext.ServerConnection, bindingContext.DataSource, isDefaultOrSystemDatabase); + session.ConnectionInfo = connectionInfo; + + sessionMap.AddOrUpdate(uri, session, (key, oldSession) => session); + return session; + }); + + queueItem.ItemProcessed.WaitOne(); + if (queueItem.GetResultAsT() != null) + { + session = queueItem.GetResultAsT(); + } + return session; + } + catch(Exception ex) + { + await SendSessionFailedNotification(uri, ex.Message); + return null; + } + } + + private async Task Connect(ConnectParams connectParams, string uri) + { + string connectionErrorMessage = string.Empty; + try + { + // open connection based on request details + ConnectionCompleteParams result = await connectionService.Connect(connectParams); + connectionErrorMessage = result != null ? $"{result.Messages} error code:{result.ErrorNumber}" : string.Empty; + if (result != null && !string.IsNullOrEmpty(result.ConnectionId)) + { + return result; + } + else + { + await SendSessionFailedNotification(uri, result.ErrorMessage); + return null; + } + + } + catch (Exception ex) + { + await SendSessionFailedNotification(uri, ex.ToString()); + return null; + } + } + + private async Task SendSessionFailedNotification(string uri, string errorMessage) + { + Logger.Write(TraceEventType.Warning, $"Failed To create OE session: {errorMessage}"); + SessionCreatedParameters result = new SessionCreatedParameters() + { + Success = false, + ErrorMessage = errorMessage, + SessionId = uri + }; + await serviceHost.SendEvent(CreateSessionCompleteNotification.Type, result); + } + + internal async Task SendSessionDisconnectedNotification(string uri, bool success, string errorMessage) + { + Logger.Write(TraceEventType.Information, $"OE session disconnected: {errorMessage}"); + SessionDisconnectedParameters result = new SessionDisconnectedParameters() + { + Success = success, + ErrorMessage = errorMessage, + SessionId = uri + }; + await serviceHost.SendEvent(SessionDisconnectedNotification.Type, result); + } + + private void RunExpandTask(ObjectExplorerSession session, ExpandParams expandParams, bool forceRefresh = false) + { + CancellationTokenSource cancellationTokenSource = new CancellationTokenSource(); + Task task = ExpandNodeAsync(session, expandParams, cancellationTokenSource.Token, forceRefresh); + ExpandTask = task; + Task.Run(async () => + { + ObjectExplorerTaskResult result = await RunTaskWithTimeout(task, + settings?.ExpandTimeout ?? ObjectExplorerSettings.DefaultExpandTimeout); + + if (result != null && !result.IsCompleted) + { + cancellationTokenSource.Cancel(); + ExpandResponse response = CreateExpandResponse(session, expandParams); + response.ErrorMessage = result.Exception != null ? result.Exception.Message: $"Failed to expand node: {expandParams.NodePath} in session {session.Uri}"; + await serviceHost.SendEvent(ExpandCompleteNotification.Type, response); + } + return result; + }).ContinueWithOnFaulted(null); + } + + private async Task RunTaskWithTimeout(Task task, int timeoutInSec) + { + ObjectExplorerTaskResult result = new ObjectExplorerTaskResult(); + TimeSpan timeout = TimeSpan.FromSeconds(timeoutInSec); + await Task.WhenAny(task, Task.Delay(timeout)); + result.IsCompleted = task.IsCompleted; + if(task.Exception != null) + { + result.Exception = task.Exception; + } + else if (!task.IsCompleted) + { + result.Exception = new TimeoutException($"Object Explorer task didn't complete within {timeoutInSec} seconds."); + } + return result; + } + + /// + /// For tests only + /// + internal Task ExpandTask + { + get; + set; + } + + private async Task ExpandNodeAsync(ObjectExplorerSession session, ExpandParams expandParams, CancellationToken cancellationToken, bool forceRefresh = false) + { + ExpandResponse response = null; + response = await ExpandNode(session, expandParams.NodePath, forceRefresh); + if (cancellationToken.IsCancellationRequested) + { + Logger.Write(TraceEventType.Verbose, "OE expand canceled"); + } + else + { + await serviceHost.SendEvent(ExpandCompleteNotification.Type, response); + } + } + + private ExpandResponse CreateExpandResponse(ObjectExplorerSession session, ExpandParams expandParams) + { + return new ExpandResponse() { SessionId = session.Uri, NodePath = expandParams.NodePath }; + } + + /// + /// Generates a URI for object explorer using a similar pattern to Mongo DB (which has URI-based database definition) + /// as this should ensure uniqueness + /// + /// + /// string representing a URI + /// Internal for testing purposes only + internal static string GenerateUri(ConnectionDetails details) + { + return ConnectedBindingQueue.GetConnectionContextKey(details); + } + + public IEnumerable GetApplicableChildFactories(TreeNode item) + { + if (ApplicableNodeChildFactories != null) + { + HashSet applicableFactories; + if (ApplicableNodeChildFactories.TryGetValue(item.NodeTypeId.ToString(), out applicableFactories)) + { + return applicableFactories; + } + } + return null; + } + + internal Dictionary> PopulateFactories() + { + VerifyServicesInitialized(); + + var childFactories = new Dictionary>(); + // Create our list of all NodeType to ChildFactory objects so we can expand appropriately + foreach (var factory in serviceProvider.GetServices()) + { + var parents = factory.ApplicableParents(); + if (parents != null) + { + foreach (var parent in parents) + { + AddToApplicableChildFactories(childFactories, factory, parent); + } + } + } + return childFactories; + } + + private void VerifyServicesInitialized() + { + if (serviceProvider == null) + { + throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet); + } + if (connectionService == null) + { + throw new InvalidOperationException(SqlTools.Hosting.SR.ServiceProviderNotSet); + } + } + + private static void AddToApplicableChildFactories(Dictionary> childFactories, ChildFactory factory, string parent) + { + HashSet applicableFactories; + if (!childFactories.TryGetValue(parent, out applicableFactories)) + { + applicableFactories = new HashSet(); + childFactories[parent] = applicableFactories; + } + applicableFactories.Add(factory); + } + + /// + /// Find all tree nodes matching the given node information + /// + /// The ID of the object explorer session to find nodes for + /// The requested node type + /// The schema for the requested object, or null if not applicable + /// The name of the requested object + /// The name of the database containing the requested object, or null if not applicable + /// The name of any other parent objects in the object explorer tree, from highest in the tree to lowest + /// A list of nodes matching the given information, or an empty list if no nodes match + public List FindNodes(string sessionId, string typeName, string schema, string name, string databaseName, List parentNames = null) + { + var nodes = new List(); + var oeSession = sessionMap.GetValueOrDefault(sessionId); + if (oeSession == null) + { + return nodes; + } + + var outputPaths = NodePathGenerator.FindNodePaths(oeSession, typeName, schema, name, databaseName, parentNames); + foreach (var outputPath in outputPaths) + { + var treeNode = oeSession.Root.FindNodeByPath(outputPath, true); + if (treeNode != null) + { + nodes.Add(treeNode); + } + } + return nodes; + } + + internal class ObjectExplorerTaskResult + { + public bool IsCompleted { get; set; } + public Exception Exception { get; set; } + } + + public void Dispose() + { + if (bindingQueue != null) + { + bindingQueue.OnUnhandledException -= OnUnhandledException; + bindingQueue.Dispose(); + } + } + + private async void OnUnhandledException(string queueKey, Exception ex) + { + string sessionUri = LookupUriFromQueueKey(queueKey); + if (!string.IsNullOrWhiteSpace(sessionUri)) + { + await SendSessionDisconnectedNotification(uri: sessionUri, success: false, errorMessage: ex.ToString()); + } + } + + private string LookupUriFromQueueKey(string queueKey) + { + foreach (var session in this.sessionMap.Values) + { + var connInfo = session.ConnectionInfo; + if (connInfo != null) + { + string currentKey = ConnectedBindingQueue.GetConnectionContextKey(connInfo.ConnectionDetails); + if (queueKey == currentKey) + { + return session.Uri; + } + } + } + return string.Empty; + } + + internal class ObjectExplorerSession + { + private ConnectionService connectionService; + private IMultiServiceProvider serviceProvider; + + // TODO decide whether a cache is needed to handle lookups in elements with a large # children + //private const int Cachesize = 10000; + //private Cache cache; + + public ObjectExplorerSession(string uri, TreeNode root, IMultiServiceProvider serviceProvider, ConnectionService connectionService) + { + Validate.IsNotNullOrEmptyString("uri", uri); + Validate.IsNotNull("root", root); + Uri = uri; + Root = root; + this.serviceProvider = serviceProvider; + this.connectionService = connectionService; + } + + public string Uri { get; private set; } + public TreeNode Root { get; private set; } + + public ConnectionInfo ConnectionInfo { get; set; } + + public string ErrorMessage { get; set; } + + public static ObjectExplorerSession CreateSession(ConnectionCompleteParams response, IMultiServiceProvider serviceProvider, ServerConnection serverConnection, IDataSource dataSource, bool isDefaultOrSystemDatabase) + { + DataSourceObjectMetadata objectMetadata = DataSourceFactory.CreateClusterMetadata(dataSource.ClusterName); + ServerNode rootNode = new ServerNode(response, serviceProvider, serverConnection, dataSource, objectMetadata); + + var session = new ObjectExplorerSession(response.OwnerUri, rootNode, serviceProvider, serviceProvider.GetService()); + if (!isDefaultOrSystemDatabase) + { + DataSourceObjectMetadata databaseMetadata = DataSourceFactory.CreateDatabaseMetadata(objectMetadata, response.ConnectionSummary.DatabaseName); + + // Assuming the databases are in a folder under server node + DataSourceTreeNode databaseNode = new DataSourceTreeNode(dataSource, databaseMetadata) { + Parent = rootNode, + NodeType = "Database", + NodeTypeId = NodeTypes.Database + }; + session.Root = databaseNode; + } + + return session; + } + + } + } + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs new file mode 100644 index 0000000000..941e45b1c3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ObjectExplorerUtils.cs @@ -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.Threading; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer +{ + /// + /// Utility class for Object Explorer related operations + /// + public static class ObjectExplorerUtils + { + /// + /// Visitor that walks all nodes from the child to the root node, unless the + /// function indicates that this should stop traversing + /// + /// node to start traversing at + /// Predicate function that accesses the tree and + /// determines whether to stop going further up the tree + /// + /// boolean - true to continue navigating up the tree, false to end the loop + /// and return early + /// + public static bool VisitChildAndParents(TreeNode child, Predicate visitor) + { + if (child == null) + { + // End case: all nodes have been visited + return true; + } + + // Visit the child first, then go up the parents + if (!visitor(child)) + { + return false; + } + return VisitChildAndParents(child.Parent, visitor); + } + + /// + /// Finds a node by traversing the tree starting from the given node through all the children + /// + /// node to start traversing at + /// Predicate function that accesses the tree and + /// determines whether to stop going further up the tree + /// Predicate function to filter the children when traversing + /// A Tree Node that matches the condition + public static TreeNode FindNode(TreeNode node, Predicate condition, Predicate filter, bool expandIfNeeded = false) + { + if(node == null) + { + return null; + } + + if (condition(node)) + { + return node; + } + var children = expandIfNeeded && !node.IsAlwaysLeaf ? node.Expand(new CancellationToken()) : node.GetChildren(); + foreach (var child in children) + { + if (filter != null && filter(child)) + { + TreeNode childNode = FindNode(child, condition, filter, expandIfNeeded); + if (childNode != null) + { + return childNode; + } + } + } + return null; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/DataSourceQueryModel.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/DataSourceQueryModel.cs new file mode 100644 index 0000000000..2ed7626402 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/DataSourceQueryModel.cs @@ -0,0 +1,52 @@ +// This file was generated by a T4 Template. Do not modify directly, instead update the SmoQueryModelDefinition.xml file +// and re-run the T4 template. This can be done in Visual Studio by right-click in and choosing "Run Custom Tool", +// or from the command-line on any platform by running "build.cmd -Target=CodeGen" or "build.sh -Target=CodeGen". + +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + + // TODOKusto: Do we need the Querier. This has been short circuited in smoChildFactoryBase. There is no caller to the "Query" function. + [Export(typeof(DataSourceQuerier))] + internal partial class DatabaseQuerier: DataSourceQuerier + { + public override IEnumerable Query(QueryContext context, string filter, bool refresh, IEnumerable extraProperties) + { + if (context.DataSource != null) + { + return context.DataSource.GetChildObjects(context.ParentObjectMetadata); + } + return Enumerable.Empty(); + } + } + + [Export(typeof(DataSourceQuerier))] + internal partial class TableQuerier: DataSourceQuerier + { + public override IEnumerable Query(QueryContext context, string filter, bool refresh, IEnumerable extraProperties) + { + if (context.ParentObjectMetadata != null) + { + return context.DataSource.GetChildObjects(context.ParentObjectMetadata); + } + return Enumerable.Empty(); + } + } + + [Export(typeof(DataSourceQuerier))] + internal partial class ColumnQuerier: DataSourceQuerier + { + public override IEnumerable Query(QueryContext context, string filter, bool refresh, IEnumerable extraProperties) + { + if (context.ParentObjectMetadata != null) + { + return context.DataSource.GetChildObjects(context.ParentObjectMetadata); + } + return Enumerable.Empty(); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/FolderNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/FolderNode.cs new file mode 100644 index 0000000000..e0ceaff4b4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/FolderNode.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Represents a folder node in the tree + /// + public class FolderNode : DataSourceTreeNode + { + public FolderNode(IDataSource dataSource, DataSourceObjectMetadata objectMetadata) + : base(dataSource, objectMetadata) + { + } + + /// + /// For folders, this copies the context of its parent if available + /// + /// + public override object GetContext() + { + return Parent?.GetContext(); + } + + /// + /// For folders, searches for its parent's SMO object rather than copying for itself + /// + /// from this parent's parent, or null if not found + public override DataSourceObjectMetadata GetParentObjectMetadata() + { + return ParentAs()?.GetParentObjectMetadata(); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/NodePathGenerator.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/NodePathGenerator.cs new file mode 100644 index 0000000000..0f72d04e09 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/NodePathGenerator.cs @@ -0,0 +1,268 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Xml.Serialization; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + public class NodePathGenerator + { + private static ServerExplorerTree TreeRoot { get; set; } + + private static Dictionary> NodeTypeDictionary { get; set; } + + internal static void Initialize() + { + if (TreeRoot != null) + { + return; + } + + var assembly = typeof(ObjectExplorerService).Assembly; + var resource = assembly.GetManifestResourceStream("Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel.TreeNodeDefinition.xml"); + var serializer = new XmlSerializer(typeof(ServerExplorerTree)); + NodeTypeDictionary = new Dictionary>(); + using (var reader = new StreamReader(resource)) + { + TreeRoot = (ServerExplorerTree)serializer.Deserialize(reader); + } + + foreach (var node in TreeRoot.Nodes) + { + var containedType = node.ContainedType(); + if (containedType != null && node.Label() != string.Empty) + { + if (!NodeTypeDictionary.ContainsKey(containedType)) + { + NodeTypeDictionary.Add(containedType, new HashSet()); + } + NodeTypeDictionary.GetValueOrDefault(containedType).Add(node); + } + } + var serverNode = TreeRoot.Nodes.FirstOrDefault(node => node.Name == "Server"); + var serverSet = new HashSet(); + serverSet.Add(serverNode); + NodeTypeDictionary.Add("Server", serverSet); + } + + internal static HashSet FindNodePaths(ObjectExplorerService.ObjectExplorerSession objectExplorerSession, string typeName, string schema, string name, string databaseName, List parentNames = null) + { + if (TreeRoot == null) + { + Initialize(); + } + + var returnSet = new HashSet(); + var matchingNodes = NodeTypeDictionary.GetValueOrDefault(typeName); + if (matchingNodes == null) + { + return returnSet; + } + + var path = name; + if (schema != null) + { + path = schema + "." + path; + } + + if (path == null) + { + path = ""; + } + + foreach (var matchingNode in matchingNodes) + { + var paths = GenerateNodePath(objectExplorerSession, matchingNode, databaseName, parentNames, path); + foreach (var newPath in paths) + { + returnSet.Add(newPath); + } + } + return returnSet; + } + + private static HashSet GenerateNodePath(ObjectExplorerService.ObjectExplorerSession objectExplorerSession, Node currentNode, string databaseName, List parentNames, string path) + { + if (parentNames != null) + { + parentNames = parentNames.ToList(); + } + + if (currentNode.Name == "Server" || (currentNode.Name == "Database" && objectExplorerSession.Root.NodeType == "Database")) + { + var serverRoot = objectExplorerSession.Root; + if (objectExplorerSession.Root.NodeType == "Database") + { + serverRoot = objectExplorerSession.Root.Parent; + path = objectExplorerSession.Root.NodeValue + (path.Length > 0 ? ("/" + path) : ""); + } + + path = serverRoot.NodeValue + (path.Length > 0 ? ("/" + path) : ""); + var returnSet = new HashSet(); + returnSet.Add(path); + return returnSet; + } + + var currentLabel = currentNode.Label(); + if (currentLabel != string.Empty) + { + path = currentLabel + "/" + path; + var returnSet = new HashSet(); + foreach (var parent in currentNode.ParentNodes()) + { + var paths = GenerateNodePath(objectExplorerSession, parent, databaseName, parentNames, path); + foreach (var newPath in paths) + { + returnSet.Add(newPath); + } + } + return returnSet; + } + else + { + var returnSet = new HashSet(); + if (currentNode.ContainedType() == "Database") + { + path = databaseName + "/" + path; + } + else if (parentNames != null && parentNames.Count > 0) + { + var parentName = parentNames.Last(); + parentNames.RemoveAt(parentNames.Count - 1); + path = parentName + "/" + path; + } + else + { + return returnSet; + } + + foreach (var parentNode in currentNode.ParentNodes()) + { + var newPaths = GenerateNodePath(objectExplorerSession, parentNode, databaseName, parentNames, path); + foreach (var newPath in newPaths) + { + returnSet.Add(newPath); + } + } + + return returnSet; + } + } + + [XmlRoot("ServerExplorerTree")] + public class ServerExplorerTree + { + [XmlElement("Node", typeof(Node))] + public List Nodes { get; set; } + + public Node GetNode(string name) + { + foreach (var node in this.Nodes) + { + if (node.Name == name) + { + return node; + } + } + + return null; + } + } + + public class Node + { + [XmlAttribute] + public string Name { get; set; } + + [XmlAttribute] + public string LocLabel { get; set; } + + [XmlAttribute] + public string TreeNode { get; set; } + + [XmlAttribute] + public string NodeType { get; set; } + + [XmlElement("Child", typeof(Child))] + public List Children { get; set; } + + public HashSet ChildFolders() + { + var childSet = new HashSet(); + foreach (var child in this.Children) + { + var node = TreeRoot.GetNode(child.Name); + if (node != null) + { + childSet.Add(node); + } + } + return childSet; + } + + public string ContainedType() + { + if (this.TreeNode != null) + { + return this.TreeNode.Replace("TreeNode", ""); + } + else if (this.NodeType != null) + { + return this.NodeType; + } + return null; + } + + public Node ContainedObject() + { + var containedType = this.ContainedType(); + if (containedType == null) + { + return null; + } + + var containedNode = TreeRoot.GetNode(containedType); + if (containedNode == this) + { + return null; + } + + return containedNode; + } + + public string Label() + { + if (this.LocLabel.StartsWith("SR.")) + { + return SR.Keys.GetString(this.LocLabel.Remove(0, 3)); + } + + return string.Empty; + } + + public HashSet ParentNodes() + { + var parentNodes = new HashSet(); + foreach (var node in TreeRoot.Nodes) + { + if (this != node && (node.ContainedType() == this.Name || node.Children.Any(child => child.Name == this.Name))) + { + parentNodes.Add(node); + } + } + return parentNodes; + } + } + + public class Child + { + [XmlAttribute] + public string Name { get; set; } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/ServerNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/ServerNode.cs new file mode 100644 index 0000000000..e7fb4c753e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/ServerNode.cs @@ -0,0 +1,129 @@ +// +// 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.Diagnostics; +using System.Globalization; +using Microsoft.SqlServer.Management.Common; +using Microsoft.SqlTools.Extensibility; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Server node implementation + /// + public class ServerNode : TreeNode + { + private ConnectionSummary connectionSummary; + private ServerInfo serverInfo; + private Lazy context; + private ServerConnection serverConnection; + + public ServerNode(ConnectionCompleteParams connInfo, IMultiServiceProvider serviceProvider, ServerConnection serverConnection, IDataSource dataSource, DataSourceObjectMetadata objectMetadata) + : base(dataSource, objectMetadata) + { + Validate.IsNotNull(nameof(connInfo), connInfo); + Validate.IsNotNull("connInfo.ConnectionSummary", connInfo.ConnectionSummary); + Validate.IsNotNull(nameof(serviceProvider), serviceProvider); + + this.connectionSummary = connInfo.ConnectionSummary; + this.serverInfo = connInfo.ServerInfo; + + this.context = new Lazy(() => CreateContext(serviceProvider)); + this.serverConnection = serverConnection; + + NodeValue = connectionSummary.ServerName; + IsAlwaysLeaf = false; + NodeType = NodeTypes.Server.ToString(); + NodeTypeId = NodeTypes.Server; + Label = GetConnectionLabel(); + } + + /// + /// Returns the label to display to the user. + /// + internal string GetConnectionLabel() + { + string userName = connectionSummary.UserName; + + // TODO Domain and username is not yet supported on .Net Core. + // Consider passing as an input from the extension where this can be queried + //if (string.IsNullOrWhiteSpace(userName)) + //{ + // userName = Environment.UserDomainName + @"\" + Environment.UserName; + //} + + // TODO Consider adding IsAuthenticatingDatabaseMaster check in the code and + // referencing result here + if (!DatabaseUtils.IsSystemDatabaseConnection(connectionSummary.DatabaseName)) + { + // We either have an azure with a database specified or a Denali database using a contained user + if (string.IsNullOrWhiteSpace(userName)) + { + userName = connectionSummary.DatabaseName; + } + else + { + userName += ", " + connectionSummary.DatabaseName; + } + } + + string label; + if (string.IsNullOrWhiteSpace(userName)) + { + label = string.Format( + CultureInfo.InvariantCulture, + "{0} ({1} {2})", + connectionSummary.ServerName, + "SQL Server", + serverInfo.ServerVersion); + } + else + { + label = string.Format( + CultureInfo.InvariantCulture, + "{0} ({1} {2} - {3})", + connectionSummary.ServerName, + "SQL Server", + serverInfo.ServerVersion, + userName); + } + + return label; + } + + private QueryContext CreateContext(IMultiServiceProvider serviceProvider) + { + string exceptionMessage; + + try + { + return new QueryContext(DataSource, serviceProvider) + { + ParentObjectMetadata = this.ObjectMetadata + }; + } + catch (Exception ex) + { + exceptionMessage = ex.Message; + } + + Logger.Write(TraceEventType.Error, "Exception at ServerNode.CreateContext() : " + exceptionMessage); + this.ErrorStateMessage = string.Format(SR.TreeNodeError, exceptionMessage); + return null; + } + + public override object GetContext() + { + return context.Value; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs new file mode 100644 index 0000000000..67a6dc6e4c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoChildFactoryBase.cs @@ -0,0 +1,178 @@ +// +// 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.Diagnostics; +using System.Linq; +using System.Threading; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + public class DataSourceChildFactoryBase : ChildFactory + { + private IEnumerable smoProperties; + public override IEnumerable ApplicableParents() + { + return null; + } + + public override IEnumerable Expand(TreeNode parent, bool refresh, string name, bool includeSystemObjects, CancellationToken cancellationToken) + { + throw new NotImplementedException(); // Moved to TreeNode.cs + } + + private bool ShouldFilterNode(TreeNode childNode, ValidForFlag validForFlag) + { + bool filterTheNode = false; + + return filterTheNode; + } + + private string GetProperyFilter(IEnumerable filters, Type querierType, ValidForFlag validForFlag) + { + string filter = string.Empty; + if (filters != null) + { + var filtersToApply = filters.Where(f => f.CanApplyFilter(querierType, validForFlag)).ToList(); + filter = string.Empty; + if (filtersToApply.Any()) + { + filter = NodeFilter.ConcatProperties(filtersToApply); + } + } + + return filter; + } + + private bool IsCompatibleQuerier(DataSourceQuerier querier) + { + if (ChildQuerierTypes == null) + { + return false; + } + + Type actualType = querier.GetType(); + foreach (Type childType in ChildQuerierTypes) + { + // We will accept any querier that is compatible with the listed querier type + if (childType.IsAssignableFrom(actualType)) + { + return true; + } + } + return false; + + } + + public override bool CanCreateChild(TreeNode parent, object context) + { + return false; + } + + public override TreeNode CreateChild(TreeNode parent, DataSourceObjectMetadata childMetadata) + { + throw new NotImplementedException(); + } + + protected virtual void InitializeChild(TreeNode parent, TreeNode child, object context) + { + DataSourceObjectMetadata objectMetadata = context as DataSourceObjectMetadata; + if (objectMetadata == null) + { + Debug.WriteLine("context is not a DataSourceObjectMetadata type: " + context.GetType()); + } + else + { + smoProperties = SmoProperties; + DataSourceTreeNode childAsMeItem = (DataSourceTreeNode)child; + childAsMeItem.CacheInfoFromModel(objectMetadata); + QueryContext oeContext = parent.GetContextAs(); + + // If node has custom name, replaced it with the name already set + string customizedName = GetNodeCustomName(context, oeContext); + if (!string.IsNullOrEmpty(customizedName)) + { + childAsMeItem.NodeValue = customizedName; + childAsMeItem.NodePathName = GetNodePathName(context); + } + + childAsMeItem.NodeSubType = GetNodeSubType(context, oeContext); + childAsMeItem.NodeStatus = GetNodeStatus(context, oeContext); + } + } + + internal virtual Type[] ChildQuerierTypes + { + get + { + return null; + } + } + + public override IEnumerable Filters + { + get + { + return Enumerable.Empty(); + } + } + + public override IEnumerable SmoProperties + { + get + { + return Enumerable.Empty(); + } + } + + internal IEnumerable CachedSmoProperties + { + get + { + return smoProperties == null ? SmoProperties : smoProperties; + } + } + + /// + /// Returns true if any final validation of the object to be added passes, and false + /// if validation fails. This provides a chance to filter specific items out of a list + /// + /// + /// + /// boolean + public virtual bool PassesFinalFilters(TreeNode parent, object context) + { + return true; + } + + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return string.Empty; + } + + public override string GetNodeStatus(object objectMetadata, QueryContext oeContext) + { + return string.Empty; + } + + public static bool IsPropertySupported(string propertyName, QueryContext context, DataSourceObjectMetadata objectMetadata, IEnumerable supportedProperties) + { + return true; + } + + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return (objectMetadata as DataSourceObjectMetadata).PrettyName; + } + + public override string GetNodePathName(object objectMetadata) + { + return (objectMetadata as DataSourceObjectMetadata).Urn; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoCollectionWrapper.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoCollectionWrapper.cs new file mode 100644 index 0000000000..a93708f4ea --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoCollectionWrapper.cs @@ -0,0 +1,57 @@ +// +// 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; +using System.Collections.Generic; +using Microsoft.SqlServer.Management.Smo; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Wrapper to convert non-generic Smo enumerables to generic enumerable types for easier use in + /// + /// + public class SmoCollectionWrapper : IEnumerable + where T : SqlSmoObject + { + private SmoCollectionBase collection; + + /// + /// Constructor which accepts a containing the objects + /// to wrap + /// + /// or null if none were set + public SmoCollectionWrapper(SmoCollectionBase collection) + { + this.collection = collection; + } + + /// + /// + /// + /// + public IEnumerator GetEnumerator() + { + if (collection == null) + { + yield break; + } + foreach(Object obj in collection) + { + yield return (T)obj; + } + } + + /// + /// + /// + /// + IEnumerator IEnumerable.GetEnumerator() + { + return collection?.GetEnumerator(); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoColumnCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoColumnCustomNode.cs new file mode 100644 index 0000000000..85ec3b62c7 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoColumnCustomNode.cs @@ -0,0 +1,356 @@ +// +// 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.Diagnostics; +using System.Globalization; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Custom name for Columns + /// + internal partial class ColumnsChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return SmoColumnCustomNodeHelper.CalculateCustomLabel(objectMetadata, oeContext); + } + + private readonly Lazy> smoPropertiesLazy = new Lazy>(() => new List + { + new NodeSmoProperty + { + Name = "Computed", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "IsColumnSet", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "Nullable", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "DataType", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "InPrimaryKey", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "IsForeignKey", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "SystemType", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "Length", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "NumericPrecision", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "NumericScale", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "XmlSchemaNamespaceSchema", + ValidFor = ValidForFlag.NotSqlDw + }, + new NodeSmoProperty + { + Name = "XmlSchemaNamespace", + ValidFor = ValidForFlag.NotSqlDw + }, + new NodeSmoProperty + { + Name = "XmlDocumentConstraint", + ValidFor = ValidForFlag.NotSqlDw + } + }); + + public override IEnumerable SmoProperties => smoPropertiesLazy.Value; + } + + /// + /// Custom name for UserDefinedTableTypeColumn + /// + internal partial class UserDefinedTableTypeColumnsChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return SmoColumnCustomNodeHelper.CalculateCustomLabel(objectMetadata, oeContext); + } + } + + static class SmoColumnCustomNodeHelper + { + private const string SimpleColumnLabelWithType = "{0} ({1}{2}, {3})"; + private const string SimpleColumnLabelWithoutType = "{0} ({1})"; + private const string SimpleColumnLabelWithTypeAndKeyString = "{0} ({1}, {2}, {3})"; + + internal static string CalculateCustomLabel(object context, QueryContext oeContext) + { + UserDefinedDataTypeCollection uddts = null; // TODOKusto: Remove. Not needed. + Column column = context as Column; + if(column != null) + { + return GetCustomizedLabel(column, uddts); + } + + return string.Empty; + } + + private static string GetCustomizedLabel(Column column, UserDefinedDataTypeCollection uddts) + { + try + { + if (column.Computed) + { + return GetComputedColumnLabel(column, uddts); + } + else if (column.IsColumnSet) + { + return GetColumnSetLabel(column, uddts); + } + else + { + return GetSimpleColumnLabel(column, uddts); + } + } + catch(Exception ex) + { + Logger.Write(TraceEventType.Error, $"Failed to get customized column name. error:{ex.Message}"); + } + return string.Empty; + } + + private static string GetTypeSpecifierLabel(DataType dataType, UserDefinedDataTypeCollection uddts) + { + string typeName = string.Empty; + if (dataType != null) + { + // typeSpecifier might still be in a resolve candidate status. If so then the + // name might be null. Don't ask for the type specifier name in this case. + typeName = dataType.Name; + + // This may return [dbo].[MyType], but for the purposes of display we only want MyType + if (!string.IsNullOrWhiteSpace(typeName) && + typeName.EndsWith("]", StringComparison.Ordinal)) + { + int nameStart = typeName.LastIndexOf('['); + typeName = typeName.Substring(nameStart + 1, typeName.Length - nameStart - 2); + + } + + if(dataType.SqlDataType == SqlDataType.UserDefinedDataType && uddts != null) + { + foreach (UserDefinedDataType item in uddts) + { + if(item.Name == dataType.Name) + { + typeName += $"({item.SystemType})"; + break; + } + } + } + + // These types supports detailed information + switch (dataType.SqlDataType) + { + case SqlDataType.Char: + case SqlDataType.NChar: + case SqlDataType.Binary: + case SqlDataType.VarChar: + case SqlDataType.NVarChar: + case SqlDataType.VarBinary: + typeName += $"({dataType.MaximumLength})"; + break; + case SqlDataType.Numeric: + case SqlDataType.Decimal: + typeName += $"({dataType.NumericPrecision},{dataType.NumericScale})"; + break; + case SqlDataType.DateTime2: + case SqlDataType.Time: + case SqlDataType.DateTimeOffset: + typeName += $"({dataType.NumericScale})"; + break; + case SqlDataType.VarBinaryMax: + case SqlDataType.NVarCharMax: + case SqlDataType.VarCharMax: + typeName += "(max)"; + break; + } + } + return typeName; + } + + private static string GetKeyString(Column column) + { + // Get if it's a PK or FK (or both) + // Here's how it could be both...notice t2c1 is both a primary and foreign key + // + // Create table t1 (t1c1 int, t1c2 int not null primary key) + // Create table t2 (t2c1 int primary key, t2c2 int not null) + // Alter table t2 add FOREIGN KEY(t2c1) references t1(t1c2) + // + string keyString = null; + if (column.InPrimaryKey) + keyString = "PK"; + if (column.IsForeignKey) + { + keyString = (keyString == null) ? "FK" : + "PK, FK"; + } + + return keyString; + } + + private static string GetColumnSetLabel(Column column, UserDefinedDataTypeCollection uddts) + { + // This is the simple name + string label = column.Name; + + // Get the column type + string columnType = GetTypeSpecifierLabel(column.DataType, uddts); + string keyString = GetKeyString(column); + + if (keyString != null && !string.IsNullOrWhiteSpace(columnType)) + { + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_ColumnSetLabelWithTypeAndKeyString, + label, + keyString, + columnType, + SR.SchemaHierarchy_NullColumn_Label); + } + + if (!string.IsNullOrWhiteSpace(columnType)) + { + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_ColumnSetLabelWithType, + label, + keyString, + columnType, + SR.SchemaHierarchy_NullColumn_Label); + } + + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_ColumnSetLabelWithoutType, + label, + SR.SchemaHierarchy_NullColumn_Label); + } + + private static string GetSimpleColumnLabel(Column column, UserDefinedDataTypeCollection uddts) + { + // This is the simple name + string label = column.Name; + + // Get the nullability + string isNullable = column.Nullable ? SR.SchemaHierarchy_NullColumn_Label : SR.SchemaHierarchy_NotNullColumn_Label; + + // Get the column type + string columnType = GetTypeSpecifierLabel(column.DataType, uddts); + + string keyString = GetKeyString(column); + + if (keyString != null && !string.IsNullOrWhiteSpace(columnType)) + { + return string.Format(CultureInfo.InvariantCulture, + SimpleColumnLabelWithTypeAndKeyString, + label, + keyString, + columnType, + isNullable); + } + + if (!string.IsNullOrWhiteSpace(columnType)) + { + return string.Format(CultureInfo.InvariantCulture, + SimpleColumnLabelWithType, + label, + keyString, + columnType, + isNullable); + } + + return string.Format(CultureInfo.InvariantCulture, + SimpleColumnLabelWithoutType, + label, + isNullable); + } + + private static string GetComputedColumnLabel(Column column, UserDefinedDataTypeCollection uddts) + { + string columnType = null; + + // Display the type name as fully qualified + string label = column.Name; + + // Get the nullability + string isNullable = column.Nullable ? SR.SchemaHierarchy_NullColumn_Label : SR.SchemaHierarchy_NotNullColumn_Label; + + string keyString = GetKeyString(column); + + // Get the column type + columnType = GetTypeSpecifierLabel(column.DataType, uddts); + + if (!string.IsNullOrWhiteSpace(columnType)) + { + if (column.Parent is View) + { + // View columns are always computed, but SSMS shows then as never computed, so + // treat them as simple columns + return string.Format(CultureInfo.InvariantCulture, + SimpleColumnLabelWithType, + label, + keyString, + columnType, + isNullable); + } + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_ComputedColumnLabelWithType, + label, + keyString, + columnType, + isNullable); + } + + if (column.Parent is View) + { + return string.Format(CultureInfo.InvariantCulture, + SimpleColumnLabelWithoutType, + label, + keyString); + } + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_ComputedColumnLabelWithoutType, + label, + keyString); + + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs new file mode 100644 index 0000000000..0152fc61a3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoDatabaseCustomNode.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Status for databases + /// + internal partial class DatabasesChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeStatus(object objectMetadata, QueryContext oeContext) + { + return DatabasesCustomNodeHelper.GetStatus(objectMetadata, oeContext, CachedSmoProperties); + } + + protected override void InitializeChild(TreeNode parent, TreeNode child, object context) + { + base.InitializeChild(parent, child, context); + var dsTreeNode = child as DataSourceTreeNode; + if (dsTreeNode != null && dsTreeNode.ObjectMetadata != null + && DatabasesCustomNodeHelper.GetDatabaseIsUnavailable(dsTreeNode.ObjectMetadata, parent.GetContextAs(), CachedSmoProperties)) + { + child.IsAlwaysLeaf = true; + } + } + } + + internal static class DatabasesCustomNodeHelper + { + private static readonly DatabaseStatus[] UnavailableDatabaseStatuses = { DatabaseStatus.Inaccessible, DatabaseStatus.Offline, DatabaseStatus.Recovering, + DatabaseStatus.RecoveryPending, DatabaseStatus.Restoring, DatabaseStatus.Suspect, DatabaseStatus.Shutdown }; + + internal static bool GetDatabaseIsUnavailable(object objectMetadata, QueryContext oeContext, IEnumerable supportedProperties) + { + if(oeContext.DataSource == null) return false; // Assume that database is available + + return !oeContext.DataSource.Exists(objectMetadata as DataSourceObjectMetadata); + } + + internal static string GetStatus(object objectMetadata, QueryContext oeContext, IEnumerable supportedProperties) + { + // TODOKusto: Remove if not needed. Returning a value appends it to the database name + // if(oeContext.DataSource.Exists(objectMetadata as DataSourceObjectMetadata)) return "Online"; + + return string.Empty; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs new file mode 100644 index 0000000000..3b2a3b1d07 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoKeyCustomNode.cs @@ -0,0 +1,115 @@ +// +// 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.SqlServer.Management.Smo; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Index = Microsoft.SqlServer.Management.Smo.Index; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Subtye for keys + /// + internal partial class KeysChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return IndexCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + /// + /// Sub types and custom name for indexes + /// + internal partial class IndexesChildFactory : DataSourceChildFactoryBase + { + private readonly Lazy> smoPropertiesLazy = new Lazy>(() => new List + { + new NodeSmoProperty + { + Name = "IsUnique", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "IsClustered", + ValidFor = ValidForFlag.All + }, + new NodeSmoProperty + { + Name = "IndexKeyType", + ValidFor = ValidForFlag.All + } + }); + + public override IEnumerable SmoProperties => smoPropertiesLazy.Value; + + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return IndexCustomeNodeHelper.GetSubType(objectMetadata); + } + + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return IndexCustomeNodeHelper.GetCustomLabel(objectMetadata); + } + } + + /// + /// sub type for UserDefinedTableTypeKeys + /// + internal partial class UserDefinedTableTypeKeysChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return IndexCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + internal static class IndexCustomeNodeHelper + { + internal static string GetCustomLabel(object context) + { + Index index = context as Index; + if (index != null) + { + string name = index.Name; + string unique = index.IsUnique ? SR.UniqueIndex_LabelPart : SR.NonUniqueIndex_LabelPart; + string clustered = index.IsClustered ? SR.ClusteredIndex_LabelPart : SR.NonClusteredIndex_LabelPart; + name = name + $" ({unique}, {clustered})"; + return name; + } + return string.Empty; + + } + + internal static string GetSubType(object context) + { + + Index index = context as Index; + if (index != null) + { + switch (index.IndexKeyType) + { + case IndexKeyType.DriPrimaryKey: + return "PrimaryKey"; + case IndexKeyType.DriUniqueKey: + return "UniqueKey"; + } + + } + + ForeignKey foreignKey = context as ForeignKey; + if (foreignKey != null) + { + return "ForeignKey"; + } + + return string.Empty; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs new file mode 100644 index 0000000000..cbc9bc65f4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoLoginCustomNode.cs @@ -0,0 +1,52 @@ +// +// 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.SqlServer.Management.Smo; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Status for logins + /// + internal partial class ServerLevelLoginsChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeStatus(object objectMetadata, QueryContext oeContext) + { + return LoginCustomNodeHelper.GetStatus(objectMetadata); + } + + private readonly Lazy> smoPropertiesLazy = new Lazy>(() => new List + { + new NodeSmoProperty + { + Name = "IsDisabled", + ValidFor = ValidForFlag.All + } + }); + + public override IEnumerable SmoProperties => smoPropertiesLazy.Value; + } + + internal static class LoginCustomNodeHelper + { + internal static string GetStatus(object context) + { + Login login = context as Login; + if (login != null) + { + if (login.IsDisabled) + { + return "Disabled"; + } + } + + return string.Empty; + } + } +} + diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs new file mode 100644 index 0000000000..f92f604032 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoParamterCustomNode.cs @@ -0,0 +1,137 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Globalization; +using Microsoft.SqlServer.Management.Smo; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Custom name for parameters + /// + internal partial class TableValuedFunctionParametersChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext); + } + + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + /// + /// Custom name for parameters + /// + internal partial class ScalarValuedFunctionParametersChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext); + } + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + /// + /// Custom name for parameters + /// + internal partial class AggregateFunctionParametersChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext); + } + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + /// + /// Custom name for parameters + /// + internal partial class StoredProcedureParametersChildFactory : DataSourceChildFactoryBase + { + public override string GetNodeCustomName(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetCustomLabel(objectMetadata, oeContext); + } + public override string GetNodeSubType(object objectMetadata, QueryContext oeContext) + { + return ParameterCustomeNodeHelper.GetSubType(objectMetadata); + } + } + + static class ParameterCustomeNodeHelper + { + internal static string GetSubType(object context) + { + Parameter parameter = context as Parameter; + if (parameter != null) + { + StoredProcedureParameter stordProcedureParameter = parameter as StoredProcedureParameter; + if (stordProcedureParameter != null && stordProcedureParameter.IsOutputParameter) + { + return "Output"; + } + return "Input"; + //TODO return parameters + } + return string.Empty; + + } + + internal static string GetCustomLabel(object context, QueryContext oeContext) + { + Parameter parameter = context as Parameter; + if (parameter != null) + { + return GetParameterCustomLabel(parameter); + } + + return string.Empty; + } + + internal static string GetParameterCustomLabel(Parameter parameter) + { + string label = parameter.Name; + string defaultString = SR.SchemaHierarchy_SubroutineParameterNoDefaultLabel; + string inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputLabel; + string typeName = parameter.DataType.ToString(); + + if (parameter.DefaultValue != null && + !string.IsNullOrEmpty(parameter.DefaultValue)) + { + defaultString = SR.SchemaHierarchy_SubroutineParameterDefaultLabel; + } + + StoredProcedureParameter stordProcedureParameter = parameter as StoredProcedureParameter; + if (stordProcedureParameter != null && stordProcedureParameter.IsOutputParameter) + { + inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputOutputLabel; + if (parameter.IsReadOnly) + { + inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputOutputReadOnlyLabel; + } + } + else if (parameter.IsReadOnly) + { + inputOutputString = SR.SchemaHierarchy_SubroutineParameterInputReadOnlyLabel; + } + + return string.Format(CultureInfo.InvariantCulture, + SR.SchemaHierarchy_SubroutineParameterLabelFormatString, + label, + typeName, + inputOutputString, + defaultString); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQuerier.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQuerier.cs new file mode 100644 index 0000000000..962e075764 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQuerier.cs @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.Data; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlTools.Extensibility; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// A handles SMO queries for one or more SMO object types. + /// The property defines which types can be queried. + /// + /// To query multiple + /// + public abstract class DataSourceQuerier : IComposableService + { + private static object lockObject = new object(); + + /// + /// Queries SMO for a collection of objects using the + /// + /// + /// + public abstract IEnumerable Query(QueryContext context, string filter, bool refresh, IEnumerable extraProperties); + + internal IMultiServiceProvider ServiceProvider + { + get; + private set; + } + + public void SetServiceProvider(IMultiServiceProvider provider) + { + ServiceProvider = provider; + } + + /// + /// Convert the data to data reader is possible + /// + protected IDataReader GetDataReader(object data) + { + IDataReader reader = null; + if (data is IDataReader) + { + + reader = data as IDataReader; + } + else if(data is DataTable) + { + reader = ((DataTable)data).CreateDataReader(); + } + + else if (data is DataSet) + { + reader = ((DataSet)data).Tables[0].CreateDataReader(); + } + + return reader; + } + + /// + /// Mthod used to do custom filtering on smo objects if cannot be implemented using the filters + /// + protected virtual bool PassesFinalFilters(SqlSmoObject parent, SqlSmoObject objectMetadata) + { + return true; + } + + /// + /// Indicates which platforms the querier is valid for + /// + public virtual ValidForFlag ValidFor + { + get + { + return ValidForFlag.All; + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs new file mode 100644 index 0000000000..6a07b2e1e3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryContext.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Extensibility; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Context object containing key properties needed to query for SMO objects + /// + public class QueryContext + { + public IDataSource DataSource { get; private set; } + + /// + /// Creates a context object with a server to use as the basis for any queries + /// + /// + public QueryContext(IDataSource dataSource, IMultiServiceProvider serviceProvider) + { + DataSource = dataSource; + ServiceProvider = serviceProvider; + } + + /// + /// Parent of a give node to use for queries + /// + public DataSourceObjectMetadata ParentObjectMetadata { get; set; } + + /// + /// A query loader that can be used to find objects + /// for specific SMO types + /// + public IMultiServiceProvider ServiceProvider { get; private set; } + + /// + /// Helper method to cast a parent to a specific type + /// + /// + /// + public T ParentAs() + where T : TreeNode + { + return ParentObjectMetadata as T; + } + + /// + /// Copies the context for use by another node + /// + /// New Parent to set + /// new with all fields except the same + public QueryContext CopyWithParent(DataSourceObjectMetadata parent) + { + QueryContext context = new QueryContext(this.DataSource, this.ServiceProvider) + { + ParentObjectMetadata = parent + }; + return context; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModel.tt b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModel.tt new file mode 100644 index 0000000000..bb9a554fed --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModel.tt @@ -0,0 +1,320 @@ +<#@ 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" #> +// This file was generated by a T4 Template. Do not modify directly, instead update the SmoQueryModelDefinition.xml file +// and re-run the T4 template. This can be done in Visual Studio by right-click in and choosing "Run Custom Tool", +// or from the command-line on any platform by running "build.cmd -Target=CodeGen" or "build.sh -Target=CodeGen". + +using System; +using System.Collections.Generic; +using System.Composition; +using System.Linq; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.SqlServer.Management.Smo.Broker; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel +{ +<# + var directory = Path.GetDirectoryName(Host.TemplateFile); + string xmlFile = Path.Combine(directory, "SmoQueryModelDefinition.xml"); + + ///////// + // Now generate all the Query methods + ///////// + var allNodes = GetNodes(xmlFile); + var indent = " "; + foreach (var nodeName in allNodes) + { + XmlElement nodeElement = GetNodeElement(xmlFile, nodeName); + IList parents = GetParents(nodeElement, xmlFile, nodeName); + string nodeType = GetNodeType(nodeElement, nodeName); + var validFor = nodeElement.GetAttribute("ValidFor"); + + string queryBaseClass = "SmoQuerier"; + PushIndent(indent); + WriteLine(""); + WriteLine(string.Format("[Export(typeof({0}))]", queryBaseClass)); + WriteLine(string.Format("internal partial class {0}Querier: {1}", nodeName, queryBaseClass)); + WriteLine("{"); + PushIndent(indent); + + // Supported Types + WriteLine("Type[] supportedTypes = new Type[] { typeof("+ nodeType + ") };"); + if (!string.IsNullOrWhiteSpace(validFor)) + { + WriteLine(""); + WriteLine(string.Format("public override ValidForFlag ValidFor {{ get {{ return {0}; }} }}", GetValidForFlags(validFor))); + WriteLine(""); + } + + WriteLine(""); + WriteLine("public override Type[] SupportedObjectTypes { get { return supportedTypes; } }"); + WriteLine(""); + + // Query impl + WriteLine("public override IEnumerable Query(SmoQueryContext context, string filter, bool refresh, IEnumerable extraProperties)"); + WriteLine("{"); + PushIndent(indent); + + // TODO Allow override of the navigation path + foreach(var parentType in parents) + { + string parentVar = string.Format("parent{0}", parentType); + WriteLine(string.Format("{0} {1} = context.Parent as {0};", parentType, parentVar)); + WriteLine(string.Format("if ({0} != null)", parentVar)); + WriteLine("{"); + PushIndent(indent); + + XmlElement navPathElement = GetNavPathElement(xmlFile, nodeName, parentType); + string navigationPath = GetNavigationPath(nodeElement, nodeName, navPathElement); + string subField = GetNavPathAttribute(navPathElement, "SubField"); + string fieldType = GetNavPathAttribute(navPathElement, "FieldType"); + + + WriteLine(string.Format("var retValue = {0}.{1};", parentVar, navigationPath)); + WriteLine("if (retValue != null)"); + WriteLine("{"); + PushIndent(indent); + + + if (IsCollection(nodeElement)) + { + WriteLine(string.Format("retValue.ClearAndInitialize(filter, extraProperties);")); + if (string.IsNullOrEmpty(subField) ) + { + WriteLine(string.Format("return new SmoCollectionWrapper<{0}>(retValue).Where(c => PassesFinalFilters({1}, c));", nodeType, parentVar)); + } + else + { + WriteLine(string.Format("List<{0}> subFieldResult = new List<{0}>();", nodeType)); + WriteLine(string.Format("foreach({0} field in retValue)", fieldType)); + WriteLine("{"); + PushIndent(indent); + WriteLine(string.Format("{0} subField = field.{1};", nodeType, subField)); + WriteLine(string.Format("if (subField != null)")); + WriteLine("{"); + PushIndent(indent); + WriteLine(string.Format("subFieldResult.Add(subField);")); + PopIndent(); + WriteLine("}"); + PopIndent(); + WriteLine("}"); + WriteLine(string.Format("return subFieldResult.Where(c => PassesFinalFilters({1}, c));", nodeType, parentVar)); + } + } + else + { + WriteLine("if (refresh)"); + WriteLine("{"); + PushIndent(indent); + WriteLine(string.Format("{0}.{1}.Refresh();", parentVar, navigationPath)); + PopIndent(); + WriteLine("}"); + WriteLine("return new SqlSmoObject[] { retValue };"); + } + + PopIndent(); + WriteLine("}"); + PopIndent(); + WriteLine("}"); // close If + } + + WriteLine("return Enumerable.Empty();"); + + PopIndent(); + WriteLine("}"); // close Query method + PopIndent(); + WriteLine("}"); // close Class + PopIndent(); + } +#> +} + +<#+ + + public static string[] GetNodes(string xmlFile) + { + List typesList = new List(); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + XmlNodeList treeTypes = doc.SelectNodes("/SmoQueryModel/Node"); + if (treeTypes != null) + { + foreach (var type in treeTypes) + { + XmlElement element = type as XmlElement; + if (element != null) + { + typesList.Add(element.GetAttribute("Name")); + } + } + } + return typesList.ToArray(); + } + + public static XmlElement GetNodeElement(string xmlFile, string nodeName) + { + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + return (XmlElement)doc.SelectSingleNode(string.Format("/SmoQueryModel/Node[@Name='{0}']", nodeName)); + } + + public static XmlElement GetNavPathElement(string xmlFile, string nodeName, string parent) + { + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + XmlElement navPathElement = (XmlElement)doc.SelectSingleNode(string.Format("/SmoQueryModel/Node[@Name='{0}']/NavigationPath[@Parent='{1}']", nodeName, parent)); + + return navPathElement; + } + + public static string GetNavPathAttribute(XmlElement navPathElement, string attributeName) + { + return navPathElement == null ? null : navPathElement.GetAttribute(attributeName); + } + + public static string GetNavigationPath(XmlElement nodeElement, string nodeName, XmlElement navPathElement) + { + string navPathField = GetNavPathAttribute(navPathElement, "Field"); + if (!string.IsNullOrEmpty(navPathField)) + { + return navPathField; + } + // else use pluralized type as this is the most common scenario + string nodeType = GetNodeType(nodeElement, nodeName); + + string nodeTypeAccessor = IsCollection(nodeElement) ? string.Format("{0}s", nodeType) : nodeType; + return nodeTypeAccessor; + } + + public static string GetNodeType(XmlElement nodeElement, string nodeName) + { + var type = nodeElement.GetAttribute("Type"); + if (!string.IsNullOrEmpty(type)) + { + return type; + } + // Otherwise assume the type is the node name without "Sql" at the start + var prefix = "Sql"; + return nodeName.IndexOf(prefix) == 0 ? nodeName.Substring(prefix.Length) : nodeName; + } + + public static bool IsCollection(XmlElement nodeElement) + { + var collection = nodeElement.GetAttribute("Collection"); + bool result; + if (bool.TryParse(collection, out result)) + { + return result; + } + // Default is true + return true; + } + + public static IList GetParents(XmlElement nodeElement, string xmlFile, string parentName) + { + var parentAttr = nodeElement.GetAttribute("Parent"); + if (!string.IsNullOrEmpty(parentAttr)) + { + return new string[] { parentAttr }; + } + + var parentNodes = GetChildren(xmlFile, parentName, "Parent"); + if (parentNodes != null && parentNodes.Count > 0) + { + List parents = new List(); + foreach(var node in parentNodes) + { + parents.Add(node.InnerText); + } + return parents; + } + + // default to assuming a type is under Database + return new string[] { "Database" }; + } + + public static List GetChildren(string xmlFile, string parentName, string childNode) + { + XmlElement nodeElement = GetNodeElement(xmlFile, parentName); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes(string.Format("/SmoQueryModel/Node[@Name='{0}']/{1}", parentName, childNode)); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } + + public static string GetValidForFlags(string validForStr) + { + List flags = new List(); + if (validForStr.Contains("Sql2005")) + { + flags.Add("ValidForFlag.Sql2005"); + } + + if (validForStr.Contains("Sql2008")) + { + flags.Add("ValidForFlag.Sql2008"); + } + + if (validForStr.Contains("Sql2012")) + { + flags.Add("ValidForFlag.Sql2012"); + } + + if (validForStr.Contains("Sql2014")) + { + flags.Add("ValidForFlag.Sql2014"); + } + + if (validForStr.Contains("Sql2016")) + { + flags.Add("ValidForFlag.Sql2016"); + } + + if (validForStr.Contains("Sql2017")) + { + flags.Add("ValidForFlag.Sql2017"); + } + + if (validForStr.Contains("AzureV12")) + { + flags.Add("ValidForFlag.AzureV12"); + } + + if (validForStr.Contains("AllOnPrem")) + { + flags.Add("ValidForFlag.AllOnPrem"); + } + if (validForStr.Contains("AllAzure")) + { + flags.Add("ValidForFlag.AllAzure"); + } + if (validForStr.Contains("NotSqlDw")) + { + flags.Add("ValidForFlag.NotSqlDw"); + } + if (validForStr == "All") + { + flags.Add("ValidForFlag.All"); + } + + return string.Join("|", flags); + } + +#> \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModelDefinition.xml b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModelDefinition.xml new file mode 100644 index 0000000000..3522327860 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoQueryModelDefinition.xml @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Table + UserDefinedTableType + + + + + Table + View + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + StoredProcedure + UserDefinedAggregate + UserDefinedFunction + + + + + + + + + + + + diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs new file mode 100644 index 0000000000..d24d04b51e --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTableCustomNode.cs @@ -0,0 +1,34 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlServer.Management.Smo; + + +// TODOKusto: Remove this file. These classes might not be needed. +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// Custom name for table + /// + internal partial class TablesChildFactory : DataSourceChildFactoryBase + { + // TODOKusto: If we are always passing DataSourceMetadataObject, stop passing object. Make it type safe. + public override string GetNodePathName(object objectMetadata) + { + return base.GetNodePathName(objectMetadata); + } + } + + /// + /// Custom name for history table + /// + internal partial class TableChildFactory : DataSourceChildFactoryBase + { + public override string GetNodePathName(object objectMetadata) + { + return base.GetNodePathName(objectMetadata); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs new file mode 100644 index 0000000000..1bfffb2743 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/SmoTreeNode.cs @@ -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 Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; +using Microsoft.Kusto.ServiceLayer.DataSource; +using Microsoft.Kusto.ServiceLayer.DataSource.Metadata; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.DataSourceModel +{ + /// + /// A Node in the tree representing a SMO-based object + /// + public class DataSourceTreeNode : TreeNode + { + public static int FolderSortPriority = 0; + private static int _nextSortPriority = FolderSortPriority + 1; // 0 is reserved for folders + + protected QueryContext context; + + public DataSourceTreeNode(IDataSource dataSource, DataSourceObjectMetadata objectMetadata) + : base(dataSource, objectMetadata) + { + } + + /// + /// Indicates which platforms a node is valid for + /// + public ValidForFlag ValidFor { get; set; } + + /// + /// Gets an incrementing sort priority value to assist in automatically sorting + /// elements in a tree + /// + public static int NextSortPriority + { + get + { + return System.Threading.Interlocked.Increment(ref _nextSortPriority); + } + } + + public virtual void CacheInfoFromModel(DataSourceObjectMetadata objectMetadata) + { + base.ObjectMetadata = objectMetadata; + NodeValue = objectMetadata.Name; + } + + public virtual DataSourceObjectMetadata GetParentObjectMetadata() + { + if (ObjectMetadata != null) + { + return ObjectMetadata; + } + // Return the parent's object, or null if it's not set / not a OETreeNode + return ParentAs()?.GetParentObjectMetadata(); + } + + public override object GetContext() + { + EnsureContextInitialized(); + return context; + } + + protected virtual void EnsureContextInitialized() + { + if (context == null) + { + DataSourceObjectMetadata oeParent = GetParentObjectMetadata(); + QueryContext parentContext = Parent?.GetContextAs(); + if (oeParent != null && parentContext != null) + { + context = parentContext.CopyWithParent(oeParent); + } + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeDefinition.xml b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeDefinition.xml new file mode 100644 index 0000000000..4c24d62b23 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeDefinition.xml @@ -0,0 +1,467 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TableTemporalType.None + TableTemporalType.SystemVersioned + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TableTemporalType.HistoryTable + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IndexKeyType.DriPrimaryKey + IndexKeyType.DriUniqueKey + + + + + + + + + + IndexKeyType.None + IndexKeyType.DriPrimaryKey + IndexKeyType.DriUniqueKey + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IndexKeyType.DriPrimaryKey + IndexKeyType.DriUniqueKey + + + + /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + UserDefinedFunctionType.Table + UserDefinedFunctionType.Inline + + + + + + + + UserDefinedFunctionType.Table + UserDefinedFunctionType.Inline + + + + + + + + + + + + + + UserDefinedFunctionType.Scalar + + + + + + + + UserDefinedFunctionType.Scalar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeGenerator.tt b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeGenerator.tt new file mode 100644 index 0000000000..2b81982fca --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/SmoModel/TreeNodeGenerator.tt @@ -0,0 +1,564 @@ +<#@ 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" #> +using System; +using System.Collections.Generic; +using System.Composition; +using Microsoft.SqlServer.Management.Smo; +using Microsoft.Kusto.ServiceLayer; +using Microsoft.Kusto.ServiceLayer.ObjectExplorer.Nodes; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer.SmoModel +{ + +<# + var directory = Path.GetDirectoryName(Host.TemplateFile); + string xmlFile = Path.Combine(directory, "TreeNodeDefinition.xml"); + + ///////// + // TODO - is Generate all the ReverseDependencies needed? + ///////// + // var allReverseDependencies = GetReverseDependencies(xmlFile); + // WriteLine(" internal static class TreeNodeRules"); + // WriteLine(" {"); + // WriteLine(" internal static Dictionary> TypeReverseDependencyMap = new Dictionary>()"); + // WriteLine(" {"); + // foreach (var reverseDependencyKey in allReverseDependencies.Keys) + // { + // bool isFirstDependentType = true; + // StringBuilder dependentListBuilder = new StringBuilder("{"); + // foreach (var dependentType in allReverseDependencies[reverseDependencyKey]) + // { + // if (isFirstDependentType) + // { + // isFirstDependentType = false; + // } + // else + // { + // dependentListBuilder.Append(","); + // } + // + // dependentListBuilder.Append(string.Format(CultureInfo.InvariantCulture, " typeof({0})", dependentType)); + // } + // dependentListBuilder.Append(" }"); + // + // WriteLine(string.Format(CultureInfo.InvariantCulture, " {{ typeof({0}), new List {1} }}", reverseDependencyKey, dependentListBuilder.ToString())); + // } + // WriteLine(" };"); + // WriteLine(" }"); + // WriteLine(""); + + ///////// + // First generate all the TreeNodes + ///////// + var allTreeNodes = GetUniqueTreeNodes(xmlFile); + foreach (var TreeNode in allTreeNodes) + { + var name = TreeNode.GetAttribute("Name"); + WriteLine(string.Format(" internal sealed partial class {0} : OETreeNode", name)); + WriteLine(" {"); + WriteLine(string.Format(" public {0}() : base()", name)); + WriteLine(" {"); + WriteLine(" NodeValue = string.Empty;"); + WriteLine(string.Format(" this.NodeType = \"{0}\";", name.Replace("TreeNode", string.Empty))); + WriteLine(string.Format(" this.NodeTypeId = NodeTypes.{0};", name.Replace("TreeNode", string.Empty))); + WriteLine(" OnInitialize();"); + WriteLine(" }"); + WriteLine(" }"); + WriteLine(""); + } + + ///////// + // Now generate all the ChildFactories + ///////// + var allNodes = GetNodes(xmlFile); + foreach (var type in allNodes) + { + XmlElement nodeElement = GetNodeElement(xmlFile, type); + var imageAttr = nodeElement.GetAttribute("Image"); + var isAlwaysLeaf = nodeElement.GetAttributeNode("IsAlwaysLeaf"); + var baseClass = nodeElement.GetAttribute("BaseClass"); + var strategy = nodeElement.GetAttribute("Strategy"); + var nodeType = nodeElement.GetAttribute("NodeType"); + var ChildQuerierTypes = nodeElement.GetAttribute("ChildQuerierTypes"); + var TreeNode = nodeElement.GetAttribute("TreeNode"); + var isAsync = nodeElement.GetAttributeNode("IsAsyncLoad"); + var disableSort = nodeElement.GetAttributeNode("DisableSort"); + + string childFactoryBaseClass = "SmoChildFactoryBase"; + + // TODO Will we need alternative child factories? If so, add code here to support this + + if (isAlwaysLeaf == null) + { + WriteLine(" [Export(typeof(ChildFactory))]"); + WriteLine(" [Shared]"); + + WriteLine(string.Format(" internal partial class {0}ChildFactory : {1}", type, childFactoryBaseClass)); + + WriteLine(" {"); + WriteLine(string.Format(" public override IEnumerable ApplicableParents() {{ return new[] {{ \"{0}\" }}; }}", type)); + + List children = GetChildren(xmlFile, type); + List filters = GetNodeFilters(xmlFile, type); + List smoProperties = GetNodeSmoProperties(xmlFile, type); + + if (filters.Count > 0) + { + WriteLine(""); + WriteLine(" public override IEnumerable Filters"); + WriteLine(" {"); + WriteLine(" get"); + WriteLine(" {"); + + WriteLine(" var filters = new List();"); + foreach (var filter in filters) + { + var propertyName = filter.GetAttribute("Property"); + var propertyType = filter.GetAttribute("Type"); + var propertyValue = filter.GetAttribute("Value"); + var validFor = filter.GetAttribute("ValidFor"); + var typeToReverse = filter.GetAttribute("TypeToReverse"); + + List filterValues = GetNodeFilterValues(xmlFile, type, propertyName); + + + WriteLine(" filters.Add(new NodeFilter"); + WriteLine(" {"); + WriteLine(string.Format(" Property = \"{0}\",", propertyName)); + WriteLine(string.Format(" Type = typeof({0}),", propertyType)); + if (!string.IsNullOrWhiteSpace(typeToReverse)) + { + WriteLine(string.Format(" TypeToReverse = typeof({0}Querier),", typeToReverse)); + } + if (!string.IsNullOrWhiteSpace(validFor)) + { + WriteLine(string.Format(" ValidFor = {0},", GetValidForFlags(validFor))); + } + if (propertyValue != null && (filterValues == null || filterValues.Count == 0)) + { + WriteLine(string.Format(" Values = new List {{ {0} }},", propertyValue)); + } + if (filterValues != null && filterValues.Count > 0) + { + string filterValueType = "object"; + if (propertyType == "Enum") + { + + } + WriteLine(string.Format(" Values = new List")); + WriteLine(string.Format(" {{")); + for(int i = 0; i < filterValues.Count; i++) + { + string separator = ""; + if (i != filterValues.Count - 1) + { + separator = ","; + } + var filterValue = filterValues[i]; + WriteLine(string.Format(" {{ {0} }}{1}", filterValue.InnerText, separator )); + + } + WriteLine(string.Format(" }}")); + } + WriteLine(" });"); + + + } + + WriteLine(" return filters;"); + WriteLine(" }"); + WriteLine(" }"); + + } + + + if (smoProperties.Count > 0) + { + WriteLine(""); + WriteLine(" public override IEnumerable SmoProperties"); + WriteLine(" {"); + WriteLine(" get"); + WriteLine(" {"); + + WriteLine(" var properties = new List();"); + foreach (var smoPropertiy in smoProperties) + { + var propertyName = smoPropertiy.GetAttribute("Name"); + var validFor = smoPropertiy.GetAttribute("ValidFor"); + + + + + WriteLine(" properties.Add(new NodeSmoProperty"); + WriteLine(" {"); + WriteLine(string.Format(" Name = \"{0}\",", propertyName)); + + if (!string.IsNullOrWhiteSpace(validFor)) + { + WriteLine(string.Format(" ValidFor = {0}", GetValidForFlags(validFor))); + } + WriteLine(" });"); + + + } + + WriteLine(" return properties;"); + WriteLine(" }"); + WriteLine(" }"); + + } + + + if (children.Count > 0) + { + WriteLine(""); + WriteLine(" protected override void OnExpandPopulateFolders(IList currentChildren, TreeNode parent)"); + WriteLine(" {"); + foreach (var child in children) + { + XmlElement childAsXmlElement = GetNodeElement(xmlFile, child.GetAttribute("Name")); + if (childAsXmlElement == null) + { + // TODO SHould we error with clear message that this needs to be fixed? + continue; + } + string childImage = childAsXmlElement.GetAttribute("Image"); + var msShippedOwned = childAsXmlElement.GetAttributeNode("IsMsShippedOwned"); + var validFor = childAsXmlElement.GetAttribute("ValidFor"); + + if (TreeNodeExists(xmlFile, child.GetAttribute("Name") + "TreeNode")) + { + WriteLine(string.Format(" currentChildren.Add(new {0}TreeNode {{ SortPriority = OETreeNode.NextSortPriority }} );", child.GetAttribute("Name"))); + } + else + { + WriteLine(" currentChildren.Add(new FolderNode {"); + WriteLine(string.Format(" NodeValue = {0},", childAsXmlElement.GetAttribute("LocLabel"))); + WriteLine(string.Format(" NodeType = \"{0}\",", "Folder")); + WriteLine(string.Format(" NodeTypeId = NodeTypes.{0},", child.GetAttribute("Name"))); + WriteLine(string.Format(" IsSystemObject = {0},", child.GetAttribute("IsSystemObject") == "1" ? "true" : "false")); + + if (msShippedOwned != null) + { + WriteLine(" IsMsShippedOwned = true,"); + } + if (!string.IsNullOrWhiteSpace(validFor)) + { + WriteLine(string.Format(" ValidFor = {0},", GetValidForFlags(validFor))); + } + WriteLine(" SortPriority = OETreeNode.NextSortPriority,"); + WriteLine(" });"); + } + } + WriteLine(" }"); + } + + if (!string.IsNullOrWhiteSpace(strategy)) + { + string[] allTypes = ChildQuerierTypes.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries); + WriteLine(""); + WriteLine(" internal override Type[] ChildQuerierTypes"); + WriteLine(" {"); + WriteLine(" get"); + WriteLine(" {"); + if (!string.IsNullOrWhiteSpace(ChildQuerierTypes)) + { + Write(" return new [] {"); + foreach (var typeToRe in allTypes) + { + Write(string.Format(" typeof({0}Querier),", typeToRe)); + } + WriteLine(" };"); + } + else + { + Write(" return new Type[0];"); + } + WriteLine(" }"); + WriteLine(" }"); + + WriteLine(""); + + WriteLine(" public override TreeNode CreateChild(TreeNode parent, object context)"); + WriteLine(" {"); + if (string.IsNullOrWhiteSpace(TreeNode)) + { + WriteLine(" var child = new OETreeNode();"); + WriteLine(" child.IsAlwaysLeaf = true;"); + + if (!string.IsNullOrEmpty(nodeType)) + { + + WriteLine(string.Format(" child.NodeType = \"{0}\";", nodeType)); + } + + } + else + { + var modelNodeChildren = GetNodeElement(xmlFile, TreeNode.Replace("TreeNode",string.Empty)); + WriteLine(string.Format(" var child = new {0}();", TreeNode)); + if (modelNodeChildren.ChildNodes.Count == 0) + { + WriteLine(" child.IsAlwaysLeaf = true;"); + } + } + if (disableSort != null) + { + WriteLine(" child.SortPriority = OETreeNode.NextSortPriority;"); + } + WriteLine(" InitializeChild(parent, child, context);"); + + + WriteLine(" return child;"); + WriteLine(" }"); + } + else if (baseClass == "ModelBased") + { + WriteLine(""); + WriteLine(" internal override Type[] ChildQuerierTypes { get {return null;} }"); + WriteLine(""); + // TODO Is reverse engineering strategy every needed? + // WriteLine(" protected override ReverseEngineeringStrategy Strategy { get {return ReverseEngineeringStrategy.None;} }"); + WriteLine(""); + WriteLine(" public override TreeNode CreateChild(TreeNode parent, object context)"); + WriteLine(" {"); + WriteLine(" return null;"); + WriteLine(" }"); + } + + WriteLine(" }"); + WriteLine(""); + } + } +#> +} + +<#+ + public static string GetValidForFlags(string validForStr) + { + List flags = new List(); + if (validForStr.Contains("Sql2005")) + { + flags.Add("ValidForFlag.Sql2005"); + } + + if (validForStr.Contains("Sql2008")) + { + flags.Add("ValidForFlag.Sql2008"); + } + + if (validForStr.Contains("Sql2012")) + { + flags.Add("ValidForFlag.Sql2012"); + } + + if (validForStr.Contains("Sql2014")) + { + flags.Add("ValidForFlag.Sql2014"); + } + + if (validForStr.Contains("Sql2016")) + { + flags.Add("ValidForFlag.Sql2016"); + } + + if (validForStr.Contains("Sql2017")) + { + flags.Add("ValidForFlag.Sql2017"); + } + + if (validForStr.Contains("AzureV12")) + { + flags.Add("ValidForFlag.AzureV12"); + } + + if (validForStr.Contains("AllOnPrem")) + { + flags.Add("ValidForFlag.AllOnPrem"); + } + if (validForStr.Contains("AllAzure")) + { + flags.Add("ValidForFlag.AllAzure"); + } + if (validForStr.Contains("NotSqlDw")) + { + flags.Add("ValidForFlag.NotSqlDw"); + } + if (validForStr == "All") + { + flags.Add("ValidForFlag.All"); + } + + return string.Join("|", flags); + } + public static string[] GetNodes(string xmlFile) + { + List typesList = new List(); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + XmlNodeList treeTypes = doc.SelectNodes("/ServerExplorerTree/Node"); + if (treeTypes != null) + { + foreach (var type in treeTypes) + { + XmlElement element = type as XmlElement; + if (element != null) + { + typesList.Add(element.GetAttribute("Name")); + } + } + } + return typesList.ToArray(); + } + + public static Dictionary> GetReverseDependencies(string xmlFile) + { + Dictionary> dependencyMap = new Dictionary>(); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + XmlNodeList treeTypes = doc.SelectNodes("/ServerExplorerTree/ReverseDependencyList/ReverseDependency"); + if (treeTypes != null) + { + foreach (var type in treeTypes) + { + XmlElement element = type as XmlElement; + if (element != null) + { + string typeName = element.GetAttribute("Type"); + string dependency = element.GetAttribute("DependsOn"); + List dependenciesForType; + if (dependencyMap.TryGetValue(typeName, out dependenciesForType)) + { + dependenciesForType.Add(dependency); + } + else + { + string[] allDepedencies = dependency.Split(new [] { ';' }, StringSplitOptions.RemoveEmptyEntries); + dependenciesForType = new List(); + dependenciesForType.AddRange(allDepedencies); + dependencyMap.Add(typeName, dependenciesForType); + } + } + } + } + return dependencyMap; + } + + public static XmlElement GetNodeElement(string xmlFile, string nodeName) + { + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + return (XmlElement)doc.SelectSingleNode(string.Format("/ServerExplorerTree/Node[@Name='{0}']", nodeName)); + } + + public static bool TreeNodeExists(string xmlFile, string TreeNode) + { + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + var found = (XmlElement)doc.SelectSingleNode(string.Format("/ServerExplorerTree/CodeGenOptions/UniqueTreeNode[@Name='{0}']", TreeNode)); + + return (found != null); + } + + public static List GetUniqueTreeNodes(string xmlFile) + { + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes("/ServerExplorerTree/CodeGenOptions/UniqueTreeNode"); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } + + public static List GetChildren(string xmlFile, string parentName) + { + XmlElement nodeElement = GetNodeElement(xmlFile, parentName); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Child", parentName)); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } + + public static List GetNodeFilters(string xmlFile, string parentName) + { + XmlElement nodeElement = GetNodeElement(xmlFile, parentName); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Filters/Filter", parentName)); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } + + + public static List GetNodeSmoProperties(string xmlFile, string parentName) + { + XmlElement nodeElement = GetNodeElement(xmlFile, parentName); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Properties/Property", parentName)); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } + + public static List GetNodeFilterValues(string xmlFile, string parentName, string filterProperty) + { + XmlElement nodeElement = GetNodeElement(xmlFile, parentName); + XmlDocument doc = new XmlDocument(); + doc.Load(xmlFile); + + List retElements = new List(); + XmlNodeList nodeList = doc.SelectNodes(string.Format("/ServerExplorerTree/Node[@Name='{0}']/Filters/Filter[@Property='{1}']/Value", parentName, filterProperty)); + foreach (var item in nodeList) + { + XmlElement itemAsElement = item as XmlElement; + if (itemAsElement != null) + { + retElements.Add(itemAsElement); + } + } + return retElements; + } +#> \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ValidForFlag.cs b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ValidForFlag.cs new file mode 100644 index 0000000000..0d6f39e686 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/ObjectExplorer/ValidForFlag.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Kusto.ServiceLayer.ObjectExplorer +{ + /// + /// Indicates which type of server a given node type is valid for + /// + [Flags] + public enum ValidForFlag + { + None = 0x00, + Sql2005 = 0x01, + Sql2008 = 0x02, + Sql2012 = 0x04, + Sql2014 = 0x08, + AzureV12 = 0x10, + Sql2016 = 0x20, + Sql2017 = 0x40, + SqlDw = 0x80, + AllOnPrem = Sql2005 | Sql2008 | Sql2012 | Sql2014 | Sql2016 | Sql2017, + AllAzure = AzureV12, + All = Sql2005 | Sql2008 | Sql2012 | Sql2014 | Sql2016 | Sql2017 | AzureV12 | SqlDw, + NotSqlDw = Sql2005 | Sql2008 | Sql2012 | Sql2014 | Sql2016 | Sql2017 | AzureV12 + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Program.cs b/src/Microsoft.Kusto.ServiceLayer/Program.cs new file mode 100644 index 0000000000..409a56cd23 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Program.cs @@ -0,0 +1,63 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.SqlTools.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; +using System.IO; +using System.Diagnostics; +//using SqlToolsContext = Microsoft.SqlTools.ServiceLayer.SqlContext.SqlToolsContext; + +namespace Microsoft.Kusto.ServiceLayer +{ + /// + /// Main application class for SQL Tools API Service Host executable + /// + internal class Program + { + /// + /// Main entry point into the SQL Tools API Service Layer + /// + internal static void Main(string[] args) + { + try + { + // read command-line arguments + ServiceLayerCommandOptions commandOptions = new ServiceLayerCommandOptions(args); + if (commandOptions.ShouldExit) + { + return; + } + + string logFilePath = commandOptions.LogFilePath; + if (string.IsNullOrWhiteSpace(logFilePath)) + { + logFilePath = Logger.GenerateLogFilePath("kustoservice"); + } + + Logger.AutoFlush = commandOptions.AutoFlushLog; + + Logger.Initialize(tracingLevel: commandOptions.TracingLevel, logFilePath: logFilePath, traceSource: "kustoservice"); + + // set up the host details and profile paths + var hostDetails = new HostDetails(version: new Version(1, 0)); + + SqlToolsContext sqlToolsContext = new SqlToolsContext(hostDetails); + ServiceHost serviceHost = HostLoader.CreateAndStartServiceHost(sqlToolsContext); + + serviceHost.WaitForExit(); + } + catch (Exception e) + { + Logger.WriteWithCallstack(TraceEventType.Critical, $"An unhandled exception occurred: {e}"); + Environment.Exit(1); + } + finally + { + Logger.Close(); + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/Properties/AssemblyInfo.cs b/src/Microsoft.Kusto.ServiceLayer/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..d46d1be403 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/Properties/AssemblyInfo.cs @@ -0,0 +1,50 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("SqlTools Editor Services Host Protocol Library")] +[assembly: AssemblyDescription("Provides message types and client/server APIs for the SqlTools Editor Services JSON protocol.")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("SqlTools Editor Services")] +[assembly: AssemblyCopyright("� Microsoft Corporation. All rights reserved.")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("78caf6c3-5955-4b15-a302-2bd6b7871d5b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] +[assembly: AssemblyInformationalVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.UnitTests")] +[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.IntegrationTests")] +[assembly: InternalsVisibleTo("Microsoft.SqlTools.ManagedBatchParser.UnitTests")] +[assembly: InternalsVisibleTo("Microsoft.SqlTools.ServiceLayer.Test.Common")] + +// Allowing internals visible access to Moq library to help testing +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs new file mode 100644 index 0000000000..60fe2d1920 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Batch.cs @@ -0,0 +1,649 @@ +// +// 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.Data; +using System.Data.Common; +using System.Diagnostics; +using System.Data.SqlClient; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage; +using Microsoft.SqlTools.Utility; +using System.Globalization; +using System.Collections.ObjectModel; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution +{ + /// + /// This class represents a batch within a query + /// + public class Batch : IDisposable + { + #region Member Variables + /// + /// For IDisposable implementation, whether or not this has been disposed + /// + private bool disposed; + + /// + /// Local time when the execution and retrieval of files is finished + /// + private DateTime executionEndTime; + + /// + /// Local time when the execution starts, specifically when the object is created + /// + private DateTime executionStartTime; + + /// + /// Whether or not any messages have been sent + /// + private bool messagesSent; + + /// + /// Factory for creating readers/writers for the output of the batch + /// + private readonly IFileStreamFactory outputFileFactory; + + /// + /// Internal representation of the result sets so we can modify internally + /// + private readonly List resultSets; + + /// + /// Special action which this batch performed + /// + private readonly SpecialAction specialAction; + + /// + /// Flag indicating whether a separate KeyInfo query should be run + /// to get the full ColumnSchema metadata. + /// + private readonly bool getFullColumnSchema; + + #endregion + + internal Batch(string batchText, SelectionData selection, int ordinalId, + IFileStreamFactory outputFileFactory, int executionCount = 1, bool getFullColumnSchema = false) + { + // Sanity check for input + Validate.IsNotNullOrEmptyString(nameof(batchText), batchText); + Validate.IsNotNull(nameof(outputFileFactory), outputFileFactory); + Validate.IsGreaterThan(nameof(ordinalId), ordinalId, 0); + + // Initialize the internal state + BatchText = batchText; + Selection = selection; + executionStartTime = DateTime.Now; + HasExecuted = false; + Id = ordinalId; + resultSets = new List(); + this.outputFileFactory = outputFileFactory; + specialAction = new SpecialAction(); + BatchExecutionCount = executionCount > 0 ? executionCount : 1; + + this.getFullColumnSchema = getFullColumnSchema; + } + + #region Events + + /// + /// Asynchronous handler for when batches are completed + /// + /// The batch that completed + public delegate Task BatchAsyncEventHandler(Batch batch); + + /// + /// Asynchronous handler for when a message is emitted by the sql connection + /// + /// The message that was emitted + public delegate Task BatchAsyncMessageHandler(ResultMessage message); + + /// + /// Event that will be called when the batch has completed execution + /// + public event BatchAsyncEventHandler BatchCompletion; + + /// + /// Event that will be called when a message has been emitted + /// + public event BatchAsyncMessageHandler BatchMessageSent; + + /// + /// Event to call when the batch has started execution + /// + public event BatchAsyncEventHandler BatchStart; + + /// + /// Event that will be called when the resultset has completed execution. It will not be + /// called from the Batch but from the ResultSet instance. + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetCompletion; + + /// + /// Event that will be called when the resultSet first becomes available. This is as soon as we start reading the results. It will not be + /// called from the Batch but from the ResultSet instance. + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetAvailable; + + /// + /// Event that will be called when additional rows in the result set are available (rowCount available has increased). It will not be + /// called from the Batch but from the ResultSet instance. + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetUpdated; + #endregion + + #region Properties + + /// + /// The text of batch that will be executed + /// + public string BatchText { get; set; } + + public int BatchExecutionCount { get; private set; } + /// + /// Localized timestamp for when the execution completed. + /// Stored in UTC ISO 8601 format; should be localized before displaying to any user + /// + public string ExecutionEndTimeStamp => executionEndTime.ToString("o"); + + /// + /// Localized timestamp for how long it took for the execution to complete + /// + public string ExecutionElapsedTime + { + get + { + TimeSpan elapsedTime = executionEndTime - executionStartTime; + return elapsedTime.ToString(); + } + } + + /// + /// Localized timestamp for when the execution began. + /// Stored in UTC ISO 8601 format; should be localized before displaying to any user + /// + public string ExecutionStartTimeStamp => executionStartTime.ToString("o"); + + /// + /// Whether or not this batch encountered an error that halted execution + /// + public bool HasError { get; set; } + + /// + /// Whether or not this batch has been executed, regardless of success or failure + /// + public bool HasExecuted { get; set; } + + /// + /// Ordinal of the batch in the query + /// + public int Id { get; } + + /// + /// The result sets of the batch execution + /// + public IList ResultSets => resultSets; + + /// + /// Property for generating a set result set summaries from the result sets + /// + public ResultSetSummary[] ResultSummaries + { + get + { + lock (resultSets) + { + return resultSets.Select(set => set.Summary).ToArray(); + } + } + } + + /// + /// Creates a based on the batch instance + /// + public BatchSummary Summary + { + get + { + // Batch summary with information available at start + BatchSummary summary = new BatchSummary + { + Id = Id, + Selection = Selection, + ExecutionStart = ExecutionStartTimeStamp, + HasError = HasError + }; + + // Add on extra details if we finished executing it + if (HasExecuted) + { + summary.ResultSetSummaries = ResultSummaries; + summary.ExecutionEnd = ExecutionEndTimeStamp; + summary.ExecutionElapsed = ExecutionElapsedTime; + summary.SpecialAction = ProcessResultSetSpecialActions(); + } + + return summary; + } + } + + /// + /// The range from the file that is this batch + /// + internal SelectionData Selection { get; set; } + + #endregion + + #region Public Methods + + /// + /// Executes this batch and captures any server messages that are returned. + /// + /// The connection to use to execute the batch + /// Token for cancelling the execution + public async Task Execute(ReliableDataSourceConnection conn, CancellationToken cancellationToken) + { + // Sanity check to make sure we haven't already run this batch + if (HasExecuted) + { + throw new InvalidOperationException("Batch has already executed."); + } + + // Notify that we've started execution + if (BatchStart != null) + { + await BatchStart(this); + } + + try + { + await DoExecute(conn, cancellationToken); + } + catch (TaskCanceledException) + { + // Cancellation isn't considered an error condition + await SendMessage(SR.QueryServiceQueryCancelled, false); + throw; + } + catch (Exception e) + { + HasError = true; + await SendMessage(SR.QueryServiceQueryFailed(e.Message), true); + throw; + } + finally + { + // Mark that we have executed + HasExecuted = true; + executionEndTime = DateTime.Now; + + // Fire an event to signify that the batch has completed + if (BatchCompletion != null) + { + await BatchCompletion(this); + } + } + + } + + private async Task DoExecute(ReliableDataSourceConnection conn, CancellationToken cancellationToken) + { + bool canContinue = true; + int timesLoop = this.BatchExecutionCount; + + await SendMessageIfExecutingMultipleTimes(SR.EE_ExecutionInfo_InitializingLoop, false); + + executionStartTime = DateTime.Now; + + while (canContinue && timesLoop > 0) + { + try + { + await ExecuteOnce(conn, cancellationToken); + } + catch (DbException dbe) + { + HasError = true; + canContinue = await UnwrapDbException(dbe); + if (canContinue) + { + // If it's a multi-batch, we notify the user that we're ignoring a single failure. + await SendMessageIfExecutingMultipleTimes(SR.EE_BatchExecutionError_Ignoring, false); + } + } + timesLoop--; + } + + await SendMessageIfExecutingMultipleTimes(string.Format(CultureInfo.CurrentCulture, SR.EE_ExecutionInfo_FinalizingLoop, this.BatchExecutionCount), false); + } + + private async Task SendMessageIfExecutingMultipleTimes(string message, bool isError) + { + if (IsExecutingMultipleTimes()) + { + await SendMessage(message, isError); + } + } + + private bool IsExecutingMultipleTimes() + { + return this.BatchExecutionCount > 1; + } + + private async Task ExecuteOnce(ReliableDataSourceConnection conn, CancellationToken cancellationToken) + { + // Make sure we haven't cancelled yet + cancellationToken.ThrowIfCancellationRequested(); + + ConnectionService.EnsureConnectionIsOpen(conn); + + // Execute the command to get back a reader + using (IDataReader reader = await conn.GetUnderlyingConnection().ExecuteQueryAsync(BatchText, cancellationToken, conn.Database)) + { + do + { + // Verify that the cancellation token hasn't been canceled + cancellationToken.ThrowIfCancellationRequested(); + + // This resultset has results (i.e. SELECT/etc queries) + ResultSet resultSet = new ResultSet(resultSets.Count, Id, outputFileFactory); + resultSet.ResultAvailable += ResultSetAvailable; + resultSet.ResultUpdated += ResultSetUpdated; + resultSet.ResultCompletion += ResultSetCompletion; + + // Add the result set to the results of the query + lock (resultSets) + { + resultSets.Add(resultSet); + } + + // Read until we hit the end of the result set + await resultSet.ReadResultToEnd(reader, cancellationToken); + + } while (reader.NextResult()); + + // If there were no messages, for whatever reason (NO COUNT set, messages + // were emitted, records returned), output a "successful" message + if (!messagesSent) + { + await SendMessage(SR.QueryServiceCompletedSuccessfully, false); + } + } + } + + /// + /// Generates a subset of the rows from a result set of the batch + /// + /// The index for selecting the result set + /// The starting row of the results + /// How many rows to retrieve + /// A subset of results + public Task GetSubset(int resultSetIndex, long startRow, int rowCount) + { + ResultSet targetResultSet; + lock (resultSets) + { + // Sanity check to make sure we have valid numbers + if (resultSetIndex < 0 || resultSetIndex >= resultSets.Count) + { + throw new ArgumentOutOfRangeException(nameof(resultSetIndex), + SR.QueryServiceSubsetResultSetOutOfRange); + } + + targetResultSet = resultSets[resultSetIndex]; + } + + // Retrieve the result set + return targetResultSet.GetSubset(startRow, rowCount); + } + + /// + /// Generates an execution plan + /// + /// The index for selecting the result set + /// An execution plan object + public Task GetExecutionPlan(int resultSetIndex) + { + ResultSet targetResultSet; + lock (resultSets) + { + // Sanity check to make sure we have valid numbers + if (resultSetIndex < 0 || resultSetIndex >= resultSets.Count) + { + throw new ArgumentOutOfRangeException(nameof(resultSetIndex), + SR.QueryServiceSubsetResultSetOutOfRange); + } + + targetResultSet = resultSets[resultSetIndex]; + } + + // Retrieve the result set + return targetResultSet.GetExecutionPlan(); + } + + /// + /// Saves a result to a file format selected by the user + /// + /// Parameters for the save as request + /// + /// Factory for creating the reader/writer pair for outputing to the selected format + /// + /// Delegate to call when request successfully completes + /// Delegate to call if the request fails + public void SaveAs(SaveResultsRequestParams saveParams, IFileStreamFactory fileFactory, + ResultSet.SaveAsAsyncEventHandler successHandler, ResultSet.SaveAsFailureAsyncEventHandler failureHandler) + { + // Get the result set to save + ResultSet resultSet; + lock (resultSets) + { + // Sanity check to make sure we have a valid result set + if (saveParams.ResultSetIndex < 0 || saveParams.ResultSetIndex >= resultSets.Count) + { + throw new ArgumentOutOfRangeException(nameof(saveParams.BatchIndex), SR.QueryServiceSubsetResultSetOutOfRange); + } + + + resultSet = resultSets[saveParams.ResultSetIndex]; + } + resultSet.SaveAs(saveParams, fileFactory, successHandler, failureHandler); + } + + #endregion + + #region Private Helpers + + private async Task SendMessage(string message, bool isError) + { + // If the message event is null, this is a no-op + if (BatchMessageSent == null) + { + return; + } + + // State that we've sent any message, and send it + messagesSent = true; + await BatchMessageSent(new ResultMessage(message, isError, Id)); + } + + /// + /// Handler for when the StatementCompleted event is fired for this batch's command. This + /// will be executed ONLY when there is a rowcount to report. If this event is not fired + /// either NOCOUNT has been set or the command doesn't affect records. + /// + /// Sender of the event + /// Arguments for the event + internal void StatementCompletedHandler(object sender, StatementCompletedEventArgs args) + { + // Add a message for the number of rows the query returned + string message = args.RecordCount == 1 + ? SR.QueryServiceAffectedOneRow + : SR.QueryServiceAffectedRows(args.RecordCount); + SendMessage(message, false).Wait(); + } + + /// + /// Delegate handler for storing messages that are returned from the server + /// + /// Object that fired the event + /// Arguments from the event + private async void ServerMessageHandler(object sender, SqlInfoMessageEventArgs args) + { + foreach (SqlError error in args.Errors) + { + await HandleSqlErrorMessage(error.Number, error.Class, error.State, error.LineNumber, error.Procedure, error.Message); + } + } + + /// + /// Handle a single SqlError's error message by processing and displaying it. The arguments come from the error being handled + /// + internal async Task HandleSqlErrorMessage(int errorNumber, byte errorClass, byte state, int lineNumber, string procedure, string message) + { + // Did the database context change (error code 5701)? + if (errorNumber == 5701) + { + return; + } + + string detailedMessage; + if (string.IsNullOrEmpty(procedure)) + { + detailedMessage = string.Format("Msg {0}, Level {1}, State {2}, Line {3}{4}{5}", + errorNumber, errorClass, state, lineNumber + (Selection != null ? Selection.StartLine : 0), + Environment.NewLine, message); + } + else + { + detailedMessage = string.Format("Msg {0}, Level {1}, State {2}, Procedure {3}, Line {4}{5}{6}", + errorNumber, errorClass, state, procedure, lineNumber, + Environment.NewLine, message); + } + + bool isError; + if (errorClass > 10) + { + isError = true; + } + else if (errorClass > 0 && errorNumber > 0) + { + isError = false; + } + else + { + isError = false; + detailedMessage = null; + } + + if (detailedMessage != null) + { + await SendMessage(detailedMessage, isError); + } + else + { + await SendMessage(message, isError); + } + + if (isError) + { + this.HasError = true; + } + } + + /// + /// Attempts to convert an to a that + /// contains much more info about Sql Server errors. The exception is then unwrapped and + /// messages are formatted and sent to the extension. If the exception cannot be + /// converted to SqlException, the message is written to the messages list. + /// + /// The exception to unwrap + /// true is exception can be ignored when in a loop, false otherwise + private async Task UnwrapDbException(Exception dbe) + { + bool canIgnore = true; + SqlException se = dbe as SqlException; + if (se != null) + { + var errors = se.Errors.Cast().ToList(); + + // Detect user cancellation errors + if (errors.Any(error => error.Class == 11 && error.Number == 0)) + { + // User cancellation error, add the single message + await SendMessage(SR.QueryServiceQueryCancelled, false); + canIgnore = false; + } + else + { + // Not a user cancellation error, add all + foreach (var error in errors) + { + int lineNumber = error.LineNumber + (Selection != null ? Selection.StartLine : 0); + string message = string.Format("Msg {0}, Level {1}, State {2}, Line {3}{4}{5}", + error.Number, error.Class, error.State, lineNumber, + Environment.NewLine, error.Message); + await SendMessage(message, true); + } + } + } + else + { + await SendMessage(dbe.Message, true); + } + return canIgnore; + } + + /// + /// Aggregates all result sets in the batch into a single special action + /// + private SpecialAction ProcessResultSetSpecialActions() + { + foreach (ResultSet resultSet in resultSets) + { + specialAction.CombineSpecialAction(resultSet.Summary.SpecialAction); + } + + return specialAction; + } + + #endregion + + #region IDisposable Implementation + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + lock (resultSets) + { + foreach (ResultSet r in resultSets) + { + r.Dispose(); + } + } + } + + disposed = true; + } + + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs new file mode 100644 index 0000000000..ca1edda9c9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/BatchSummary.cs @@ -0,0 +1,55 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Summary of a batch within a query + /// + public class BatchSummary + { + /// + /// Localized timestamp for how long it took for the execution to complete + /// + public string ExecutionElapsed { get; set; } + + /// + /// Localized timestamp for when the execution completed. + /// + public string ExecutionEnd { get; set; } + + /// + /// Localized timestamp for when the execution started. + /// + public string ExecutionStart { get; set; } + + /// + /// Whether or not the batch encountered an error that halted execution + /// + public bool HasError { get; set; } + + /// + /// The ID of the result set within the query results + /// + public int Id { get; set; } + + /// + /// The selection from the file for this batch + /// + public SelectionData Selection { get; set; } + + /// + /// The summaries of the result sets inside the batch + /// + public ResultSetSummary[] ResultSetSummaries { get; set; } + + /// + /// The special action of the batch + /// + public SpecialAction SpecialAction { get; set; } + + public override string ToString() => $"Batch Id:'{Id}', Elapsed:'{ExecutionElapsed}', HasError:'{HasError}'"; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs new file mode 100644 index 0000000000..528872984d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbCellValue.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Class used for internally passing results from a cell around. + /// + public class DbCellValue + { + /// + /// Display value for the cell, suitable to be passed back to the client + /// + public string DisplayValue { get; set; } + + /// + /// Whether or not the cell is NULL + /// + public bool IsNull { get; set; } + + /// + /// Culture invariant display value for the cell, this value can later be used by the client to convert back to the original value. + /// + public string InvariantCultureDisplayValue { get; set; } + + /// + /// The raw object for the cell, for use internally + /// + internal object RawObject { get; set; } + + /// + /// The internal ID for the row. Should be used when directly referencing the row for edit + /// or other purposes. + /// + public long RowId { get; set; } + + /// + /// Copies the values of this DbCellValue into another DbCellValue (or child object) + /// + /// The DbCellValue (or child) that will receive the values + public virtual void CopyTo(DbCellValue other) + { + Validate.IsNotNull(nameof(other), other); + + other.DisplayValue = DisplayValue; + other.InvariantCultureDisplayValue = InvariantCultureDisplayValue; + other.IsNull = IsNull; + other.RawObject = RawObject; + other.RowId = RowId; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbColumnWrapper.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbColumnWrapper.cs new file mode 100644 index 0000000000..9aa25811b6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/DbColumnWrapper.cs @@ -0,0 +1,352 @@ +// +// 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.Data; +using System.Data.Common; +using System.Diagnostics; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Wrapper around a DbColumn, which provides extra functionality, but can be used as a + /// regular DbColumn + /// + public class DbColumnWrapper : DbColumn + { + #region Constants + + /// + /// All types supported by the server, stored as a hash set to provide O(1) lookup + /// + private static readonly HashSet AllServerDataTypes = new HashSet + { + "bigint", + "binary", + "bit", + "char", + "datetime", + "decimal", + "float", + "image", + "int", + "money", + "nchar", + "ntext", + "nvarchar", + "real", + "uniqueidentifier", + "smalldatetime", + "smallint", + "smallmoney", + "text", + "timestamp", + "tinyint", + "varbinary", + "varchar", + "sql_variant", + "xml", + "date", + "time", + "datetimeoffset", + "datetime2" + }; + + private const string SqlXmlDataTypeName = "xml"; + private const string DbTypeXmlDataTypeName = "DBTYPE_XML"; + private const string UnknownTypeName = "unknown"; + + #endregion + + /// + /// Constructor for a DbColumnWrapper + /// + /// Most of this logic is taken from SSMS ColumnInfo class + /// The column we're wrapping around + public DbColumnWrapper(DataRow row) + { + // Set all the fields for the base + AllowDBNull = SafeGetValue(row, "AllowDBNull"); + BaseCatalogName = SafeGetValue(row, "BaseCatalogName"); + BaseColumnName = SafeGetValue(row,"BaseColumnName"); + BaseSchemaName = SafeGetValue(row,"BaseSchemaName"); + BaseServerName = SafeGetValue(row,"BaseServerName"); + BaseTableName = SafeGetValue(row, "BaseTableName"); + ColumnOrdinal = SafeGetValue(row, "ColumnOrdinal"); + ColumnSize = SafeGetValue(row, "ColumnSize"); + IsAliased = SafeGetValue(row, "IsAliased"); + IsAutoIncrement = SafeGetValue(row, "IsAutoIncrement"); + IsExpression = SafeGetValue(row, "IsExpression"); + IsHidden = SafeGetValue(row, "IsHidden"); + IsIdentity = SafeGetValue(row, "IsIdentity"); + IsKey = SafeGetValue(row, "IsKey"); + IsLong = SafeGetValue(row, "IsLong"); + IsReadOnly = SafeGetValue(row, "IsReadOnly"); + IsUnique = SafeGetValue(row, "IsUnique"); + NumericPrecision = SafeGetValue(row, "NumericPrecision"); + NumericScale = SafeGetValue(row, "NumericScale"); + UdtAssemblyQualifiedName = SafeGetValue(row, "UdtAssemblyQualifiedName"); + DataType = SafeGetValue(row, "DataType"); + DataTypeName = SafeGetValue(row, "ColumnType"); + ColumnName = SafeGetValue(row, "ColumnName"); + } + + private T SafeGetValue(DataRow row, string attribName) + { + try + { + if (row[attribName] is T value) + { + return value; + } + } + catch + { + // Ignore exceptions + } + + return default(T); + } + + public DbColumnWrapper(ColumnInfo columnInfo) + { + DataTypeName = columnInfo.DataTypeName.ToLowerInvariant(); + DetermineSqlDbType(); + DataType = TypeConvertor.ToNetType(this.SqlDbType); + if (DataType == typeof(String)) + { + this.ColumnSize = int.MaxValue; + } + AddNameAndDataFields(columnInfo.Name); + } + + + /// + /// Default constructor, used for deserializing JSON RPC only + /// + public DbColumnWrapper() + { + } + + #region Properties + + /// + /// Whether or not the column is bytes + /// + public bool IsBytes { get; private set; } + + /// + /// Whether or not the column is a character type + /// + public bool IsChars { get; private set; } + + /// + /// Whether or not the column is a SqlVariant type + /// + public bool IsSqlVariant { get; private set; } + + /// + /// Whether or not the column is a user-defined type + /// + public bool IsUdt { get; private set; } + + /// + /// Whether or not the column is XML + /// + public bool IsXml { get; set; } + + /// + /// Whether or not the column is JSON + /// + public bool IsJson { get; set; } + + /// + /// The SqlDbType of the column, for use in a SqlParameter + /// + public SqlDbType SqlDbType { get; private set; } + + /// + /// Whther this is a HierarchyId column + /// + public bool IsHierarchyId { get; set; } + + /// + /// Whether or not the column is an unknown type + /// + /// + /// Logic taken from SSDT determination of unknown columns. It may not even be possible to + /// have "unknown" column types with the .NET Core SqlClient. + /// + public bool IsUnknownType => DataType == typeof(object) && + DataTypeName.Equals(UnknownTypeName, StringComparison.OrdinalIgnoreCase); + + #endregion + + + private void DetermineSqlDbType() + { + if(string.IsNullOrEmpty(DataTypeName)) + { + SqlDbType = SqlDbType.Udt; + return; + } + + // Determine the SqlDbType + SqlDbType type; + if (Enum.TryParse(DataTypeName, true, out type)) + { + SqlDbType = type; + } + else + { + switch (DataTypeName) + { + case "numeric": + SqlDbType = SqlDbType.Decimal; + break; + case "sql_variant": + SqlDbType = SqlDbType.Variant; + break; + case "timestamp": + SqlDbType = SqlDbType.VarBinary; + break; + case "sysname": + SqlDbType = SqlDbType.NVarChar; + break; + default: + SqlDbType = DataTypeName.EndsWith(".sys.hierarchyid") ? SqlDbType.NVarChar : SqlDbType.Udt; + break; + } + } + } + + private void AddNameAndDataFields(string columnName) + { + // We want the display name for the column to always exist + ColumnName = string.IsNullOrEmpty(columnName) + ? SR.QueryServiceColumnNull + : columnName; + + switch (DataTypeName) + { + case "varchar": + case "nvarchar": + IsChars = true; + + Debug.Assert(ColumnSize.HasValue); + if (ColumnSize.Value == int.MaxValue) + { + IsLong = true; + } + break; + case "text": + case "ntext": + IsChars = true; + IsLong = true; + break; + case "xml": + IsXml = true; + IsLong = true; + break; + case "binary": + case "image": + IsBytes = true; + IsLong = true; + break; + case "varbinary": + case "rowversion": + IsBytes = true; + + Debug.Assert(ColumnSize.HasValue); + if (ColumnSize.Value == int.MaxValue) + { + IsLong = true; + } + break; + case "sql_variant": + IsSqlVariant = true; + break; + default: + if (!AllServerDataTypes.Contains(DataTypeName)) + { + // treat all UDT's as long/bytes data types to prevent the CLR from attempting + // to load the UDT assembly into our process to call ToString() on the object. + + IsUdt = true; + IsBytes = true; + IsLong = true; + } + break; + } + } + } + + + + /// + /// Convert a base data type to another base data type + /// + public sealed class TypeConvertor + { + private static Dictionary _typeMap = new Dictionary(); + + static TypeConvertor() + { + _typeMap[SqlDbType.BigInt] = typeof(Int64); + _typeMap[SqlDbType.Binary] = typeof(Byte); + _typeMap[SqlDbType.Bit] = typeof(Boolean); + _typeMap[SqlDbType.Char] = typeof(String); + _typeMap[SqlDbType.DateTime] = typeof(DateTime); + _typeMap[SqlDbType.Decimal] = typeof(Decimal); + _typeMap[SqlDbType.Float] = typeof(Double); + _typeMap[SqlDbType.Image] = typeof(Byte[]); + _typeMap[SqlDbType.Int] = typeof(Int32); + _typeMap[SqlDbType.Money] = typeof(Decimal); + _typeMap[SqlDbType.NChar] = typeof(String); + _typeMap[SqlDbType.NChar] = typeof(String); + _typeMap[SqlDbType.NChar] = typeof(String); + _typeMap[SqlDbType.NText] = typeof(String); + _typeMap[SqlDbType.NVarChar] = typeof(String); + _typeMap[SqlDbType.Real] = typeof(Single); + _typeMap[SqlDbType.UniqueIdentifier] = typeof(Guid); + _typeMap[SqlDbType.SmallDateTime] = typeof(DateTime); + _typeMap[SqlDbType.SmallInt] = typeof(Int16); + _typeMap[SqlDbType.SmallMoney] = typeof(Decimal); + _typeMap[SqlDbType.Text] = typeof(String); + _typeMap[SqlDbType.Timestamp] = typeof(Byte[]); + _typeMap[SqlDbType.TinyInt] = typeof(Byte); + _typeMap[SqlDbType.VarBinary] = typeof(Byte[]); + _typeMap[SqlDbType.VarChar] = typeof(String); + _typeMap[SqlDbType.Variant] = typeof(Object); + // Note: treating as string + _typeMap[SqlDbType.Xml] = typeof(String); + _typeMap[SqlDbType.TinyInt] = typeof(Byte); + _typeMap[SqlDbType.TinyInt] = typeof(Byte); + _typeMap[SqlDbType.TinyInt] = typeof(Byte); + _typeMap[SqlDbType.TinyInt] = typeof(Byte); + } + + private TypeConvertor() + { + + } + + + /// + /// Convert TSQL type to .Net data type + /// + /// + /// + public static Type ToNetType(SqlDbType sqlDbType) + { + Type netType; + if (!_typeMap.TryGetValue(sqlDbType, out netType)) + { + netType = typeof(String); + } + return netType; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/BatchEvents.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/BatchEvents.cs new file mode 100644 index 0000000000..db0e023413 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/BatchEvents.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters to be sent back as part of a batch start or complete event to indicate that a + /// batch of a query started or completed. + /// + public class BatchEventParams + { + /// + /// Summary of the batch that just completed + /// + public BatchSummary BatchSummary { get; set; } + + /// + /// URI for the editor that owns the query + /// + public string OwnerUri { get; set; } + } + + public class BatchCompleteEvent + { + public static readonly + EventType Type = + EventType.Create("query/batchComplete"); + } + + public class BatchStartEvent + { + public static readonly + EventType Type = + EventType.Create("query/batchStart"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentSelectionRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentSelectionRequest.cs new file mode 100644 index 0000000000..ffbd16f11c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentSelectionRequest.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters for executing a query from a document open in the workspace + /// + public class ExecuteDocumentSelectionParams : ExecuteRequestParamsBase + { + /// + /// The selection from the document + /// + public SelectionData QuerySelection { get; set; } + } + + public class ExecuteDocumentSelectionRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/executeDocumentSelection"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs new file mode 100644 index 0000000000..a434bc1a74 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteDocumentStatementRequest.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters for executing a query from a document open in the workspace + /// + public class ExecuteDocumentStatementParams : ExecuteRequestParamsBase + { + /// + /// Line in the document for the location of the SQL statement + /// + public int Line { get; set; } + + /// + /// Column in the document for the location of the SQL statement + /// + public int Column { get; set; } + } + + public class ExecuteDocumentStatementRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/executedocumentstatement"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestParamsBase.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestParamsBase.cs new file mode 100644 index 0000000000..8338766f6f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestParamsBase.cs @@ -0,0 +1,28 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Basic parameters that are required for executing a query + /// + public abstract class ExecuteRequestParamsBase + { + /// + /// URI for the editor that is asking for the query execute + /// + public string OwnerUri { get; set; } + + /// + /// Execution plan options + /// + public ExecutionPlanOptions ExecutionPlanOptions { get; set; } + + /// + /// Flag to get full column schema via additional queries. + /// + public bool GetFullColumnSchema { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestResult.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestResult.cs new file mode 100644 index 0000000000..628df5abe1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteRequestResult.cs @@ -0,0 +1,13 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters for the query execute result + /// + public class ExecuteRequestResult + { + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteStringRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteStringRequest.cs new file mode 100644 index 0000000000..2566db460b --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ExecuteStringRequest.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters for executing a query directly + /// + public class ExecuteStringParams : ExecuteRequestParamsBase + { + /// + /// The query to execute + /// + public string Query { get; set; } + } + + public class ExecuteStringRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/executeString"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/MessageEvent.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/MessageEvent.cs new file mode 100644 index 0000000000..64333749f6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/MessageEvent.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters to be sent back with a message notification + /// + public class MessageParams + { + /// + /// URI for the editor that owns the query + /// + public string OwnerUri { get; set; } + + /// + /// The message that is being returned + /// + public ResultMessage Message { get; set; } + } + + public class MessageEvent + { + public static readonly + EventType Type = + EventType.Create("query/message"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/QueryCompleteEvent.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/QueryCompleteEvent.cs new file mode 100644 index 0000000000..5412630491 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/QueryCompleteEvent.cs @@ -0,0 +1,32 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters to be sent back with a query execution complete event + /// + public class QueryCompleteParams + { + /// + /// URI for the editor that owns the query + /// + public string OwnerUri { get; set; } + + /// + /// Summaries of the result sets that were returned with the query + /// + public BatchSummary[] BatchSummaries { get; set; } + } + + public class QueryCompleteEvent + { + public static readonly + EventType Type = + EventType.Create("query/complete"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ResultSetEvents.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ResultSetEvents.cs new file mode 100644 index 0000000000..6f0f81daa1 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/ResultSetEvents.cs @@ -0,0 +1,67 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Base class of parameters to return when a result set is available, updated or completed + /// + public abstract class ResultSetEventParams + { + public ResultSetSummary ResultSetSummary { get; set; } + + public string OwnerUri { get; set; } + } + + /// + /// Parameters to return when a result set is completed. + /// + public class ResultSetCompleteEventParams : ResultSetEventParams + { + } + + /// + /// Parameters to return when a result set is available. + /// + public class ResultSetAvailableEventParams : ResultSetEventParams + { + } + + /// + /// Parameters to return when a result set is updated + /// + public class ResultSetUpdatedEventParams : ResultSetEventParams + { + } + + public class ResultSetCompleteEvent + { + public static string MethodName { get; } = "query/resultSetComplete"; + + public static readonly + EventType Type = + EventType.Create(MethodName); + } + + public class ResultSetAvailableEvent + { + public static string MethodName { get; } = "query/resultSetAvailable"; + + public static readonly + EventType Type = + EventType.Create(MethodName); + } + + public class ResultSetUpdatedEvent + { + public static string MethodName { get; } = "query/resultSetUpdated"; + + public static readonly + EventType Type = + EventType.Create(MethodName); + } + +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/SimpleExecuteRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/SimpleExecuteRequest.cs new file mode 100644 index 0000000000..0291d336be --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecuteRequests/SimpleExecuteRequest.cs @@ -0,0 +1,54 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests +{ + /// + /// Parameters for executing a query from a provided string + /// + public class SimpleExecuteParams + { + /// + /// The string to execute + /// + public string QueryString { get; set; } + + /// + /// The owneruri to get connection from + /// + public string OwnerUri { get; set; } + } + + /// + /// Result + /// + public class SimpleExecuteResult + { + + /// + /// The number of rows that was returned with the resultset + /// + public long RowCount { get; set; } + + /// + /// Details about the columns that are provided as solutions + /// + public DbColumnWrapper[] ColumnInfo { get; set; } + + /// + /// 2D array of the cell values requested from result set + /// + public DbCellValue[][] Rows { get; set; } + } + + public class SimpleExecuteRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/simpleexecute"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlan.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlan.cs new file mode 100644 index 0000000000..7d840c9eef --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlan.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Class used to represent an execution plan from a query for transmission across JSON RPC + /// + public class ExecutionPlan + { + /// + /// The format of the execution plan + /// + public string Format { get; set; } + + /// + /// The execution plan content + /// + public string Content { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlanOptions.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlanOptions.cs new file mode 100644 index 0000000000..2bd3aa1b7a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ExecutionPlanOptions.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Incoming execution plan options from the extension + /// + public struct ExecutionPlanOptions + { + + /// + /// Setting to return the actual execution plan as XML + /// + public bool IncludeActualExecutionPlanXml { get; set; } + + /// + /// Setting to return the estimated execution plan as XML + /// + public bool IncludeEstimatedExecutionPlanXml { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryCancelRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryCancelRequest.cs new file mode 100644 index 0000000000..92f57b583a --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryCancelRequest.cs @@ -0,0 +1,36 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for the query cancellation request + /// + public class QueryCancelParams + { + public string OwnerUri { get; set; } + } + + /// + /// Parameters to return as the result of a query dispose request + /// + public class QueryCancelResult + { + /// + /// Any error messages that occurred during disposing the result set. Optional, can be set + /// to null if there were no errors. + /// + public string Messages { get; set; } + } + + public class QueryCancelRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/cancel"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs new file mode 100644 index 0000000000..4365a209b4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryDisposeRequest.cs @@ -0,0 +1,31 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for the query dispose request + /// + public class QueryDisposeParams + { + public string OwnerUri { get; set; } + } + + /// + /// Parameters to return as the result of a query dispose request + /// + public class QueryDisposeResult + { + } + + public class QueryDisposeRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/dispose"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryExecutionPlanRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryExecutionPlanRequest.cs new file mode 100644 index 0000000000..53e1d4ea9f --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/QueryExecutionPlanRequest.cs @@ -0,0 +1,49 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for query execution plan request + /// + public class QueryExecutionPlanParams + { + /// + /// URI for the file that owns the query to look up the results for + /// + public string OwnerUri { get; set; } + + /// + /// Index of the batch to get the results from + /// + public int BatchIndex { get; set; } + + /// + /// Index of the result set to get the results from + /// + public int ResultSetIndex { get; set; } + + } + + /// + /// Parameters for the query execution plan request + /// + public class QueryExecutionPlanResult + { + /// + /// The requested execution plan. Optional, can be set to null to indicate an error + /// + public ExecutionPlan ExecutionPlan { get; set; } + } + + public class QueryExecutionPlanRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/executionPlan"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs new file mode 100644 index 0000000000..ce1cd1d60d --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultMessage.cs @@ -0,0 +1,56 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Result message object with timestamp and actual message + /// + public class ResultMessage + { + /// + /// ID of the batch that generated this message. If null, this message + /// was not generated as part of a batch + /// + public int? BatchId { get; set; } + + /// + /// Whether or not this message is an error + /// + public bool IsError { get; set; } + + /// + /// Timestamp of the message + /// Stored in UTC ISO 8601 format; should be localized before displaying to any user + /// + public string Time { get; set; } + + /// + /// Message contents + /// + public string Message { get; set; } + + /// + /// Constructor with default "Now" time + /// + public ResultMessage(string message, bool isError, int? batchId) + { + BatchId = batchId; + IsError = isError; + Time = DateTime.Now.ToString("o"); + Message = message; + } + + /// + /// Default constructor, used for deserializing JSON RPC only + /// + public ResultMessage() + { + } + public override string ToString() => $"Message on Batch Id:'{BatchId}', IsError:'{IsError}', Message:'{Message}'"; + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs new file mode 100644 index 0000000000..5b9af07783 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSubset.cs @@ -0,0 +1,24 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Class used to represent a subset of results from a query for transmission across JSON RPC + /// + public class ResultSetSubset + { + /// + /// The number of rows returned from result set, useful for determining if less rows were + /// returned than requested. + /// + public int RowCount { get; set; } + + /// + /// 2D array of the cell values requested from result set + /// + public DbCellValue[][] Rows { get; set; } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs new file mode 100644 index 0000000000..8548b07f9c --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/ResultSetSummary.cs @@ -0,0 +1,46 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Represents a summary of information about a result without returning any cells of the results + /// + public class ResultSetSummary + { + /// + /// The ID of the result set within the batch results + /// + public int Id { get; set; } + + /// + /// The ID of the batch set within the query + /// + public int BatchId { get; set; } + + /// + /// The number of rows that are available for the resultset thus far + /// + public long RowCount { get; set; } + + /// + /// If true it indicates that all rows have been fetched and the RowCount being sent across is final for this ResultSet + /// + public bool Complete { get; set; } + + /// + /// Details about the columns that are provided as solutions + /// + public DbColumnWrapper[] ColumnInfo { get; set; } + + /// + /// The special action definition of the result set + /// + public SpecialAction SpecialAction { get; set; } + + public override string ToString() => $"Result Summary Id:{Id}, Batch Id:'{BatchId}', RowCount:'{RowCount}', Complete:'{Complete}', SpecialAction:'{SpecialAction}'"; + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs new file mode 100644 index 0000000000..b515791426 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SaveResultsRequest.cs @@ -0,0 +1,188 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for the save results request + /// + public class SaveResultsRequestParams + { + /// + /// The path of the file to save results in + /// + public string FilePath { get; set; } + + /// + /// Index of the batch to get the results from + /// + public int BatchIndex { get; set; } + + /// + /// Index of the result set to get the results from + /// + public int ResultSetIndex { get; set; } + + /// + /// URI for the editor that called save results + /// + public string OwnerUri { get; set; } + + /// + /// Start index of the selected rows (inclusive) + /// + public int? RowStartIndex { get; set; } + + /// + /// End index of the selected rows (inclusive) + /// + public int? RowEndIndex { get; set; } + + /// + /// Start index of the selected columns (inclusive) + /// + /// + public int? ColumnStartIndex { get; set; } + + /// + /// End index of the selected columns (inclusive) + /// + /// + public int? ColumnEndIndex { get; set; } + + /// + /// Check if request is a subset of result set or whole result set + /// + /// + internal bool IsSaveSelection + { + get + { + return ColumnStartIndex.HasValue && ColumnEndIndex.HasValue + && RowStartIndex.HasValue && RowEndIndex.HasValue; + } + } + } + + /// + /// Parameters to save results as CSV + /// + public class SaveResultsAsCsvRequestParams: SaveResultsRequestParams + { + /// + /// Include headers of columns in CSV + /// + public bool IncludeHeaders { get; set; } + + /// + /// Delimiter for separating data items in CSV + /// + public string Delimiter { get; set; } + + /// + /// either CR, CRLF or LF to seperate rows in CSV + /// + public string LineSeperator { get; set; } + + /// + /// Text identifier for alphanumeric columns in CSV + /// + public string TextIdentifier { get; set; } + + /// + /// Encoding of the CSV file + /// + public string Encoding { get; set; } + } + + /// + /// Parameters to save results as Excel + /// + public class SaveResultsAsExcelRequestParams : SaveResultsRequestParams + { + /// + /// Include headers of columns in Excel + /// + public bool IncludeHeaders { get; set; } + } + + /// + /// Parameters to save results as JSON + /// + public class SaveResultsAsJsonRequestParams: SaveResultsRequestParams + { + //TODO: define config for save as JSON + } + + /// + /// Parameters to save results as XML + /// + public class SaveResultsAsXmlRequestParams: SaveResultsRequestParams + { + /// + /// Formatting of the XML file + /// + public bool Formatted { get; set; } + + /// + /// Encoding of the XML file + /// + public string Encoding { get; set; } + } + + /// + /// Parameters for the save results result + /// + public class SaveResultRequestResult + { + /// + /// Error messages for saving to file. + /// + public string Messages { get; set; } + } + + /// + /// Request type to save results as CSV + /// + public class SaveResultsAsCsvRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/saveCsv"); + } + + /// + /// Request type to save results as Excel + /// + public class SaveResultsAsExcelRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/saveExcel"); + } + + /// + /// Request type to save results as JSON + /// + public class SaveResultsAsJsonRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/saveJson"); + } + + /// + /// Request type to save results as XML + /// + public class SaveResultsAsXmlRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/saveXml"); + } + +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SelectionData.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SelectionData.cs new file mode 100644 index 0000000000..f8beb500a4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SelectionData.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Container class for a selection range from file + /// + /// TODO: Remove this in favor of buffer range end-to-end + public class SelectionData + { + public SelectionData() { } + + public SelectionData(int startLine, int startColumn, int endLine, int endColumn) + { + StartLine = startLine; + StartColumn = startColumn; + EndLine = endLine; + EndColumn = endColumn; + } + + #region Properties + + public int EndColumn { get; set; } + + public int EndLine { get; set; } + + public int StartColumn { get; set; } + public int StartLine { get; set; } + + #endregion + + public BufferRange ToBufferRange() + { + return new BufferRange(StartLine, StartColumn, EndLine, EndColumn); + } + + public static SelectionData FromBufferRange(BufferRange range) + { + return new SelectionData + { + StartLine = range.Start.Line, + StartColumn = range.Start.Column, + EndLine = range.End.Line, + EndColumn = range.End.Column + }; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/Serialization.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/Serialization.cs new file mode 100644 index 0000000000..414b04e3c8 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/Serialization.cs @@ -0,0 +1,180 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Data; +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + + + public class ColumnInfo + { + /// + /// Name of this column + /// + public string Name { get; set; } + + public string DataTypeName { get; set; } + + public ColumnInfo() + { + } + + public ColumnInfo(string name, string dataTypeName) + { + this.Name = name; + this.DataTypeName = dataTypeName; + } + } + + public interface ISerializationParams + { + + /// + /// Path to file that the serialized results will be stored in + /// + string FilePath { get; set; } + + /// + /// Results that are to be serialized into 'SaveFormat' format + /// + DbCellValue[][] Rows { get; set; } + + /// + /// Whether the current set of Rows passed in is the last for this file + // + bool IsLastBatch { get; set; } + } + /// + /// Class used for storing results and how the results are to be serialized + /// + public class SerializeDataContinueRequestParams : ISerializationParams + { + /// + /// Path to file that the serialized results will be stored in + /// + public string FilePath { get; set; } + + /// + /// Results that are to be serialized into 'SaveFormat' format + /// + public DbCellValue[][] Rows { get; set; } + + /// + /// Whether the current set of Rows passed in is the last for this file + // + public bool IsLastBatch { get; set; } + + } + /// + /// Class used for storing results and how the results are to be serialized + /// + public class SerializeDataStartRequestParams : GeneralRequestDetails, ISerializationParams + { + /// + /// String representation of the type that service is supposed to serialize to + /// E.g. "json" or "csv" + /// + public string SaveFormat { get; set; } + + /// + /// Path to file that the serialized results will be stored in + /// + public string FilePath { get; set; } + + /// + /// Results that are to be serialized into 'SaveFormat' format + /// + public DbCellValue[][] Rows { get; set; } + + public ColumnInfo[] Columns { get; set; } + + /// + /// Whether this is the only request expected for this file. + // + public bool IsLastBatch { get; set; } + + public SerializeDataStartRequestParams() + { + } + /// + /// Constructor + /// + public SerializeDataStartRequestParams(string saveFormat, + string savePath, + DbCellValue[][] rows, + bool isLast) + { + this.SaveFormat = saveFormat; + this.FilePath = savePath; + this.Rows = Rows; + this.IsLastBatch = isLast; + } + + internal bool IncludeHeaders + { + get { return this.GetOptionValue(SerializationOptionsHelper.IncludeHeaders); } + set { this.SetOptionValue(SerializationOptionsHelper.IncludeHeaders, value); } + } + + internal string Delimiter + { + get { return this.GetOptionValue(SerializationOptionsHelper.Delimiter); } + set { this.SetOptionValue(SerializationOptionsHelper.Delimiter, value); } + } + + internal string LineSeparator + { + get { return this.GetOptionValue(SerializationOptionsHelper.LineSeparator); } + set { this.SetOptionValue(SerializationOptionsHelper.LineSeparator, value); } + } + + internal string TextIdentifier + { + get { return this.GetOptionValue(SerializationOptionsHelper.TextIdentifier); } + set { this.SetOptionValue(SerializationOptionsHelper.TextIdentifier, value); } + } + + internal string Encoding + { + get { return this.GetOptionValue(SerializationOptionsHelper.Encoding); } + set { this.SetOptionValue(SerializationOptionsHelper.Encoding, value); } + } + + internal bool Formatted + { + get { return this.GetOptionValue(SerializationOptionsHelper.Formatted); } + set { this.SetOptionValue(SerializationOptionsHelper.Formatted, value); } + } + } + + public class SerializeDataResult + { + public string Messages { get; set; } + + public bool Succeeded { get; set; } + } + + public class SerializeStartRequest + { + public static readonly RequestType Type = RequestType.Create("serialize/start"); + } + public class SerializeContinueRequest + { + public static readonly RequestType Type = RequestType.Create("serialize/continue"); + } + + class SerializationOptionsHelper + { + internal const string IncludeHeaders = "includeHeaders"; + internal const string Delimiter = "delimiter"; + internal const string LineSeparator = "lineSeparator"; + internal const string TextIdentifier = "textIdentifier"; + internal const string Encoding = "encoding"; + internal const string Formatted = "formatted"; + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SubsetRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SubsetRequest.cs new file mode 100644 index 0000000000..8f84711923 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Contracts/SubsetRequest.cs @@ -0,0 +1,61 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for a query result subset retrieval request + /// + public class SubsetParams + { + /// + /// URI for the file that owns the query to look up the results for + /// + public string OwnerUri { get; set; } + + /// + /// Index of the batch to get the results from + /// + public int BatchIndex { get; set; } + + /// + /// Index of the result set to get the results from + /// + public int ResultSetIndex { get; set; } + + /// + /// Beginning index of the rows to return from the selected resultset. This index will be + /// included in the results. + /// + public long RowsStartIndex { get; set; } + + /// + /// Number of rows to include in the result of this request. If the number of the rows + /// exceeds the number of rows available after the start index, all available rows after + /// the start index will be returned. + /// + public int RowsCount { get; set; } + } + + /// + /// Parameters for the result of a subset retrieval request + /// + public class SubsetResult + { + /// + /// The requested subset of results. Optional, can be set to null to indicate an error + /// + public ResultSetSubset ResultSubset { get; set; } + } + + public class SubsetRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/subset"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/FileStreamReadResult.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/FileStreamReadResult.cs new file mode 100644 index 0000000000..2c45203bf4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/FileStreamReadResult.cs @@ -0,0 +1,44 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Represents a value returned from a read from a file stream. This is used to eliminate ref + /// parameters used in the read methods. + /// + public struct FileStreamReadResult + { + /// + /// The total length in bytes of the value, (including the bytes used to store the length + /// of the value) + /// + /// + /// Cell values are stored such that the length of the value is stored first, then the + /// value itself is stored. Eg, a string may be stored as 0x03 0x6C 0x6F 0x6C. Under this + /// system, the value would be "lol", the length would be 3, and the total length would be + /// 4 bytes. + /// + public int TotalLength { get; set; } + + /// + /// Value of the cell + /// + public DbCellValue Value { get; set; } + + /// + /// Constructs a new FileStreamReadResult + /// + /// The value of the result, ready for consumption by a client + /// The number of bytes for the used to store the value's length and values + public FileStreamReadResult(DbCellValue value, int totalLength) + { + Value = value; + TotalLength = totalLength; + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamFactory.cs new file mode 100644 index 0000000000..753fc953a0 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamFactory.cs @@ -0,0 +1,22 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Interface for a factory that creates filesystem readers/writers + /// + public interface IFileStreamFactory + { + string CreateFile(); + + IFileStreamReader GetReader(string fileName); + + IFileStreamWriter GetWriter(string fileName); + + void DisposeFile(string fileName); + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs new file mode 100644 index 0000000000..c974326857 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamReader.cs @@ -0,0 +1,19 @@ +// +// 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.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Interface for a object that reads from the filesystem + /// + public interface IFileStreamReader : IDisposable + { + IList ReadRow(long offset, long rowId, IEnumerable columns); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamWriter.cs new file mode 100644 index 0000000000..c4043104b3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/IFileStreamWriter.cs @@ -0,0 +1,23 @@ +// +// 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.Kusto.ServiceLayer.QueryExecution.Contracts; + + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Interface for a object that writes to a filesystem wrapper + /// + public interface IFileStreamWriter : IDisposable + { + int WriteRow(StorageDataReader dataReader); + void WriteRow(IList row, IList columns); + void Seek(long offset); + void FlushBuffer(); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamFactory.cs new file mode 100644 index 0000000000..06060ff476 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamFactory.cs @@ -0,0 +1,73 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Factory for creating a reader/writer pair that will read from the temporary buffer file + /// and output to a CSV file. + /// + public class SaveAsCsvFileStreamFactory : IFileStreamFactory + { + #region Properties + + /// + /// Settings for query execution + /// + public QueryExecutionSettings QueryExecutionSettings { get; set; } + + /// + /// Parameters for the save as CSV request + /// + public SaveResultsAsCsvRequestParams SaveRequestParams { get; set; } + + #endregion + + /// + /// File names are not meant to be created with this factory. + /// + /// Thrown all times + [Obsolete] + public string CreateFile() + { + throw new NotImplementedException(); + } + + /// + /// Returns a new service buffer reader for reading results back in from the temporary buffer files, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the temp buffer file + /// Stream reader + public IFileStreamReader GetReader(string fileName) + { + return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), QueryExecutionSettings); + } + + /// + /// Returns a new CSV writer for writing results to a CSV file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the CSV output file + /// Stream writer + public IFileStreamWriter GetWriter(string fileName) + { + return new SaveAsCsvFileStreamWriter(new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite), SaveRequestParams); + } + + /// + /// Safely deletes the file + /// + /// Path to the file to delete + public void DisposeFile(string fileName) + { + FileUtilities.SafeFileDelete(fileName); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamWriter.cs new file mode 100644 index 0000000000..048fb9bfe4 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsCsvFileStreamWriter.cs @@ -0,0 +1,161 @@ +// +// 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.IO; +using System.Linq; +using System.Text; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Writer for writing rows of results to a CSV file + /// + public class SaveAsCsvFileStreamWriter : SaveAsStreamWriter + { + + #region Member Variables + + private readonly SaveResultsAsCsvRequestParams saveParams; + private bool headerWritten; + + #endregion + + /// + /// Constructor, stores the CSV specific request params locally, chains into the base + /// constructor + /// + /// FileStream to access the CSV file output + /// CSV save as request parameters + public SaveAsCsvFileStreamWriter(Stream stream, SaveResultsAsCsvRequestParams requestParams) + : base(stream, requestParams) + { + saveParams = requestParams; + } + + /// + /// Writes a row of data as a CSV row. If this is the first row and the user has requested + /// it, the headers for the column will be emitted as well. + /// + /// The data of the row to output to the file + /// + /// The entire list of columns for the result set. They will be filtered down as per the + /// request params. + /// + public override void WriteRow(IList row, IList columns) + { + char delimiter = ','; + if(!string.IsNullOrEmpty(saveParams.Delimiter)) + { + // first char in string + delimiter = saveParams.Delimiter[0]; + } + + string lineSeperator = Environment.NewLine; + if(!string.IsNullOrEmpty(saveParams.LineSeperator)) + { + lineSeperator = saveParams.LineSeperator; + } + + char textIdentifier = '"'; + if(!string.IsNullOrEmpty(saveParams.TextIdentifier)) + { + // first char in string + textIdentifier = saveParams.TextIdentifier[0]; + } + + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + int codepage; + Encoding encoding; + try + { + if(int.TryParse(saveParams.Encoding, out codepage)) + { + encoding = Encoding.GetEncoding(codepage); + } + else + { + encoding = Encoding.GetEncoding(saveParams.Encoding); + } + } + catch + { + // Fallback encoding when specified codepage is invalid + encoding = Encoding.GetEncoding("utf-8"); + } + + // Write out the header if we haven't already and the user chose to have it + if (saveParams.IncludeHeaders && !headerWritten) + { + // Build the string + var selectedColumns = columns.Skip(ColumnStartIndex ?? 0).Take(ColumnCount ?? columns.Count) + .Select(c => EncodeCsvField(c.ColumnName, delimiter, textIdentifier) ?? string.Empty); + + string headerLine = string.Join(delimiter, selectedColumns); + + // Encode it and write it out + byte[] headerBytes = encoding.GetBytes(headerLine + lineSeperator); + FileStream.Write(headerBytes, 0, headerBytes.Length); + + headerWritten = true; + } + + // Build the string for the row + var selectedCells = row.Skip(ColumnStartIndex ?? 0) + .Take(ColumnCount ?? columns.Count) + .Select(c => EncodeCsvField(c.DisplayValue, delimiter, textIdentifier)); + string rowLine = string.Join(delimiter, selectedCells); + + // Encode it and write it out + byte[] rowBytes = encoding.GetBytes(rowLine + lineSeperator); + FileStream.Write(rowBytes, 0, rowBytes.Length); + } + + /// + /// Encodes a single field for inserting into a CSV record. The following rules are applied: + /// + /// All double quotes (") are replaced with a pair of consecutive double quotes + /// + /// The entire field is also surrounded by a pair of double quotes if any of the following conditions are met: + /// + /// The field begins or ends with a space + /// The field begins or ends with a tab + /// The field contains the ListSeparator string + /// The field contains the '\n' character + /// The field contains the '\r' character + /// The field contains the '"' character + /// + /// + /// The field to encode + /// The CSV encoded version of the original field + internal static string EncodeCsvField(string field, char delimiter, char textIdentifier) + { + string strTextIdentifier = textIdentifier.ToString(); + + // Special case for nulls + if (field == null) + { + return "NULL"; + } + + // Whether this field has special characters which require it to be embedded in quotes + bool embedInQuotes = field.IndexOfAny(new[] { delimiter, '\r', '\n', textIdentifier }) >= 0 // Contains special characters + || field.StartsWith(" ") || field.EndsWith(" ") // Start/Ends with space + || field.StartsWith("\t") || field.EndsWith("\t"); // Starts/Ends with tab + + //Replace all quotes in the original field with double quotes + string ret = field.Replace(strTextIdentifier, strTextIdentifier + strTextIdentifier); + + if (embedInQuotes) + { + ret = strTextIdentifier + $"{ret}" + strTextIdentifier; + } + + return ret; + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamFactory.cs new file mode 100644 index 0000000000..afd42ea909 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamFactory.cs @@ -0,0 +1,73 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Factory for creating a reader/writer pair that will read from the temporary buffer file + /// and output to a Excel file. + /// + public class SaveAsExcelFileStreamFactory : IFileStreamFactory + { + #region Properties + + /// + /// Settings for query execution + /// + public QueryExecutionSettings QueryExecutionSettings { get; set; } + + /// + /// Parameters for the save as Excel request + /// + public SaveResultsAsExcelRequestParams SaveRequestParams { get; set; } + + #endregion + + /// + /// File names are not meant to be created with this factory. + /// + /// Thrown all times + [Obsolete] + public string CreateFile() + { + throw new NotImplementedException(); + } + + /// + /// Returns a new service buffer reader for reading results back in from the temporary buffer files, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the temp buffer file + /// Stream reader + public IFileStreamReader GetReader(string fileName) + { + return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), QueryExecutionSettings); + } + + /// + /// Returns a new Excel writer for writing results to a Excel file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the Excel output file + /// Stream writer + public IFileStreamWriter GetWriter(string fileName) + { + return new SaveAsExcelFileStreamWriter(new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite), SaveRequestParams); + } + + /// + /// Safely deletes the file + /// + /// Path to the file to delete + public void DisposeFile(string fileName) + { + FileUtilities.SafeFileDelete(fileName); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriter.cs new file mode 100644 index 0000000000..032cbf79ee --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriter.cs @@ -0,0 +1,87 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.Collections.Generic; +using System.IO; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Writer for writing rows of results to a Excel file + /// + public class SaveAsExcelFileStreamWriter : SaveAsStreamWriter + { + + #region Member Variables + + private readonly SaveResultsAsExcelRequestParams saveParams; + private bool headerWritten; + private SaveAsExcelFileStreamWriterHelper helper; + private SaveAsExcelFileStreamWriterHelper.ExcelSheet sheet; + + #endregion + + /// + /// Constructor, stores the Excel specific request params locally, chains into the base + /// constructor + /// + /// FileStream to access the Excel file output + /// Excel save as request parameters + public SaveAsExcelFileStreamWriter(Stream stream, SaveResultsAsExcelRequestParams requestParams) + : base(stream, requestParams) + { + saveParams = requestParams; + helper = new SaveAsExcelFileStreamWriterHelper(stream); + sheet = helper.AddSheet(); + } + + /// + /// Writes a row of data as a Excel row. If this is the first row and the user has requested + /// it, the headers for the column will be emitted as well. + /// + /// The data of the row to output to the file + /// + /// The entire list of columns for the result set. They will be filtered down as per the + /// request params. + /// + public override void WriteRow(IList row, IList columns) + { + int columnStart = ColumnStartIndex ?? 0; + int columnEnd = (ColumnEndIndex != null) ? ColumnEndIndex.Value + 1 : columns.Count; + + // Write out the header if we haven't already and the user chose to have it + if (saveParams.IncludeHeaders && !headerWritten) + { + sheet.AddRow(); + for (int i = columnStart; i < columnEnd; i++) + { + sheet.AddCell(columns[i].ColumnName); + } + headerWritten = true; + } + + sheet.AddRow(); + for (int i = columnStart; i < columnEnd; i++) + { + sheet.AddCell(row[i]); + } + } + + private bool disposed; + override protected void Dispose(bool disposing) + { + if (disposed) + return; + + sheet.Dispose(); + helper.Dispose(); + + disposed = true; + base.Dispose(disposing); + } + + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelper.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelper.cs new file mode 100644 index 0000000000..1164c15352 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsExcelFileStreamWriterHelper.cs @@ -0,0 +1,805 @@ +// +// 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.IO; +using System.IO.Compression; +using System.Xml; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + // A xlsx file is a zip with specific folder structure. + // http://www.ecma-international.org/publications/standards/Ecma-376.htm + + // The page number in the comments are based on + // ECMA-376, Fifth Edition, Part 1 - Fundamentals And Markup Language Reference + + // Page 75, SpreadsheetML package structure + // |- [Content_Types].xml + // |- _rels + // |- .rels + // |- xl + // |- workbook.xml + // |- styles.xml + // |- _rels + // |- workbook.xml.rels + // |- worksheets + // |- sheet1.xml + + /// + /// A helper class for write xlsx file base on ECMA-376. It tries to be minimal, + /// both in implementation and runtime allocation. + /// + /// + /// This sample shows how to use the class + /// + /// public class TestClass + /// { + /// public static int Main() + /// { + /// using (Stream stream = File.Create("test.xlsx")) + /// using (var helper = new SaveAsExcelFileStreamWriterHelper(stream, false)) + /// using (var sheet = helper.AddSheet()) + /// { + /// sheet.AddRow(); + /// sheet.AddCell("string"); + /// } + /// } + /// } + /// + /// + + internal sealed class SaveAsExcelFileStreamWriterHelper : IDisposable + { + /// + /// Present a Excel sheet + /// + public sealed class ExcelSheet : IDisposable + { + // The excel epoch is 1/1/1900, but it has 1/0/1900 and 2/29/1900 + // which is equal to set the epoch back two days to 12/30/1899 + // new DateTime(1899,12,30).Ticks + private const long ExcelEpochTick = 599264352000000000L; + + // Excel can not use date before 1/0/1900 and + // date before 3/1/1900 is wrong, off by 1 because of 2/29/1900 + // thus, for any date before 3/1/1900, use string for date + // new DateTime(1900,3,1).Ticks + private const long ExcelDateCutoffTick = 599317056000000000L; + + // new TimeSpan(24,0,0).Ticks + private const long TicksPerDay = 864000000000L; + + private XmlWriter writer; + private ReferenceManager referenceManager; + private bool hasOpenRowTag; + + /// + /// Initializes a new instance of the ExcelSheet class. + /// + /// XmlWriter to write the sheet data + internal ExcelSheet(XmlWriter writer) + { + this.writer = writer; + writer.WriteStartDocument(); + writer.WriteStartElement("worksheet", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + writer.WriteAttributeString("xmlns", "r", null, "http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + writer.WriteStartElement("sheetData"); + referenceManager = new ReferenceManager(writer); + } + + /// + /// Start a new row + /// + public void AddRow() + { + EndRowIfNeeded(); + hasOpenRowTag = true; + + referenceManager.AssureRowReference(); + + writer.WriteStartElement("row"); + referenceManager.WriteAndIncreaseRowReference(); + } + + /// + /// Write a string cell + /// + /// string value to write + public void AddCell(string value) + { + // string needs string + // This class uses inlineStr instead of more common shared string table + // to improve write performance and reduce implementation complexity + referenceManager.AssureColumnReference(); + if (value == null) + { + AddCellEmpty(); + return; + } + + writer.WriteStartElement("c"); + + referenceManager.WriteAndIncreaseColumnReference(); + + writer.WriteAttributeString("t", "inlineStr"); + + writer.WriteStartElement("is"); + writer.WriteStartElement("t"); + writer.WriteValue(value); + writer.WriteEndElement(); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + + /// + /// Write a object cell + /// + /// The program will try to output number/datetime, otherwise, call the ToString + /// + public void AddCell(DbCellValue dbCellValue) + { + object o = dbCellValue.RawObject; + if (dbCellValue.IsNull || o == null) + { + AddCellEmpty(); + return; + } + switch (Type.GetTypeCode(o.GetType())) + { + case TypeCode.Boolean: + AddCell((bool)o); + break; + case TypeCode.Byte: + case TypeCode.Int16: + case TypeCode.Int32: + case TypeCode.Int64: + case TypeCode.Single: + case TypeCode.Double: + case TypeCode.Decimal: + AddCellBoxedNumber(o); + break; + case TypeCode.DateTime: + AddCell((DateTime)o); + break; + case TypeCode.String: + AddCell((string)o); + break; + default: + if (o is TimeSpan) //TimeSpan doesn't have TypeCode + { + AddCell((TimeSpan)o); + break; + } + AddCell(dbCellValue.DisplayValue); + break; + } + } + + /// + /// Close the tags and close the stream + /// + public void Dispose() + { + EndRowIfNeeded(); + writer.WriteEndElement(); // + writer.WriteEndElement(); // + writer.Dispose(); + } + + /// + /// Write a empty cell + /// + /// This only increases the internal bookmark and doesn't arcturally write out anything. + private void AddCellEmpty() + { + referenceManager.IncreaseColumnReference(); + } + + /// + /// Write a bool cell. + /// + /// + private void AddCell(bool value) + { + // Excel FALSE: 0 + // Excel TRUE: 1 + referenceManager.AssureColumnReference(); + + writer.WriteStartElement("c"); + + referenceManager.WriteAndIncreaseColumnReference(); + + writer.WriteAttributeString("t", "b"); + + writer.WriteStartElement("v"); + if (value) + { + writer.WriteValue("1"); //use string to avoid convert + } + else + { + writer.WriteValue("0"); + } + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + + /// + /// Write a TimeSpan cell. + /// + /// + private void AddCell(TimeSpan time) + { + referenceManager.AssureColumnReference(); + double excelDate = (double)time.Ticks / (double)TicksPerDay; + // The default hh:mm:ss format do not support more than 24 hours + // For that case, use the format string [h]:mm:ss + if (time.Ticks >= TicksPerDay) + { + AddCellDateTimeInternal(excelDate, Style.TimeMoreThan24Hours); + } + else + { + AddCellDateTimeInternal(excelDate, Style.Time); + } + } + + /// + /// Write a DateTime cell. + /// + /// Datetime + /// + /// If the DateTime does not have date part, it will be written as datetime and show as time only + /// If the DateTime is before 1900-03-01, save as string because excel doesn't support them. + /// Otherwise, save as datetime, and if the time is 00:00:00, show as yyyy-MM-dd. + /// Show the datetime as yyyy-MM-dd HH:mm:ss if none of the previous situations + /// + private void AddCell(DateTime dateTime) + { + referenceManager.AssureColumnReference(); + long ticks = dateTime.Ticks; + Style style = Style.DateTime; + double excelDate; + if (ticks < TicksPerDay) //date empty, time only + { + style = Style.Time; + excelDate = ((double)ticks) / (double)TicksPerDay; + } + else if (ticks < ExcelDateCutoffTick) //before excel cut-off, use string + { + AddCell(dateTime.ToString("yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture)); + return; + } + else + { + if (ticks % TicksPerDay == 0) //time empty, date only + { + style = Style.Date; + } + excelDate = ((double)(ticks - ExcelEpochTick)) / (double)TicksPerDay; + } + AddCellDateTimeInternal(excelDate, style); + } + + // number needs 12.5 + private void AddCellBoxedNumber(object number) + { + referenceManager.AssureColumnReference(); + + writer.WriteStartElement("c"); + + referenceManager.WriteAndIncreaseColumnReference(); + + writer.WriteStartElement("v"); + writer.WriteValue(number); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + + + // datetime needs 26012.451 + private void AddCellDateTimeInternal(double excelDate, Style style) + { + writer.WriteStartElement("c"); + + referenceManager.WriteAndIncreaseColumnReference(); + + writer.WriteStartAttribute("s"); + writer.WriteValue((int)style); + writer.WriteEndAttribute(); + + writer.WriteStartElement("v"); + writer.WriteValue(excelDate); + writer.WriteEndElement(); + + writer.WriteEndElement(); + } + + private void EndRowIfNeeded() + { + if (hasOpenRowTag) + { + writer.WriteEndElement(); // + } + } + + + } + + /// + /// Helper class to track the current cell reference. + /// + /// + /// SpreadsheetML cell needs a reference attribute. (e.g. r="A1"). This class is used + /// to track the current cell reference. + /// + internal class ReferenceManager + { + private int currColumn; // 0 is invalid, the first AddRow will set to 1 + private int currRow = 1; + + // In order to reduce allocation, current reference is saved in this array, + // and write to the XmlWriter through WriteChars. + // For example, when the reference has value AA15, + // The content of this array will be @AA15xxxxx, with currReferenceRowLength=2 + // and currReferenceColumnLength=2 + private char[] currReference = new char[3 + 7]; //maximal XFD1048576 + private int currReferenceRowLength; + private int currReferenceColumnLength; + + private XmlWriter writer; + + /// + /// Initializes a new instance of the ReferenceManager class. + /// + /// XmlWriter to write the reference attribute to. + public ReferenceManager(XmlWriter writer) + { + this.writer = writer; + } + + /// + /// Check that we have not write too many columns. (xlsx has a limit of 16384 columns) + /// + public void AssureColumnReference() + { + if (currColumn == 0) + { + throw new InvalidOperationException("AddRow must be called before AddCell"); + + } + if (currColumn > 16384) + { + throw new InvalidOperationException("max column number is 16384, see https://support.office.com/en-us/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3"); + } + } + + /// + /// Write out the r="A1" attribute and increase the column number of internal bookmark + /// + public void WriteAndIncreaseColumnReference() + { + writer.WriteStartAttribute("r"); + writer.WriteChars(currReference, 3 - currReferenceColumnLength, currReferenceRowLength + currReferenceColumnLength); + writer.WriteEndAttribute(); + IncreaseColumnReference(); + } + + /// + /// Increase the column of internal bookmark. + /// + public void IncreaseColumnReference() + { + // This function change the first three chars of currReference array + // The logic is simple, when a start a new row, the array is reset to @@A + // where @='A'-1. At each increase, check if the current reference is Z + // and move to AA if needed, since the maximal is 16384, or XFD, the code + // manipulates the array element directly instead of loop + char[] reference = currReference; + currColumn++; + if ('Z' == reference[2]++) + { + reference[2] = 'A'; + if (currReferenceColumnLength < 2) + { + currReferenceColumnLength = 2; + } + if ('Z' == reference[1]++) + { + reference[0]++; + reference[1] = 'A'; + currReferenceColumnLength = 3; + } + } + } + + /// + /// Check that we have not write too many rows. (xlsx has a limit of 1048576 rows) + /// + public void AssureRowReference() + { + if (currRow > 1048576) + { + throw new InvalidOperationException("max row number is 1048576, see https://support.office.com/en-us/article/Excel-specifications-and-limits-1672b34d-7043-467e-8e27-269d656771c3"); + } + } + /// + /// Write out the r="1" attribute and increase the row number of internal bookmark + /// + public void WriteAndIncreaseRowReference() + { + writer.WriteStartAttribute("r"); + writer.WriteValue(currRow); + writer.WriteEndAttribute(); + + ResetColumnReference(); //This need to be called before the increase + + currRow++; + } + + // Reset the Column Reference + // This will reset the first three chars of currReference array to '@@A' + // and the rest to the array to the string presentation of the current row. + private void ResetColumnReference() + { + currColumn = 1; + currReference[0] = currReference[1] = (char)('A' - 1); + currReference[2] = 'A'; + currReferenceColumnLength = 1; + + string rowReference = XmlConvert.ToString(currRow); + currReferenceRowLength = rowReference.Length; + rowReference.CopyTo(0, currReference, 3, rowReference.Length); + } + } + + private enum Style + { + Normal = 0, + Date = 1, + Time = 2, + DateTime = 3, + TimeMoreThan24Hours = 4, + } + + private ZipArchive zipArchive; + private List sheetNames = new List(); + private XmlWriterSettings writerSetting = new XmlWriterSettings() + { + CloseOutput = true, + }; + + /// + /// Initializes a new instance of the SaveAsExcelFileStreamWriterHelper class. + /// + /// The input or output stream. + public SaveAsExcelFileStreamWriterHelper(Stream stream) + { + zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, false); + } + + /// + /// Initializes a new instance of the SaveAsExcelFileStreamWriterHelper class. + /// + /// The input or output stream. + /// true to leave the stream open after the + /// SaveAsExcelFileStreamWriterHelper object is disposed; otherwise, false. + public SaveAsExcelFileStreamWriterHelper(Stream stream, bool leaveOpen) + { + zipArchive = new ZipArchive(stream, ZipArchiveMode.Create, leaveOpen); + } + + /// + /// Add sheet inside the Xlsx file. + /// + /// Sheet name + /// ExcelSheet for writing the sheet content + /// + /// When the sheetName is null, sheet1,shhet2,..., will be used. + /// The following charactors are not allowed in the sheetName + /// '\', '/','*','[',']',':','?' + /// + public ExcelSheet AddSheet(string sheetName = null) + { + string sheetFileName = "sheet" + (sheetNames.Count + 1); + if (sheetName == null) + { + sheetName = sheetFileName; + } + EnsureValidSheetName(sheetName); + + sheetNames.Add(sheetName); + XmlWriter sheetWriter = AddEntry($"xl/worksheets/{sheetFileName}.xml"); + return new ExcelSheet(sheetWriter); + } + + /// + /// Write out the rest of the xlsx files and release the resources used by the current instance + /// + public void Dispose() + { + WriteMinimalTemplate(); + zipArchive.Dispose(); + } + + + private XmlWriter AddEntry(string entryName) + { + ZipArchiveEntry entry = zipArchive.CreateEntry(entryName, CompressionLevel.Fastest); + return XmlWriter.Create(entry.Open(), writerSetting); + } + + //ECMA-376 page 75 + private void WriteMinimalTemplate() + { + WriteTopRel(); + WriteWorkbook(); + WriteStyle(); + WriteContentType(); + WriteWorkbookRel(); + } + + /// + /// write [Content_Types].xml + /// + /// + /// This file need to describe all the files in the zip. + /// + private void WriteContentType() + { + using (XmlWriter xw = AddEntry("[Content_Types].xml")) + { + xw.WriteStartDocument(); + xw.WriteStartElement("Types", "http://schemas.openxmlformats.org/package/2006/content-types"); + + xw.WriteStartElement("Default"); + xw.WriteAttributeString("Extension", "rels"); + xw.WriteAttributeString("ContentType", "application/vnd.openxmlformats-package.relationships+xml"); + xw.WriteEndElement(); + + xw.WriteStartElement("Override"); + xw.WriteAttributeString("PartName", "/xl/workbook.xml"); + xw.WriteAttributeString("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"); + xw.WriteEndElement(); + + xw.WriteStartElement("Override"); + xw.WriteAttributeString("PartName", "/xl/styles.xml"); + xw.WriteAttributeString("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"); + xw.WriteEndElement(); + + for (int i = 1; i <= sheetNames.Count; ++i) + { + xw.WriteStartElement("Override"); + xw.WriteAttributeString("PartName", "/xl/worksheets/sheet" + i + ".xml"); + xw.WriteAttributeString("ContentType", "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + xw.WriteEndDocument(); + } + } + + /// + /// Write _rels/.rels. This file only need to reference main workbook + /// + private void WriteTopRel() + { + using (XmlWriter xw = AddEntry("_rels/.rels")) + { + xw.WriteStartDocument(); + + xw.WriteStartElement("Relationships", "http://schemas.openxmlformats.org/package/2006/relationships"); + + xw.WriteStartElement("Relationship"); + xw.WriteAttributeString("Id", "rId1"); + xw.WriteAttributeString("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"); + xw.WriteAttributeString("Target", "xl/workbook.xml"); + xw.WriteEndElement(); + + xw.WriteEndElement(); + + xw.WriteEndDocument(); + } + } + + private static char[] invalidSheetNameCharacters = new char[] + { + '\\', '/','*','[',']',':','?' + }; + private void EnsureValidSheetName(string sheetName) + { + if (sheetName.IndexOfAny(invalidSheetNameCharacters) != -1) + { + throw new ArgumentException($"Invalid sheetname: sheetName"); + } + if (sheetNames.IndexOf(sheetName) != -1) + { + throw new ArgumentException($"Duplicate sheetName: {sheetName}"); + } + } + + /// + /// Write xl/workbook.xml. This file will references the sheets through ids in xl/_rels/workbook.xml.rels + /// + private void WriteWorkbook() + { + using (XmlWriter xw = AddEntry("xl/workbook.xml")) + { + xw.WriteStartDocument(); + xw.WriteStartElement("workbook", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + xw.WriteAttributeString("xmlns", "r", null, "http://schemas.openxmlformats.org/officeDocument/2006/relationships"); + xw.WriteStartElement("sheets"); + for (int i = 1; i <= sheetNames.Count; i++) + { + xw.WriteStartElement("sheet"); + xw.WriteAttributeString("name", sheetNames[i - 1]); + xw.WriteAttributeString("sheetId", i.ToString()); + xw.WriteAttributeString("r", "id", null, "rId" + i); + xw.WriteEndElement(); + } + xw.WriteEndDocument(); + } + } + + /// + /// Write xl/_rels/workbook.xml.rels. This file will have the paths of the style and sheets. + /// + private void WriteWorkbookRel() + { + using (XmlWriter xw = AddEntry("xl/_rels/workbook.xml.rels")) + { + xw.WriteStartDocument(); + xw.WriteStartElement("Relationships", "http://schemas.openxmlformats.org/package/2006/relationships"); + + xw.WriteStartElement("Relationship"); + xw.WriteAttributeString("Id", "rId0"); + xw.WriteAttributeString("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"); + xw.WriteAttributeString("Target", "styles.xml"); + xw.WriteEndElement(); + + for (int i = 1; i <= sheetNames.Count; i++) + { + xw.WriteStartElement("Relationship"); + xw.WriteAttributeString("Id", "rId" + i); + xw.WriteAttributeString("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet"); + xw.WriteAttributeString("Target", "worksheets/sheet" + i + ".xml"); + xw.WriteEndElement(); + } + xw.WriteEndElement(); + xw.WriteEndDocument(); + } + } + + // Write the xl/styles.xml + private void WriteStyle() + { + // the style 0 is used for general case, style 1 for date, style 2 for time and style 3 for datetime see Enum Style + // reference chain: (index start with 0) + // (in sheet1.xml) --> (by s) --> (by xfId) + // --> (by numFmtId) + // that is will reference the second element of + // then, this xf reference numFmt by name and get formatCode "hh:mm:ss" + + using (XmlWriter xw = AddEntry("xl/styles.xml")) + { + xw.WriteStartElement("styleSheet", "http://schemas.openxmlformats.org/spreadsheetml/2006/main"); + + xw.WriteStartElement("numFmts"); + xw.WriteAttributeString("count", "4"); + xw.WriteStartElement("numFmt"); + xw.WriteAttributeString("numFmtId", "166"); + xw.WriteAttributeString("formatCode", "yyyy-mm-dd"); + xw.WriteEndElement(); + xw.WriteStartElement("numFmt"); + xw.WriteAttributeString("numFmtId", "167"); + xw.WriteAttributeString("formatCode", "hh:mm:ss"); + xw.WriteEndElement(); + xw.WriteStartElement("numFmt"); + xw.WriteAttributeString("numFmtId", "168"); + xw.WriteAttributeString("formatCode", "yyyy-mm-dd hh:mm:ss"); + xw.WriteEndElement(); + xw.WriteStartElement("numFmt"); + xw.WriteAttributeString("numFmtId", "169"); + xw.WriteAttributeString("formatCode", "[h]:mm:ss"); + xw.WriteEndElement(); + xw.WriteEndElement(); //mumFmts + + + xw.WriteStartElement("fonts"); + xw.WriteAttributeString("count", "1"); + xw.WriteStartElement("font"); + xw.WriteStartElement("sz"); + xw.WriteAttributeString("val", "11"); + xw.WriteEndElement(); + xw.WriteStartElement("color"); + xw.WriteAttributeString("theme", "1"); + xw.WriteEndElement(); + xw.WriteStartElement("name"); + xw.WriteAttributeString("val", "Calibri"); + xw.WriteEndElement(); + xw.WriteStartElement("family"); + xw.WriteAttributeString("val", "2"); + xw.WriteEndElement(); + xw.WriteStartElement("scheme"); + xw.WriteAttributeString("val", "minor"); + xw.WriteEndElement(); + xw.WriteEndElement(); // font + xw.WriteEndElement(); // fonts + + xw.WriteStartElement("fills"); + xw.WriteAttributeString("count", "1"); + xw.WriteStartElement("fill"); + xw.WriteStartElement("patternFill"); + xw.WriteAttributeString("patternType", "none"); + xw.WriteEndElement(); // patternFill + xw.WriteEndElement(); // fill + xw.WriteEndElement(); // fills + + xw.WriteStartElement("borders"); + xw.WriteAttributeString("count", "1"); + xw.WriteStartElement("border"); + xw.WriteElementString("left", null); + xw.WriteElementString("right", null); + xw.WriteElementString("top", null); + xw.WriteElementString("bottom", null); + xw.WriteElementString("diagonal", null); + xw.WriteEndElement(); // board + xw.WriteEndElement(); // borders + + xw.WriteStartElement("cellStyleXfs"); + xw.WriteAttributeString("count", "1"); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("numFmtId", "0"); + xw.WriteAttributeString("fontId", "0"); + xw.WriteAttributeString("fillId", "0"); + xw.WriteAttributeString("borderId", "0"); + xw.WriteEndElement(); // xf + xw.WriteEndElement(); // cellStyleXfs + + xw.WriteStartElement("cellXfs"); + xw.WriteAttributeString("count", "5"); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteEndElement(); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("numFmtId", "166"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteAttributeString("applyNumberFormat", "1"); + xw.WriteEndElement(); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("numFmtId", "167"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteAttributeString("applyNumberFormat", "1"); + xw.WriteEndElement(); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("numFmtId", "168"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteAttributeString("applyNumberFormat", "1"); + xw.WriteEndElement(); + xw.WriteStartElement("xf"); + xw.WriteAttributeString("numFmtId", "169"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteAttributeString("applyNumberFormat", "1"); + xw.WriteEndElement(); + xw.WriteEndElement(); // cellXfs + + xw.WriteStartElement("cellStyles"); + xw.WriteAttributeString("count", "1"); + xw.WriteStartElement("cellStyle"); + xw.WriteAttributeString("name", "Normal"); + xw.WriteAttributeString("builtinId", "0"); + xw.WriteAttributeString("xfId", "0"); + xw.WriteEndElement(); // cellStyle + xw.WriteEndElement(); // cellStyles + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamFactory.cs new file mode 100644 index 0000000000..8b69ff7df9 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamFactory.cs @@ -0,0 +1,71 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + public class SaveAsJsonFileStreamFactory : IFileStreamFactory + { + + #region Properties + + /// + /// Settings for query execution + /// + public QueryExecutionSettings QueryExecutionSettings { get; set; } + + /// + /// Parameters for the save as JSON request + /// + public SaveResultsAsJsonRequestParams SaveRequestParams { get; set; } + + #endregion + + /// + /// File names are not meant to be created with this factory. + /// + /// Thrown all times + [Obsolete] + public string CreateFile() + { + throw new InvalidOperationException(); + } + + /// + /// Returns a new service buffer reader for reading results back in from the temporary buffer files, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the temp buffer file + /// Stream reader + public IFileStreamReader GetReader(string fileName) + { + return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), QueryExecutionSettings); + } + + /// + /// Returns a new JSON writer for writing results to a JSON file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the JSON output file + /// Stream writer + public IFileStreamWriter GetWriter(string fileName) + { + return new SaveAsJsonFileStreamWriter(new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite), SaveRequestParams); + } + + /// + /// Safely deletes the file + /// + /// Path to the file to delete + public void DisposeFile(string fileName) + { + FileUtilities.SafeFileDelete(fileName); + } + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamWriter.cs new file mode 100644 index 0000000000..5233fe0919 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsJsonFileStreamWriter.cs @@ -0,0 +1,111 @@ +// +// 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.IO; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Newtonsoft.Json; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Writer for writing rows of results to a JSON file. + /// + /// + /// This implements its own IDisposable because the cleanup logic closes the array that was + /// created when the writer was created. Since this behavior is different than the standard + /// file stream cleanup, the extra Dispose method was added. + /// + public class SaveAsJsonFileStreamWriter : SaveAsStreamWriter, IDisposable + { + #region Member Variables + + private readonly StreamWriter streamWriter; + private readonly JsonWriter jsonWriter; + + #endregion + + /// + /// Constructor, writes the header to the file, chains into the base constructor + /// + /// FileStream to access the JSON file output + /// JSON save as request parameters + public SaveAsJsonFileStreamWriter(Stream stream, SaveResultsRequestParams requestParams) + : base(stream, requestParams) + { + // Setup the internal state + streamWriter = new StreamWriter(stream); + jsonWriter = new JsonTextWriter(streamWriter); + jsonWriter.Formatting = Formatting.Indented; + + // Write the header of the file + jsonWriter.WriteStartArray(); + } + + /// + /// Writes a row of data as a JSON object + /// + /// The data of the row to output to the file + /// + /// The entire list of columns for the result set. They will be filtered down as per the + /// request params. + /// + public override void WriteRow(IList row, IList columns) + { + // Write the header for the object + jsonWriter.WriteStartObject(); + + // Write the items out as properties + int columnStart = ColumnStartIndex ?? 0; + int columnEnd = (ColumnEndIndex != null) ? ColumnEndIndex.Value + 1 : columns.Count; + for (int i = columnStart; i < columnEnd; i++) + { + jsonWriter.WritePropertyName(columns[i].ColumnName); + if (row[i].RawObject == null) + { + jsonWriter.WriteNull(); + } + else + { + // Try converting to column type + try + { + var value = Convert.ChangeType(row[i].DisplayValue, columns[i].DataType); + jsonWriter.WriteValue(value); + } + // Default column type as string + catch + { + jsonWriter.WriteValue(row[i].DisplayValue); + } + } + } + + // Write the footer for the object + jsonWriter.WriteEndObject(); + } + + private bool disposed = false; + /// + /// Disposes the writer by closing up the array that contains the row objects + /// + protected override void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + // Write the footer of the file + jsonWriter.WriteEndArray(); + // This closes the underlying stream, so we needn't call close on the underlying stream explicitly + jsonWriter.Close(); + } + disposed = true; + base.Dispose(disposing); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsWriterBase.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsWriterBase.cs new file mode 100644 index 0000000000..49160c0ad2 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsWriterBase.cs @@ -0,0 +1,123 @@ +// +// 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.IO; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Abstract class for implementing writers that save results to file. Stores some basic info + /// that all save as writer would need. + /// + public abstract class SaveAsStreamWriter : IFileStreamWriter + { + /// + /// Stores the internal state for the writer that will be necessary for any writer. + /// + /// The stream that will be written to + /// The SaveAs request parameters + protected SaveAsStreamWriter(Stream stream, SaveResultsRequestParams requestParams) + { + FileStream = stream; + var saveParams = requestParams; + if (requestParams.IsSaveSelection) + { + // ReSharper disable PossibleInvalidOperationException IsSaveSelection verifies these values exist + ColumnStartIndex = saveParams.ColumnStartIndex.Value; + ColumnEndIndex = saveParams.ColumnEndIndex.Value; + ColumnCount = saveParams.ColumnEndIndex.Value - saveParams.ColumnStartIndex.Value + 1; + // ReSharper restore PossibleInvalidOperationException + } + } + + #region Properties + + /// + /// Index of the first column to write to the output file + /// + protected int? ColumnStartIndex { get; private set; } + + /// + /// Number of columns to write to the output file + /// + protected int? ColumnCount { get; private set; } + + /// + /// Index of the last column to write to the output file + /// + protected int? ColumnEndIndex { get; private set; } + + /// + /// The file stream to use to write the output file + /// + protected Stream FileStream { get; private set; } + + #endregion + + /// + /// Not implemented, do not use. + /// + [Obsolete] + public int WriteRow(StorageDataReader dataReader) + { + throw new InvalidOperationException("This type of writer is meant to write values from a list of cell values only."); + } + + /// + /// Writes a row of data to the output file using the format provided by the implementing class. + /// + /// The row of data to output + /// The list of columns to output + public abstract void WriteRow(IList row, IList columns); + + /// + /// Not implemented, do not use. + /// + [Obsolete] + public void Seek(long offset) + { + throw new InvalidOperationException("SaveAs writers are meant to be written once contiguously."); + } + + /// + /// Flushes the file stream buffer + /// + public void FlushBuffer() + { + FileStream.Flush(); + } + + #region IDisposable Implementation + + private bool disposed; + + /// + /// Disposes the instance by flushing and closing the file stream + /// + /// + protected virtual void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + FileStream.Dispose(); + } + disposed = true; + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamFactory.cs new file mode 100644 index 0000000000..ab0d3439d6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamFactory.cs @@ -0,0 +1,71 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + public class SaveAsXmlFileStreamFactory : IFileStreamFactory + { + + #region Properties + + /// + /// Settings for query execution + /// + public QueryExecutionSettings QueryExecutionSettings { get; set; } + + /// + /// Parameters for the save as XML request + /// + public SaveResultsAsXmlRequestParams SaveRequestParams { get; set; } + + #endregion + + /// + /// File names are not meant to be created with this factory. + /// + /// Thrown all times + [Obsolete] + public string CreateFile() + { + throw new InvalidOperationException(); + } + + /// + /// Returns a new service buffer reader for reading results back in from the temporary buffer files, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the temp buffer file + /// Stream reader + public IFileStreamReader GetReader(string fileName) + { + return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), QueryExecutionSettings); + } + + /// + /// Returns a new XML writer for writing results to a XML file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// Path to the XML output file + /// Stream writer + public IFileStreamWriter GetWriter(string fileName) + { + return new SaveAsXmlFileStreamWriter(new FileStream(fileName, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite), SaveRequestParams); + } + + /// + /// Safely deletes the file + /// + /// Path to the file to delete + public void DisposeFile(string fileName) + { + FileUtilities.SafeFileDelete(fileName); + } + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamWriter.cs new file mode 100644 index 0000000000..a80e2139cb --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/SaveAsXmlFileStreamWriter.cs @@ -0,0 +1,142 @@ +// +// 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.IO; +using System.Text; +using System.Xml; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Writer for writing rows of results to a XML file. + /// + /// + /// This implements its own IDisposable because the cleanup logic closes the element that was + /// created when the writer was created. Since this behavior is different than the standard + /// file stream cleanup, the extra Dispose method was added. + /// + public class SaveAsXmlFileStreamWriter : SaveAsStreamWriter, IDisposable + { + // Root element name for the output XML + private const string RootElementTag = "data"; + + // Item element name which will be used for every row + private const string ItemElementTag = "row"; + + #region Member Variables + + private readonly XmlTextWriter xmlTextWriter; + + #endregion + + /// + /// Constructor, writes the header to the file, chains into the base constructor + /// + /// FileStream to access the JSON file output + /// XML save as request parameters + public SaveAsXmlFileStreamWriter(Stream stream, SaveResultsAsXmlRequestParams requestParams) + : base(stream, requestParams) + { + // Setup the internal state + var encoding = GetEncoding(requestParams); + xmlTextWriter = new XmlTextWriter(stream, encoding); + xmlTextWriter.Formatting = requestParams.Formatted ? Formatting.Indented : Formatting.None; + + //Start the document and the root element + xmlTextWriter.WriteStartDocument(); + xmlTextWriter.WriteStartElement(RootElementTag); + } + + /// + /// Writes a row of data as a XML object + /// + /// The data of the row to output to the file + /// + /// The entire list of columns for the result set. They will be filtered down as per the + /// request params. + /// + public override void WriteRow(IList row, IList columns) + { + // Write the header for the object + xmlTextWriter.WriteStartElement(ItemElementTag); + + // Write the items out as properties + int columnStart = ColumnStartIndex ?? 0; + int columnEnd = ColumnEndIndex + 1 ?? columns.Count; + for (int i = columnStart; i < columnEnd; i++) + { + // Write the column name as item tag + xmlTextWriter.WriteStartElement(columns[i].ColumnName); + + if (row[i].RawObject != null) + { + xmlTextWriter.WriteString(row[i].DisplayValue); + } + + // End the item tag + xmlTextWriter.WriteEndElement(); + } + + // Write the footer for the object + xmlTextWriter.WriteEndElement(); + } + + /// + /// Get the encoding for the XML file according to + /// + /// XML save as request parameters + /// + private Encoding GetEncoding(SaveResultsAsXmlRequestParams requestParams) + { + Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); + Encoding encoding; + try + { + if (int.TryParse(requestParams.Encoding, out var codepage)) + { + encoding = Encoding.GetEncoding(codepage); + } + else + { + encoding = Encoding.GetEncoding(requestParams.Encoding); + } + } + catch + { + // Fallback encoding when specified codepage is invalid + encoding = Encoding.GetEncoding("utf-8"); + } + + return encoding; + } + + private bool disposed = false; + + /// + /// Disposes the writer by closing up the element that contains the row objects + /// + protected override void Dispose(bool disposing) + { + if (disposed) + return; + + if (disposing) + { + // Write the footer of the file + xmlTextWriter.WriteEndElement(); + xmlTextWriter.WriteEndDocument(); + + xmlTextWriter.Close(); + xmlTextWriter.Dispose(); + } + + disposed = true; + base.Dispose(disposing); + } + } +} \ No newline at end of file diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs new file mode 100644 index 0000000000..91b02db5e6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamFactory.cs @@ -0,0 +1,66 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using System.IO; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Factory that creates file reader/writers that process rows in an internal, non-human readable file format + /// + public class ServiceBufferFileStreamFactory : IFileStreamFactory + { + #region Properties + + /// + /// The settings for query execution + /// + public QueryExecutionSettings ExecutionSettings { get; set; } + + #endregion + + /// + /// Creates a new temporary file + /// + /// The name of the temporary file + public string CreateFile() + { + return Path.GetTempFileName(); + } + + /// + /// Creates a new for reading values back from + /// an SSMS formatted buffer file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// The file to read values from + /// A + public IFileStreamReader GetReader(string fileName) + { + return new ServiceBufferFileStreamReader(new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), ExecutionSettings); + } + + /// + /// Creates a new for writing values out to an + /// SSMS formatted buffer file, file share is ReadWrite to allow concurrent reads/writes to the file. + /// + /// The file to write values to + /// A + public IFileStreamWriter GetWriter(string fileName) + { + return new ServiceBufferFileStreamWriter(new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite), ExecutionSettings); + } + + /// + /// Disposes of a file created via this factory + /// + /// The file to dispose of + public void DisposeFile(string fileName) + { + FileUtilities.SafeFileDelete(fileName); + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs new file mode 100644 index 0000000000..46f72aff13 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamReader.cs @@ -0,0 +1,552 @@ +// +// 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.Data.SqlTypes; +using System.IO; +using System.Text; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Reader for service buffer formatted file streams + /// + public class ServiceBufferFileStreamReader : IFileStreamReader + { + + #region Constants + + private const int DefaultBufferSize = 8192; + private const string DateFormatString = "yyyy-MM-dd"; + private const string TimeFormatString = "HH:mm:ss"; + + #endregion + + #region Member Variables + + private delegate FileStreamReadResult ReadMethod(long fileOffset, long rowId, DbColumnWrapper column); + + private byte[] buffer; + + private readonly QueryExecutionSettings executionSettings; + + private readonly Stream fileStream; + + private readonly Dictionary readMethods; + + #endregion + + /// + /// Constructs a new ServiceBufferFileStreamReader and initializes its state + /// + /// The filestream to read from + /// The query execution settings + public ServiceBufferFileStreamReader(Stream stream, QueryExecutionSettings settings) + { + Validate.IsNotNull(nameof(stream), stream); + Validate.IsNotNull(nameof(settings), settings); + + // Open file for reading/writing + if (!stream.CanRead || !stream.CanSeek) + { + throw new InvalidOperationException("Stream must be readable and seekable"); + } + fileStream = stream; + + executionSettings = settings; + + // Create internal buffer + buffer = new byte[DefaultBufferSize]; + + // Create the methods that will be used to read back + readMethods = new Dictionary + { + {typeof(string), (o, id, col) => ReadString(o, id)}, + {typeof(short), (o, id, col) => ReadInt16(o, id)}, + {typeof(int), (o, id, col) => ReadInt32(o, id)}, + {typeof(long), (o, id, col) => ReadInt64(o, id)}, + {typeof(byte), (o, id, col) => ReadByte(o, id)}, + {typeof(char), (o, id, col) => ReadChar(o, id)}, + {typeof(bool), (o, id, col) => ReadBoolean(o, id)}, + {typeof(double), (o, id, col) => ReadDouble(o, id)}, + {typeof(float), (o, id, col) => ReadSingle(o, id)}, + {typeof(decimal), (o, id, col) => ReadDecimal(o, id)}, + {typeof(DateTime), ReadDateTime}, + {typeof(DateTimeOffset), (o, id, col) => ReadDateTimeOffset(o, id)}, + {typeof(TimeSpan), (o, id, col) => ReadTimeSpan(o, id)}, + {typeof(byte[]), (o, id, col) => ReadBytes(o, id)}, + {typeof(Guid), (o, id, col) => ReadGuid(o, id)}, + + {typeof(SqlString), (o, id, col) => ReadString(o, id)}, + {typeof(SqlInt16), (o, id, col) => ReadInt16(o, id)}, + {typeof(SqlInt32), (o, id, col) => ReadInt32(o, id)}, + {typeof(SqlInt64), (o, id, col) => ReadInt64(o, id)}, + {typeof(SqlByte), (o, id, col) => ReadByte(o, id)}, + {typeof(SqlBoolean), (o, id, col) => ReadBoolean(o, id)}, + {typeof(SqlDouble), (o, id, col) => ReadDouble(o, id)}, + {typeof(SqlSingle), (o, id, col) => ReadSingle(o, id)}, + {typeof(SqlDecimal), (o, id, col) => ReadSqlDecimal(o, id)}, + {typeof(SqlDateTime), ReadDateTime}, + {typeof(SqlBytes), (o, id, col) => ReadBytes(o, id)}, + {typeof(SqlBinary), (o, id, col) => ReadBytes(o, id)}, + {typeof(SqlGuid), (o, id, col) => ReadGuid(o, id)}, + {typeof(SqlMoney), (o, id, col) => ReadMoney(o, id)}, + }; + } + + #region IFileStreamStorage Implementation + + /// + /// Reads a row from the file, based on the columns provided + /// + /// Offset into the file where the row starts + /// Internal ID of the row to set for all cells in this row + /// The columns that were encoded + /// The objects from the row, ready for output to the client + public IList ReadRow(long fileOffset, long rowId, IEnumerable columns) + { + // Initialize for the loop + long currentFileOffset = fileOffset; + List results = new List(); + + // Iterate over the columns + Type colType; + foreach (DbColumnWrapper column in columns) + { + colType = column.DataType; + + // Use the right read function for the type to read the data from the file + ReadMethod readFunc; + if (!readMethods.TryGetValue(colType, out readFunc)) + { + // Treat everything else as a string + readFunc = readMethods[typeof(string)]; + } + FileStreamReadResult result = readFunc(currentFileOffset, rowId, column); + currentFileOffset += result.TotalLength; + results.Add(result.Value); + } + + return results; + } + + #endregion + + #region Private Helpers + + /// + /// Creates a new buffer that is of the specified length if the buffer is not already + /// at least as long as specified. + /// + /// The minimum buffer size + private void AssureBufferLength(int newBufferLength) + { + if (buffer.Length < newBufferLength) + { + buffer = new byte[newBufferLength]; + } + } + + /// + /// Reads the value of a cell from the file wrapper, checks to see if it null using + /// , and converts it to the proper output type using + /// . + /// + /// Offset into the file to read from + /// Internal ID of the row to set on all cells in this row + /// Function to use to convert the buffer to the target type + /// + /// If provided, this function will be used to determine if the value is null + /// + /// Optional function to use to convert the object to a string. + /// Optional parameter indicates whether the culture invariant display value should be provided. + /// The expected type of the cell. Used to keep the code honest + /// The object, a display value, and the length of the value + its length + private FileStreamReadResult ReadCellHelper(long offset, long rowId, + Func convertFunc, + Func isNullFunc = null, + Func toStringFunc = null, + bool setInvariantCultureDisplayValue = false) + { + LengthResult length = ReadLength(offset); + DbCellValue result = new DbCellValue { RowId = rowId }; + + if (isNullFunc == null ? length.ValueLength == 0 : isNullFunc(length.TotalLength)) + { + result.RawObject = null; + result.DisplayValue = SR.QueryServiceCellNull; + result.IsNull = true; + } + else + { + AssureBufferLength(length.ValueLength); + fileStream.Read(buffer, 0, length.ValueLength); + T resultObject = convertFunc(length.ValueLength); + result.RawObject = resultObject; + result.DisplayValue = toStringFunc == null ? result.RawObject.ToString() : toStringFunc(resultObject); + if (setInvariantCultureDisplayValue) + { + string icDisplayValue = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}", result.RawObject); + + // Only set the value when it is different from the DisplayValue to reduce the size of the result + // + if (icDisplayValue != result.DisplayValue) + { + result.InvariantCultureDisplayValue = icDisplayValue; + } + } + result.IsNull = false; + } + + return new FileStreamReadResult(result, length.TotalLength); + } + + /// + /// Reads a short from the file at the offset provided + /// + /// Offset into the file to read the short from + /// Internal ID of the row that will be stored in the cell + /// A short + internal FileStreamReadResult ReadInt16(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt16(buffer, 0)); + } + + /// + /// Reads a int from the file at the offset provided + /// + /// Offset into the file to read the int from + /// Internal ID of the row that will be stored in the cell + /// An int + internal FileStreamReadResult ReadInt32(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt32(buffer, 0)); + } + + /// + /// Reads a long from the file at the offset provided + /// + /// Offset into the file to read the long from + /// Internal ID of the row that will be stored in the cell + /// A long + internal FileStreamReadResult ReadInt64(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToInt64(buffer, 0)); + } + + /// + /// Reads a byte from the file at the offset provided + /// + /// Offset into the file to read the byte from + /// Internal ID of the row that will be stored in the cell + /// A byte + internal FileStreamReadResult ReadByte(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => buffer[0]); + } + + /// + /// Reads a char from the file at the offset provided + /// + /// Offset into the file to read the char from + /// Internal ID of the row that will be stored in the cell + /// A char + internal FileStreamReadResult ReadChar(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToChar(buffer, 0)); + } + + /// + /// Reads a bool from the file at the offset provided + /// + /// Offset into the file to read the bool from + /// Internal ID of the row that will be stored in the cell + /// A bool + internal FileStreamReadResult ReadBoolean(long fileOffset, long rowId) + { + // Override the stringifier with numeric values if the user prefers that + return ReadCellHelper(fileOffset, rowId, length => buffer[0] == 0x1, + toStringFunc: val => executionSettings.DisplayBitAsNumber + ? val ? "1" : "0" + : val.ToString()); + } + + /// + /// Reads a single from the file at the offset provided + /// + /// Offset into the file to read the single from + /// Internal ID of the row that will be stored in the cell + /// A single + internal FileStreamReadResult ReadSingle(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToSingle(buffer, 0), setInvariantCultureDisplayValue: true); + } + + /// + /// Reads a double from the file at the offset provided + /// + /// Offset into the file to read the double from + /// Internal ID of the row that will be stored in the cell + /// A double + internal FileStreamReadResult ReadDouble(long fileOffset, long rowId) + { + return ReadCellHelper(fileOffset, rowId, length => BitConverter.ToDouble(buffer, 0), setInvariantCultureDisplayValue: true); + } + + /// + /// Reads a SqlDecimal from the file at the offset provided + /// + /// Offset into the file to read the SqlDecimal from + /// A SqlDecimal + internal FileStreamReadResult ReadSqlDecimal(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + int[] arrInt32 = new int[(length - 3) / 4]; + Buffer.BlockCopy(buffer, 3, arrInt32, 0, length - 3); + return new SqlDecimal(buffer[0], buffer[1], buffer[2] == 1, arrInt32); + }, setInvariantCultureDisplayValue: true); + } + + /// + /// Reads a decimal from the file at the offset provided + /// + /// Offset into the file to read the decimal from + /// A decimal + internal FileStreamReadResult ReadDecimal(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + int[] arrInt32 = new int[length / 4]; + Buffer.BlockCopy(buffer, 0, arrInt32, 0, length); + return new decimal(arrInt32); + }, setInvariantCultureDisplayValue: true); + } + + /// + /// Reads a DateTime from the file at the offset provided + /// + /// Offset into the file to read the DateTime from + /// Internal ID of the row that will be stored in the cell + /// Column metadata, used for determining what precision to output + /// A DateTime + internal FileStreamReadResult ReadDateTime(long offset, long rowId, DbColumnWrapper col) + { + return ReadCellHelper(offset, rowId, length => + { + long ticks = BitConverter.ToInt64(buffer, 0); + return new DateTime(ticks); + + }, null, dt => + { + // Switch based on the type of column + string formatString; + // For anything else that returns as a CLR DateTime, just show date and time + formatString = $"{DateFormatString} {TimeFormatString}"; + + return dt.ToString(formatString); + + }); + } + + /// + /// Reads a DateTimeOffset from the file at the offset provided + /// + /// Offset into the file to read the DateTimeOffset from + /// Internal ID of the row that will be stored in the cell + /// A DateTimeOffset + internal FileStreamReadResult ReadDateTimeOffset(long offset, long rowId) + { + // DateTimeOffset is represented by DateTime.Ticks followed by TimeSpan.Ticks + // both as Int64 values + return ReadCellHelper(offset, rowId, length => + { + long dtTicks = BitConverter.ToInt64(buffer, 0); + long dtOffset = BitConverter.ToInt64(buffer, 8); + return new DateTimeOffset(new DateTime(dtTicks), new TimeSpan(dtOffset)); + }, null, dt => + { + string formatString = $"{DateFormatString} {TimeFormatString}.fffffff zzz"; + + return dt.ToString(formatString); + }); + } + + /// + /// Reads a TimeSpan from the file at the offset provided + /// + /// Offset into the file to read the TimeSpan from + /// Internal ID of the row that will be stored in the cell + /// A TimeSpan + internal FileStreamReadResult ReadTimeSpan(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + long ticks = BitConverter.ToInt64(buffer, 0); + return new TimeSpan(ticks); + }); + } + + /// + /// Reads a string from the file at the offset provided + /// + /// Offset into the file to read the string from + /// Internal ID of the row that will be stored in the cell + /// A string + internal FileStreamReadResult ReadString(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + length > 0 + ? Encoding.Unicode.GetString(buffer, 0, length) + : string.Empty, totalLength => totalLength == 1); + } + + /// + /// Reads bytes from the file at the offset provided + /// + /// Offset into the file to read the bytes from + /// Internal ID of the row that will be stored in the cell + /// A byte array + internal FileStreamReadResult ReadBytes(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + byte[] output = new byte[length]; + Buffer.BlockCopy(buffer, 0, output, 0, length); + return output; + }, totalLength => totalLength == 1, + bytes => + { + StringBuilder sb = new StringBuilder("0x"); + foreach (byte b in bytes) + { + sb.AppendFormat("{0:X2}", b); + } + return sb.ToString(); + }); + } + + /// + /// Reads the bytes that make up a GUID at the offset provided + /// + /// Offset into the file to read the bytes from + /// Internal ID of the row that will be stored in the cell + /// A system guid type object + internal FileStreamReadResult ReadGuid(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + byte[] output = new byte[length]; + Buffer.BlockCopy(buffer, 0, output, 0, length); + return new Guid(output); + }, totalLength => totalLength == 1); + } + + /// + /// Reads a SqlMoney type from the offset provided + /// into a + /// + /// Offset into the file to read the value + /// Internal ID of the row that will be stored in the cell + /// A sql money type object + internal FileStreamReadResult ReadMoney(long offset, long rowId) + { + return ReadCellHelper(offset, rowId, length => + { + int[] arrInt32 = new int[length / 4]; + Buffer.BlockCopy(buffer, 0, arrInt32, 0, length); + return new SqlMoney(new decimal(arrInt32)); + }); + } + + /// + /// Reads the length of a field at the specified offset in the file + /// + /// Offset into the file to read the field length from + /// A LengthResult + private LengthResult ReadLength(long offset) + { + // read in length information + int lengthValue; + fileStream.Seek(offset, SeekOrigin.Begin); + int lengthLength = fileStream.Read(buffer, 0, 1); + if (buffer[0] != 0xFF) + { + // one byte is enough + lengthValue = Convert.ToInt32(buffer[0]); + } + else + { + // read in next 4 bytes + lengthLength += fileStream.Read(buffer, 0, 4); + + // reconstruct the length + lengthValue = BitConverter.ToInt32(buffer, 0); + } + + return new LengthResult { LengthLength = lengthLength, ValueLength = lengthValue }; + } + + #endregion + + /// + /// Internal struct used for representing the length of a field from the file + /// + internal struct LengthResult + { + /// + /// How many bytes the length takes up + /// + public int LengthLength { get; set; } + + /// + /// How many bytes the value takes up + /// + public int ValueLength { get; set; } + + /// + /// + + /// + public int TotalLength => LengthLength + ValueLength; + } + + #region IDisposable Implementation + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + fileStream.Dispose(); + } + + disposed = true; + } + + ~ServiceBufferFileStreamReader() + { + Dispose(false); + } + + #endregion + + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs new file mode 100644 index 0000000000..2b50396cd6 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/ServiceBufferFileStreamWriter.cs @@ -0,0 +1,587 @@ +// +// 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.Data.SqlTypes; +using System.Diagnostics; +using System.IO; +using System.Text; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Utility; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Writer for service buffer formatted file streams + /// + public class ServiceBufferFileStreamWriter : IFileStreamWriter + { + private const int DefaultBufferLength = 8192; + + #region Member Variables + + private readonly Stream fileStream; + private readonly QueryExecutionSettings executionSettings; + + private byte[] byteBuffer; + private readonly short[] shortBuffer; + private readonly int[] intBuffer; + private readonly long[] longBuffer; + private readonly char[] charBuffer; + private readonly double[] doubleBuffer; + private readonly float[] floatBuffer; + + /// + /// Functions to use for writing various types to a file + /// + private readonly Dictionary> writeMethods; + + #endregion + + /// + /// Constructs a new writer + /// + /// The file wrapper to use as the underlying file stream + /// The query execution settings + public ServiceBufferFileStreamWriter(Stream stream, QueryExecutionSettings settings) + { + Validate.IsNotNull(nameof(stream), stream); + Validate.IsNotNull(nameof(settings), settings); + + // open file for reading/writing + if (!stream.CanWrite || !stream.CanSeek) + { + throw new InvalidOperationException("Stream must be writable and seekable."); + } + fileStream = stream; + executionSettings = settings; + + // create internal buffer + byteBuffer = new byte[DefaultBufferLength]; + + // Create internal buffers for blockcopy of contents to byte array + // Note: We create them now to avoid the overhead of creating a new array for every write call + shortBuffer = new short[1]; + intBuffer = new int[1]; + longBuffer = new long[1]; + charBuffer = new char[1]; + doubleBuffer = new double[1]; + floatBuffer = new float[1]; + + // Define what methods to use to write a type to the file + writeMethods = new Dictionary> + { + {typeof(string), val => WriteString((string) val)}, + {typeof(short), val => WriteInt16((short) val)}, + {typeof(int), val => WriteInt32((int) val)}, + {typeof(long), val => WriteInt64((long) val)}, + {typeof(byte), val => WriteByte((byte) val)}, + {typeof(char), val => WriteChar((char) val)}, + {typeof(bool), val => WriteBoolean((bool) val)}, + {typeof(double), val => WriteDouble((double) val) }, + {typeof(float), val => WriteSingle((float) val) }, + {typeof(decimal), val => WriteDecimal((decimal) val) }, + {typeof(DateTime), val => WriteDateTime((DateTime) val) }, + {typeof(DateTimeOffset), val => WriteDateTimeOffset((DateTimeOffset) val) }, + {typeof(TimeSpan), val => WriteTimeSpan((TimeSpan) val) }, + {typeof(byte[]), val => WriteBytes((byte[]) val)}, + {typeof(Guid), val => WriteGuid((Guid) val)}, + + {typeof(SqlString), val => WriteNullable((SqlString) val, obj => WriteString((string) obj))}, + {typeof(SqlInt16), val => WriteNullable((SqlInt16) val, obj => WriteInt16((short) obj))}, + {typeof(SqlInt32), val => WriteNullable((SqlInt32) val, obj => WriteInt32((int) obj))}, + {typeof(SqlInt64), val => WriteNullable((SqlInt64) val, obj => WriteInt64((long) obj)) }, + {typeof(SqlByte), val => WriteNullable((SqlByte) val, obj => WriteByte((byte) obj)) }, + {typeof(SqlBoolean), val => WriteNullable((SqlBoolean) val, obj => WriteBoolean((bool) obj)) }, + {typeof(SqlDouble), val => WriteNullable((SqlDouble) val, obj => WriteDouble((double) obj)) }, + {typeof(SqlSingle), val => WriteNullable((SqlSingle) val, obj => WriteSingle((float) obj)) }, + {typeof(SqlDecimal), val => WriteNullable((SqlDecimal) val, obj => WriteSqlDecimal((SqlDecimal) obj)) }, + {typeof(SqlDateTime), val => WriteNullable((SqlDateTime) val, obj => WriteDateTime((DateTime) obj)) }, + {typeof(SqlBytes), val => WriteNullable((SqlBytes) val, obj => WriteBytes((byte[]) obj)) }, + {typeof(SqlBinary), val => WriteNullable((SqlBinary) val, obj => WriteBytes((byte[]) obj)) }, + {typeof(SqlGuid), val => WriteNullable((SqlGuid) val, obj => WriteGuid((Guid) obj)) }, + {typeof(SqlMoney), val => WriteNullable((SqlMoney) val, obj => WriteMoney((SqlMoney) obj)) } + }; + } + + #region IFileStreamWriter Implementation + + /// + /// Writes an entire row to the file stream + /// + /// A primed reader + /// Number of bytes used to write the row + public int WriteRow(StorageDataReader reader) + { + // Read the values in from the db + object[] values = new object[reader.Columns.Length]; + if (!reader.HasLongColumns) + { + // get all record values in one shot if there are no extra long fields + reader.GetValues(values); + } + + // Loop over all the columns and write the values to the temp file + int rowBytes = 0; + for (int i = 0; i < reader.Columns.Length; i++) + { + DbColumnWrapper ci = reader.Columns[i]; + if (reader.HasLongColumns) + { + if (reader.IsDBNull(i)) + { + // Need special case for DBNull because + // reader.GetValue doesn't return DBNull in case of SqlXml and CLR type + values[i] = DBNull.Value; + } + else + { + if (ci.IsLong.HasValue && ci.IsLong.Value) + { + // this is a long field + if (ci.IsBytes) + { + values[i] = reader.GetBytesWithMaxCapacity(i, executionSettings.MaxCharsToStore); + } + else if (ci.IsChars) + { + int maxChars = ci.IsXml + ? executionSettings.MaxXmlCharsToStore + : executionSettings.MaxCharsToStore; + values[i] = reader.GetCharsWithMaxCapacity(i, maxChars); + } + else if (ci.IsXml) + { + values[i] = reader.GetXmlWithMaxCapacity(i, executionSettings.MaxXmlCharsToStore); + } + else + { + // we should never get here + Debug.Assert(false); + } + } + else + { + // not a long field + values[i] = reader.GetValue(i); + } + } + } + + // Get true type of the object + Type tVal = values[i].GetType(); + + // Write the object to a file + if (tVal == typeof(DBNull)) + { + rowBytes += WriteNull(); + } + else + { + if (ci.IsSqlVariant) + { + // serialize type information as a string before the value + string val = tVal.ToString(); + rowBytes += WriteString(val); + } + + // Use the appropriate writing method for the type + Func writeMethod; + if (writeMethods.TryGetValue(tVal, out writeMethod)) + { + rowBytes += writeMethod(values[i]); + } + else + { + rowBytes += WriteString(values[i].ToString()); + } + } + } + + // Flush the buffer after every row + FlushBuffer(); + return rowBytes; + } + + [Obsolete] + public void WriteRow(IList row, IList columns) + { + throw new InvalidOperationException("This type of writer is meant to write values from a DbDataReader only."); + } + + /// + /// Seeks to a given offset in the file, relative to the beginning of the file + /// + public void Seek(long offset) + { + fileStream.Seek(offset, SeekOrigin.Begin); + } + + /// + /// Flushes the internal buffer to the file stream + /// + public void FlushBuffer() + { + fileStream.Flush(); + } + + #endregion + + #region Private Helpers + + /// + /// Writes null to the file as one 0x00 byte + /// + /// Number of bytes used to store the null + internal int WriteNull() + { + byteBuffer[0] = 0x00; + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 1); + } + + /// + /// Writes a short to the file + /// + /// Number of bytes used to store the short + internal int WriteInt16(short val) + { + byteBuffer[0] = 0x02; // length + shortBuffer[0] = val; + Buffer.BlockCopy(shortBuffer, 0, byteBuffer, 1, 2); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 3); + } + + /// + /// Writes a int to the file + /// + /// Number of bytes used to store the int + internal int WriteInt32(int val) + { + byteBuffer[0] = 0x04; // length + intBuffer[0] = val; + Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 5); + } + + /// + /// Writes a long to the file + /// + /// Number of bytes used to store the long + internal int WriteInt64(long val) + { + byteBuffer[0] = 0x08; // length + longBuffer[0] = val; + Buffer.BlockCopy(longBuffer, 0, byteBuffer, 1, 8); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 9); + } + + /// + /// Writes a char to the file + /// + /// Number of bytes used to store the char + internal int WriteChar(char val) + { + byteBuffer[0] = 0x02; // length + charBuffer[0] = val; + Buffer.BlockCopy(charBuffer, 0, byteBuffer, 1, 2); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 3); + } + + /// + /// Writes a bool to the file + /// + /// Number of bytes used to store the bool + internal int WriteBoolean(bool val) + { + byteBuffer[0] = 0x01; // length + byteBuffer[1] = (byte) (val ? 0x01 : 0x00); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 2); + } + + /// + /// Writes a byte to the file + /// + /// Number of bytes used to store the byte + internal int WriteByte(byte val) + { + byteBuffer[0] = 0x01; // length + byteBuffer[1] = val; + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 2); + } + + /// + /// Writes a float to the file + /// + /// Number of bytes used to store the float + internal int WriteSingle(float val) + { + byteBuffer[0] = 0x04; // length + floatBuffer[0] = val; + Buffer.BlockCopy(floatBuffer, 0, byteBuffer, 1, 4); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 5); + } + + /// + /// Writes a double to the file + /// + /// Number of bytes used to store the double + internal int WriteDouble(double val) + { + byteBuffer[0] = 0x08; // length + doubleBuffer[0] = val; + Buffer.BlockCopy(doubleBuffer, 0, byteBuffer, 1, 8); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 9); + } + + /// + /// Writes a SqlDecimal to the file + /// + /// Number of bytes used to store the SqlDecimal + internal int WriteSqlDecimal(SqlDecimal val) + { + int[] arrInt32 = val.Data; + int iLen = 3 + (arrInt32.Length * 4); + int iTotalLen = WriteLength(iLen); // length + + // precision + byteBuffer[0] = val.Precision; + + // scale + byteBuffer[1] = val.Scale; + + // positive + byteBuffer[2] = (byte)(val.IsPositive ? 0x01 : 0x00); + + // data value + Buffer.BlockCopy(arrInt32, 0, byteBuffer, 3, iLen - 3); + iTotalLen += FileUtilities.WriteWithLength(fileStream, byteBuffer, iLen); + return iTotalLen; // len+data + } + + /// + /// Writes a decimal to the file + /// + /// Number of bytes used to store the decimal + internal int WriteDecimal(decimal val) + { + int[] arrInt32 = decimal.GetBits(val); + + int iLen = arrInt32.Length * 4; + int iTotalLen = WriteLength(iLen); // length + + Buffer.BlockCopy(arrInt32, 0, byteBuffer, 0, iLen); + iTotalLen += FileUtilities.WriteWithLength(fileStream, byteBuffer, iLen); + + return iTotalLen; // len+data + } + + /// + /// Writes a DateTime to the file + /// + /// Number of bytes used to store the DateTime + public int WriteDateTime(DateTime dtVal) + { + return WriteInt64(dtVal.Ticks); + } + + /// + /// Writes a DateTimeOffset to the file + /// + /// Number of bytes used to store the DateTimeOffset + internal int WriteDateTimeOffset(DateTimeOffset dtoVal) + { + // Write the length, which is the 2*sizeof(long) + byteBuffer[0] = 0x10; // length (16) + + // Write the two longs, the datetime and the offset + long[] longBufferOffset = new long[2]; + longBufferOffset[0] = dtoVal.Ticks; + longBufferOffset[1] = dtoVal.Offset.Ticks; + Buffer.BlockCopy(longBufferOffset, 0, byteBuffer, 1, 16); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 17); + } + + /// + /// Writes a TimeSpan to the file + /// + /// Number of bytes used to store the TimeSpan + internal int WriteTimeSpan(TimeSpan timeSpan) + { + return WriteInt64(timeSpan.Ticks); + } + + /// + /// Writes a string to the file + /// + /// Number of bytes used to store the string + internal int WriteString(string sVal) + { + Validate.IsNotNull(nameof(sVal), sVal); + + int iTotalLen; + if (0 == sVal.Length) // special case of 0 length string + { + const int iLen = 5; + + AssureBufferLength(iLen); + byteBuffer[0] = 0xFF; + byteBuffer[1] = 0x00; + byteBuffer[2] = 0x00; + byteBuffer[3] = 0x00; + byteBuffer[4] = 0x00; + + iTotalLen = FileUtilities.WriteWithLength(fileStream, byteBuffer, 5); + } + else + { + // Convert to a unicode byte array + byte[] bytes = Encoding.Unicode.GetBytes(sVal); + + // convert char array into byte array and write it out + iTotalLen = WriteLength(bytes.Length); + iTotalLen += FileUtilities.WriteWithLength(fileStream, bytes, bytes.Length); + } + return iTotalLen; // len+data + } + + /// + /// Writes a byte[] to the file + /// + /// Number of bytes used to store the byte[] + internal int WriteBytes(byte[] bytesVal) + { + Validate.IsNotNull(nameof(bytesVal), bytesVal); + + int iTotalLen; + if (bytesVal.Length == 0) // special case of 0 length byte array "0x" + { + AssureBufferLength(5); + byteBuffer[0] = 0xFF; + byteBuffer[1] = 0x00; + byteBuffer[2] = 0x00; + byteBuffer[3] = 0x00; + byteBuffer[4] = 0x00; + + iTotalLen = FileUtilities.WriteWithLength(fileStream, byteBuffer, 5); + } + else + { + iTotalLen = WriteLength(bytesVal.Length); + iTotalLen += FileUtilities.WriteWithLength(fileStream, bytesVal, bytesVal.Length); + } + return iTotalLen; // len+data + } + + /// + /// Stores a GUID value to the file by treating it as a byte array + /// + /// The GUID to write to the file + /// Number of bytes written to the file + internal int WriteGuid(Guid val) + { + byte[] guidBytes = val.ToByteArray(); + return WriteBytes(guidBytes); + } + + /// + /// Stores a SqlMoney value to the file by treating it as a decimal + /// + /// The SqlMoney value to write to the file + /// Number of bytes written to the file + internal int WriteMoney(SqlMoney val) + { + return WriteDecimal(val.Value); + } + + /// + /// Creates a new buffer that is of the specified length if the buffer is not already + /// at least as long as specified. + /// + /// The minimum buffer size + private void AssureBufferLength(int newBufferLength) + { + if (newBufferLength > byteBuffer.Length) + { + byteBuffer = new byte[byteBuffer.Length]; + } + } + + /// + /// Writes the length of the field using the appropriate number of bytes (ie, 1 if the + /// length is <255, 5 if the length is >=255) + /// + /// Number of bytes used to store the length + private int WriteLength(int iLen) + { + if (iLen < 0xFF) + { + // fits in one byte of memory only need to write one byte + int iTmp = iLen & 0x000000FF; + + byteBuffer[0] = Convert.ToByte(iTmp); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 1); + } + // The length won't fit in 1 byte, so we need to use 1 byte to signify that the length + // is a full 4 bytes. + byteBuffer[0] = 0xFF; + + // convert int32 into array of bytes + intBuffer[0] = iLen; + Buffer.BlockCopy(intBuffer, 0, byteBuffer, 1, 4); + return FileUtilities.WriteWithLength(fileStream, byteBuffer, 5); + } + + /// + /// Writes a Nullable type (generally a Sql* type) to the file. The function provided by + /// is used to write to the file if + /// is not null. is used if is null. + /// + /// The value to write to the file + /// The function to use if val is not null + /// Number of bytes used to write value to the file + private int WriteNullable(INullable val, Func valueWriteFunc) + { + return val.IsNull ? WriteNull() : valueWriteFunc(val); + } + + #endregion + + #region IDisposable Implementation + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + fileStream.Flush(); + fileStream.Dispose(); + } + + disposed = true; + } + + ~ServiceBufferFileStreamWriter() + { + Dispose(false); + } + + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/StorageDataReader.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/StorageDataReader.cs new file mode 100644 index 0000000000..1b0a13e729 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/DataStorage/StorageDataReader.cs @@ -0,0 +1,309 @@ +// +// 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.Data; +using System.Data.Common; +using System.Data.SqlClient; +using System.Data.SqlTypes; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using System.Xml; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.SqlTools.Utility; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage +{ + /// + /// Wrapper around a DbData reader to perform some special operations more simply + /// + public class StorageDataReader + { + /// + /// Constructs a new wrapper around the provided reader + /// + /// The reader to wrap around + public StorageDataReader(IDataReader reader) + { + // Sanity check to make sure there is a data reader + Validate.IsNotNull(nameof(reader), reader); + + DataReader = reader; + + // Read the columns into a set of wrappers + List columnList = new List(); + var rows = DataReader.GetSchemaTable().Rows; + + foreach (DataRow row in rows) + { + columnList.Add(new DbColumnWrapper(row)); + } + + Columns = columnList.ToArray(); + HasLongColumns = Columns.Any(column => column.IsLong.HasValue && column.IsLong.Value); + } + + #region Properties + + /// + /// All the columns that this reader currently contains + /// + public DbColumnWrapper[] Columns { get; private set; } + + /// + /// The that will be read from + /// + public IDataReader DataReader { get; private set; } + + /// + /// Whether or not any of the columns of this reader are 'long', such as nvarchar(max) + /// + public bool HasLongColumns { get; private set; } + + #endregion + + #region DbDataReader Methods + + /// + /// Pass-through to DbDataReader.ReadAsync() + /// + /// The cancellation token to use for cancelling a query + /// + public Task ReadAsync(CancellationToken cancellationToken) + { + return Task.Run(() => DataReader.Read()); + } + + /// + /// Retrieves a value + /// + /// Column ordinal + /// The value of the given column + public object GetValue(int i) + { + return DataReader.GetValue(i); + } + + /// + /// Stores all values of the current row into the provided object array + /// + /// Where to store the values from this row + public void GetValues(object[] values) + { + DataReader.GetValues(values); + } + + /// + /// Whether or not the cell of the given column at the current row is a DBNull + /// + /// Column ordinal + /// True if the cell is DBNull, false otherwise + public bool IsDBNull(int i) + { + return DataReader.IsDBNull(i); + } + + #endregion + + #region Public Methods + + /// + /// Retrieves bytes with a maximum number of bytes to return + /// + /// Column ordinal + /// Number of bytes to return at maximum + /// Byte array + public byte[] GetBytesWithMaxCapacity(int iCol, int maxNumBytesToReturn) + { + if (maxNumBytesToReturn <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxNumBytesToReturn), SR.QueryServiceDataReaderByteCountInvalid); + } + + //first, ask provider how much data it has and calculate the final # of bytes + //NOTE: -1 means that it doesn't know how much data it has + long neededLength; + long origLength = neededLength = GetBytes(iCol, 0, null, 0, 0); + if (neededLength == -1 || neededLength > maxNumBytesToReturn) + { + neededLength = maxNumBytesToReturn; + } + + //get the data up to the maxNumBytesToReturn + byte[] bytesBuffer = new byte[neededLength]; + GetBytes(iCol, 0, bytesBuffer, 0, (int)neededLength); + + //see if server sent back more data than we should return + if (origLength == -1 || origLength > neededLength) + { + //pump the rest of data from the reader and discard it right away + long dataIndex = neededLength; + const int tmpBufSize = 100000; + byte[] tmpBuf = new byte[tmpBufSize]; + while (GetBytes(iCol, dataIndex, tmpBuf, 0, tmpBufSize) == tmpBufSize) + { + dataIndex += tmpBufSize; + } + } + + return bytesBuffer; + } + + /// + /// Retrieves characters with a maximum number of charss to return + /// + /// Column ordinal + /// Number of chars to return at maximum + /// String + public string GetCharsWithMaxCapacity(int iCol, int maxCharsToReturn) + { + if (maxCharsToReturn <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxCharsToReturn), SR.QueryServiceDataReaderCharCountInvalid); + } + + //first, ask provider how much data it has and calculate the final # of chars + //NOTE: -1 means that it doesn't know how much data it has + long neededLength; + long origLength = neededLength = GetChars(iCol, 0, null, 0, 0); + if (neededLength == -1 || neededLength > maxCharsToReturn) + { + neededLength = maxCharsToReturn; + } + Debug.Assert(neededLength < int.MaxValue); + + //get the data up to maxCharsToReturn + char[] buffer = new char[neededLength]; + if (neededLength > 0) + { + GetChars(iCol, 0, buffer, 0, (int)neededLength); + } + + //see if server sent back more data than we should return + if (origLength == -1 || origLength > neededLength) + { + //pump the rest of data from the reader and discard it right away + long dataIndex = neededLength; + const int tmpBufSize = 100000; + char[] tmpBuf = new char[tmpBufSize]; + while (GetChars(iCol, dataIndex, tmpBuf, 0, tmpBufSize) == tmpBufSize) + { + dataIndex += tmpBufSize; + } + } + string res = new string(buffer); + return res; + } + + /// + /// Retrieves xml with a maximum number of bytes to return + /// + /// Column ordinal + /// Number of chars to return at maximum + /// String + public string GetXmlWithMaxCapacity(int iCol, int maxCharsToReturn) + { + if (maxCharsToReturn <= 0) + { + throw new ArgumentOutOfRangeException(nameof(maxCharsToReturn), SR.QueryServiceDataReaderXmlCountInvalid); + } + + object o = GetValue(iCol); + return o?.ToString(); + } + + #endregion + + #region Private Helpers + + private long GetBytes(int i, long dataIndex, byte[] buffer, int bufferIndex, int length) + { + return DataReader.GetBytes(i, dataIndex, buffer, bufferIndex, length); + } + + private long GetChars(int i, long dataIndex, char[] buffer, int bufferIndex, int length) + { + return DataReader.GetChars(i, dataIndex, buffer, bufferIndex, length); + } + + #endregion + + /// + /// Internal class for writing strings with a maximum capacity + /// + /// + /// This code is take almost verbatim from Microsoft.SqlServer.Management.UI.Grid, SSMS + /// DataStorage, StorageDataReader class. + /// + internal class StringWriterWithMaxCapacity : StringWriter + { + private bool stopWriting; + + private int CurrentLength + { + get { return GetStringBuilder().Length; } + } + + public StringWriterWithMaxCapacity(IFormatProvider formatProvider, int capacity) : base(formatProvider) + { + MaximumCapacity = capacity; + } + + private int MaximumCapacity { get; set; } + + public override void Write(char value) + { + if (stopWriting) { return; } + + if (CurrentLength < MaximumCapacity) + { + base.Write(value); + } + else + { + stopWriting = true; + } + } + + public override void Write(char[] buffer, int index, int count) + { + if (stopWriting) { return; } + + int curLen = CurrentLength; + if (curLen + (count - index) > MaximumCapacity) + { + stopWriting = true; + + count = MaximumCapacity - curLen + index; + if (count < 0) + { + count = 0; + } + } + base.Write(buffer, index, count); + } + + public override void Write(string value) + { + if (stopWriting) { return; } + + int curLen = CurrentLength; + if (value.Length + curLen > MaximumCapacity) + { + stopWriting = true; + base.Write(value.Substring(0, MaximumCapacity - curLen)); + } + else + { + base.Write(value); + } + } + } + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs new file mode 100644 index 0000000000..75708c23b2 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/Query.cs @@ -0,0 +1,456 @@ +// +// 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.Data.Common; +using System.Data.SqlClient; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.SqlTools.ServiceLayer.BatchParser; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.SqlTools.Utility; +using Microsoft.SqlTools.ServiceLayer.BatchParser.ExecutionEngineCode; +using System.Collections.Generic; +using System.Diagnostics; +using Microsoft.Kusto.ServiceLayer.Utility; +using System.Text; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution +{ + /// + /// Internal representation of an active query + /// + public class Query : IDisposable + { + #region Member Variables + + /// + /// Cancellation token source, used for cancelling async db actions + /// + private readonly CancellationTokenSource cancellationSource; + + /// + /// For IDisposable implementation, whether or not this object has been disposed + /// + private bool disposed; + + /// + /// The connection info associated with the file editor owner URI, used to create a new + /// connection upon execution of the query + /// + private readonly ConnectionInfo editorConnection; + + /// + /// Whether or not the execute method has been called for this query + /// + private bool hasExecuteBeenCalled; + + #endregion + + /// + /// Constructor for a query + /// + /// The text of the query to execute + /// The information of the connection to use to execute the query + /// Settings for how to execute the query, from the user + /// Factory for creating output files + public Query( + string queryText, + ConnectionInfo connection, + QueryExecutionSettings settings, + IFileStreamFactory outputFactory, + bool getFullColumnSchema = false, + bool applyExecutionSettings = false) + { + // Sanity check for input + Validate.IsNotNull(nameof(queryText), queryText); + Validate.IsNotNull(nameof(connection), connection); + Validate.IsNotNull(nameof(settings), settings); + Validate.IsNotNull(nameof(outputFactory), outputFactory); + + // Initialize the internal state + QueryText = queryText; + editorConnection = connection; + cancellationSource = new CancellationTokenSource(); + + // Process the query into batches + BatchParserWrapper parser = new BatchParserWrapper(); + ExecutionEngineConditions conditions = null; + List parserResult = parser.GetBatches(queryText, conditions); + + var batchSelection = parserResult + .Select((batchDefinition, index) => + new Batch(batchDefinition.BatchText, + new SelectionData( + batchDefinition.StartLine-1, + batchDefinition.StartColumn-1, + batchDefinition.EndLine-1, + batchDefinition.EndColumn-1), + index, outputFactory, + batchDefinition.BatchExecutionCount, + getFullColumnSchema)); + + Batches = batchSelection.ToArray(); + + // Create our batch lists + BeforeBatches = new List(); + AfterBatches = new List(); + } + + #region Events + + /// + /// Delegate type for callback when a query completes or fails + /// + /// The query that completed + public delegate Task QueryAsyncEventHandler(Query query); + + /// + /// Delegate type for callback when a query fails + /// + /// Query that raised the event + /// Exception that caused the query to fail + public delegate Task QueryAsyncErrorEventHandler(Query query, Exception exception); + + /// + /// Event to be called when a batch is completed. + /// + public event Batch.BatchAsyncEventHandler BatchCompleted; + + /// + /// Event that will be called when a message has been emitted + /// + public event Batch.BatchAsyncMessageHandler BatchMessageSent; + + /// + /// Event to be called when a batch starts execution. + /// + public event Batch.BatchAsyncEventHandler BatchStarted; + + /// + /// Callback for when the query has completed successfully + /// + public event QueryAsyncEventHandler QueryCompleted; + + /// + /// Callback for when the query has failed + /// + public event QueryAsyncErrorEventHandler QueryFailed; + + /// + /// Event to be called when a resultset has completed. + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetCompleted; + + /// + /// Event that will be called when the resultSet first becomes available. This is as soon as we start reading the results. + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetAvailable; + + /// + /// Event that will be called when additional rows in the result set are available (rowCount available has increased) + /// + public event ResultSet.ResultSetAsyncEventHandler ResultSetUpdated; + #endregion + + #region Properties + + /// + /// The batches which should run before the user batches + /// + private List BeforeBatches { get; } + + /// + /// The batches underneath this query + /// + internal Batch[] Batches { get; } + + /// + /// The batches which should run after the user batches + /// + internal List AfterBatches { get; } + + /// + /// The summaries of the batches underneath this query + /// + public BatchSummary[] BatchSummaries + { + get + { + if (!HasExecuted && !HasCancelled && !HasErrored) + { + throw new InvalidOperationException("Query has not been executed."); + } + return Batches.Select(b => b.Summary).ToArray(); + } + } + + /// + /// Storage for the async task for execution. Set as internal in order to await completion + /// in unit tests. + /// + internal Task ExecutionTask { get; private set; } + + /// + /// Whether or not the query has completed executed, regardless of success or failure + /// + /// + /// Don't touch the setter unless you're doing unit tests! + /// + public bool HasExecuted + { + get { return Batches.Length == 0 ? hasExecuteBeenCalled : Batches.All(b => b.HasExecuted); } + internal set + { + hasExecuteBeenCalled = value; + foreach (var batch in Batches) + { + batch.HasExecuted = value; + } + } + } + + /// + /// if the query has been cancelled (before execution started) + /// + public bool HasCancelled { get; private set; } + + /// + /// if the query has errored out (before batch execution started) + /// + public bool HasErrored { get; private set; } + + /// + /// The text of the query to execute + /// + public string QueryText { get; } + + #endregion + + #region Public Methods + + /// + /// Cancels the query by issuing the cancellation token + /// + public void Cancel() + { + // Make sure that the query hasn't completed execution + if (HasExecuted) + { + throw new InvalidOperationException(SR.QueryServiceCancelAlreadyCompleted); + } + + // Issue the cancellation token for the query + this.HasCancelled = true; + cancellationSource.Cancel(); + } + + /// + /// Launches the asynchronous process for executing the query + /// + public void Execute() + { + ExecutionTask = Task.Run(ExecuteInternal) + .ContinueWithOnFaulted(async t => + { + if (QueryFailed != null) + { + await QueryFailed(this, t.Exception); + } + }); + } + + /// + /// Retrieves a subset of the result sets + /// + /// The index for selecting the batch item + /// The index for selecting the result set + /// The starting row of the results + /// How many rows to retrieve + /// A subset of results + public Task GetSubset(int batchIndex, int resultSetIndex, long startRow, int rowCount) + { + Logger.Write(TraceEventType.Start, $"Starting GetSubset execution for batchIndex:'{batchIndex}', resultSetIndex:'{resultSetIndex}', startRow:'{startRow}', rowCount:'{rowCount}'"); + // Sanity check to make sure that the batch is within bounds + if (batchIndex < 0 || batchIndex >= Batches.Length) + { + throw new ArgumentOutOfRangeException(nameof(batchIndex), SR.QueryServiceSubsetBatchOutOfRange); + } + + return Batches[batchIndex].GetSubset(resultSetIndex, startRow, rowCount); + } + + /// + /// Retrieves a subset of the result sets + /// + /// The index for selecting the batch item + /// The index for selecting the result set + /// The Execution Plan, if the result set has one + public Task GetExecutionPlan(int batchIndex, int resultSetIndex) + { + // Sanity check to make sure that the batch is within bounds + if (batchIndex < 0 || batchIndex >= Batches.Length) + { + throw new ArgumentOutOfRangeException(nameof(batchIndex), SR.QueryServiceSubsetBatchOutOfRange); + } + + return Batches[batchIndex].GetExecutionPlan(resultSetIndex); + } + + /// + /// Saves the requested results to a file format of the user's choice + /// + /// Parameters for the save as request + /// + /// Factory for creating the reader/writer pair for the requested output format + /// + /// Delegate to call when the request completes successfully + /// Delegate to call if the request fails + public void SaveAs(SaveResultsRequestParams saveParams, IFileStreamFactory fileFactory, + ResultSet.SaveAsAsyncEventHandler successHandler, ResultSet.SaveAsFailureAsyncEventHandler failureHandler) + { + // Sanity check to make sure that the batch is within bounds + if (saveParams.BatchIndex < 0 || saveParams.BatchIndex >= Batches.Length) + { + throw new ArgumentOutOfRangeException(nameof(saveParams.BatchIndex), SR.QueryServiceSubsetBatchOutOfRange); + } + + Batches[saveParams.BatchIndex].SaveAs(saveParams, fileFactory, successHandler, failureHandler); + } + + #endregion + + #region Private Helpers + + /// + /// Executes this query asynchronously and collects all result sets + /// + private async Task ExecuteInternal() + { + ReliableDataSourceConnection sqlConn = null; + try + { + // check for cancellation token before actually making connection + cancellationSource.Token.ThrowIfCancellationRequested(); + + // Mark that we've internally executed + hasExecuteBeenCalled = true; + + // Don't actually execute if there aren't any batches to execute + if (Batches.Length == 0) + { + if (BatchMessageSent != null) + { + await BatchMessageSent(new ResultMessage(SR.QueryServiceCompletedSuccessfully, false, null)); + } + if (QueryCompleted != null) + { + await QueryCompleted(this); + } + return; + } + + // Locate and setup the connection + ReliableDataSourceConnection queryConnection = await ConnectionService.Instance.GetOrOpenConnection(editorConnection.OwnerUri, ConnectionType.Query); + + // Execute beforeBatches synchronously, before the user defined batches + foreach (Batch b in BeforeBatches) + { + await b.Execute(queryConnection, cancellationSource.Token); + } + + // We need these to execute synchronously, otherwise the user will be very unhappy + foreach (Batch b in Batches) + { + // Add completion callbacks + b.BatchStart += BatchStarted; + b.BatchCompletion += BatchCompleted; + b.BatchMessageSent += BatchMessageSent; + b.ResultSetCompletion += ResultSetCompleted; + b.ResultSetAvailable += ResultSetAvailable; + b.ResultSetUpdated += ResultSetUpdated; + await b.Execute(queryConnection, cancellationSource.Token); + } + + // Execute afterBatches synchronously, after the user defined batches + foreach (Batch b in AfterBatches) + { + await b.Execute(queryConnection, cancellationSource.Token); + } + + // Call the query execution callback + if (QueryCompleted != null) + { + await QueryCompleted(this); + } + } + catch (Exception e) + { + HasErrored = true; + if (e is OperationCanceledException) + { + await BatchMessageSent(new ResultMessage(SR.QueryServiceQueryCancelled, false, null)); + } + // Call the query failure callback + if (QueryFailed != null) + { + await QueryFailed(this, e); + } + } + finally + { + foreach (Batch b in Batches) + { + if (b.HasError) + { + ConnectionService.EnsureConnectionIsOpen(sqlConn); + break; + } + } + } + } + + /// + /// Function to add a new batch to a Batch set + /// + private static void AddBatch(string query, ICollection batchSet, IFileStreamFactory outputFactory) + { + batchSet.Add(new Batch(query, null, batchSet.Count, outputFactory, 1)); + } + #endregion + + #region IDisposable Implementation + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected virtual void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + cancellationSource.Dispose(); + foreach (Batch b in Batches) + { + b.Dispose(); + } + } + + disposed = true; + } + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionOptionsRequest.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionOptionsRequest.cs new file mode 100644 index 0000000000..0f14ae9435 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionOptionsRequest.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +using Microsoft.SqlTools.Hosting.Protocol.Contracts; +using Microsoft.Kusto.ServiceLayer.SqlContext; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts +{ + /// + /// Parameters for the query execution options request + /// + public class QueryExecutionOptionsParams + { + public string OwnerUri { get; set; } + + public QueryExecutionSettings Options { get; set; } + } + + public class QueryExecutionOptionsRequest + { + public static readonly + RequestType Type = + RequestType.Create("query/setexecutionoptions"); + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionService.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionService.cs new file mode 100644 index 0000000000..ec0358cbd3 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QueryExecutionService.cs @@ -0,0 +1,1076 @@ +// +// 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.Concurrent; +using System.Threading.Tasks; +using Microsoft.SqlTools.Hosting.Protocol; +using Microsoft.Kusto.ServiceLayer.Connection; +using Microsoft.Kusto.ServiceLayer.Connection.Contracts; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts; +using Microsoft.Kusto.ServiceLayer.QueryExecution.Contracts.ExecuteRequests; +using Microsoft.Kusto.ServiceLayer.QueryExecution.DataStorage; +using Microsoft.Kusto.ServiceLayer.SqlContext; +using Microsoft.Kusto.ServiceLayer.Workspace; +using Microsoft.Kusto.ServiceLayer.Workspace.Contracts; +using Microsoft.Kusto.ServiceLayer.Hosting; +using Microsoft.SqlTools.Utility; +using System.Diagnostics; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution +{ + /// + /// Service for executing queries + /// + public sealed class QueryExecutionService : IDisposable + { + #region Singleton Instance Implementation + + private static readonly Lazy LazyInstance = new Lazy(() => new QueryExecutionService()); + + /// + /// Singleton instance of the query execution service + /// + public static QueryExecutionService Instance => LazyInstance.Value; + + private QueryExecutionService() + { + ConnectionService = ConnectionService.Instance; + WorkspaceService = WorkspaceService.Instance; + Settings = new SqlToolsSettings(); + } + + internal QueryExecutionService(ConnectionService connService, WorkspaceService workspaceService) + { + ConnectionService = connService; + WorkspaceService = workspaceService; + Settings = new SqlToolsSettings(); + } + + #endregion + + #region Properties + + /// + /// File factory to be used to create a buffer file for results. + /// + /// + /// Made internal here to allow for overriding in unit testing + /// + internal IFileStreamFactory BufferFileStreamFactory; + + /// + /// File factory to be used to create a buffer file for results + /// + private IFileStreamFactory BufferFileFactory + { + get + { + if (BufferFileStreamFactory == null) + { + BufferFileStreamFactory = new ServiceBufferFileStreamFactory + { + ExecutionSettings = Settings.QueryExecutionSettings + }; + } + return BufferFileStreamFactory; + } + } + + /// + /// File factory to be used to create CSV files from result sets. Set to internal in order + /// to allow overriding in unit testing + /// + internal IFileStreamFactory CsvFileFactory { get; set; } + + /// + /// File factory to be used to create Excel files from result sets. Set to internal in order + /// to allow overriding in unit testing + /// + internal IFileStreamFactory ExcelFileFactory { get; set; } + + /// + /// File factory to be used to create JSON files from result sets. Set to internal in order + /// to allow overriding in unit testing + /// + internal IFileStreamFactory JsonFileFactory { get; set; } + + /// + /// File factory to be used to create XML files from result sets. Set to internal in order + /// to allow overriding in unit testing + /// + internal IFileStreamFactory XmlFileFactory { get; set; } + + /// + /// The collection of active queries + /// + internal ConcurrentDictionary ActiveQueries => queries.Value; + + /// + /// The collection of query execution options + /// + internal ConcurrentDictionary ActiveQueryExecutionSettings => queryExecutionSettings.Value; + + /// + /// Internal task for testability + /// + internal Task WorkTask { get; private set; } + + /// + /// Instance of the connection service, used to get the connection info for a given owner URI + /// + private ConnectionService ConnectionService { get; } + + private WorkspaceService WorkspaceService { get; } + + /// + /// Internal storage of active queries, lazily constructed as a threadsafe dictionary + /// + private readonly Lazy> queries = + new Lazy>(() => new ConcurrentDictionary()); + + /// + /// Internal storage of active query settings + /// + private readonly Lazy> queryExecutionSettings = + new Lazy>(() => new ConcurrentDictionary()); + + /// + /// Settings that will be used to execute queries. Internal for unit testing + /// + internal SqlToolsSettings Settings { get; set; } + + /// + /// Holds a map from the simple execute unique GUID and the underlying task that is being ran + /// + private readonly Lazy> simpleExecuteRequests = + new Lazy>(() => new ConcurrentDictionary()); + + /// + /// Holds a map from the simple execute unique GUID and the underlying task that is being ran + /// + internal ConcurrentDictionary ActiveSimpleExecuteRequests => simpleExecuteRequests.Value; + + #endregion + + /// + /// Initializes the service with the service host, registers request handlers and shutdown + /// event handler. + /// + /// The service host instance to register with + public void InitializeService(ServiceHost serviceHost) + { + // Register handlers for requests + serviceHost.SetRequestHandler(ExecuteDocumentSelectionRequest.Type, HandleExecuteRequest); + serviceHost.SetRequestHandler(ExecuteDocumentStatementRequest.Type, HandleExecuteRequest); + serviceHost.SetRequestHandler(ExecuteStringRequest.Type, HandleExecuteRequest); + serviceHost.SetRequestHandler(SubsetRequest.Type, HandleResultSubsetRequest); + serviceHost.SetRequestHandler(QueryDisposeRequest.Type, HandleDisposeRequest); + serviceHost.SetRequestHandler(QueryCancelRequest.Type, HandleCancelRequest); + serviceHost.SetRequestHandler(SaveResultsAsCsvRequest.Type, HandleSaveResultsAsCsvRequest); + serviceHost.SetRequestHandler(SaveResultsAsExcelRequest.Type, HandleSaveResultsAsExcelRequest); + serviceHost.SetRequestHandler(SaveResultsAsJsonRequest.Type, HandleSaveResultsAsJsonRequest); + serviceHost.SetRequestHandler(SaveResultsAsXmlRequest.Type, HandleSaveResultsAsXmlRequest); + serviceHost.SetRequestHandler(QueryExecutionPlanRequest.Type, HandleExecutionPlanRequest); + serviceHost.SetRequestHandler(SimpleExecuteRequest.Type, HandleSimpleExecuteRequest); + serviceHost.SetRequestHandler(QueryExecutionOptionsRequest.Type, HandleQueryExecutionOptionsRequest); + + // Register the file open update handler + WorkspaceService.Instance.RegisterTextDocCloseCallback(HandleDidCloseTextDocumentNotification); + + // Register handler for shutdown event + serviceHost.RegisterShutdownTask((shutdownParams, requestContext) => + { + Dispose(); + return Task.FromResult(0); + }); + + // Register a handler for when the configuration changes + WorkspaceService.RegisterConfigChangeCallback(UpdateSettings); + } + + #region Request Handlers + + /// + /// Handles request to execute a selection of a document in the workspace service + /// + internal async Task HandleExecuteRequest(ExecuteRequestParamsBase executeParams, + RequestContext requestContext) + { + try + { + // Setup actions to perform upon successful start and on failure to start + Func> queryCreateSuccessAction = async q => + { + await requestContext.SendResult(new ExecuteRequestResult()); + Logger.Write(TraceEventType.Stop, $"Response for Query: '{executeParams.OwnerUri} sent. Query Complete!"); + return true; + }; + Func queryCreateFailureAction = message => + { + Logger.Write(TraceEventType.Warning, $"Failed to create Query: '{executeParams.OwnerUri}. Message: '{message}' Complete!"); + return requestContext.SendError(message); + }; + + // Use the internal handler to launch the query + WorkTask = Task.Run(async () => + { + await InterServiceExecuteQuery( + executeParams, + null, + requestContext, + queryCreateSuccessAction, + queryCreateFailureAction, + null, + null, + isQueryEditor(executeParams.OwnerUri)); + }); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Handles a request to execute a string and return the result + /// + internal async Task HandleSimpleExecuteRequest(SimpleExecuteParams executeParams, + RequestContext requestContext) + { + try + { + string randomUri = Guid.NewGuid().ToString(); + ExecuteStringParams executeStringParams = new ExecuteStringParams + { + Query = executeParams.QueryString, + // generate guid as the owner uri to make sure every query is unique + OwnerUri = randomUri + }; + + // get connection + ConnectionInfo connInfo; + if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connInfo)) + { + await requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri); + return; + } + + ConnectParams connectParams = new ConnectParams + { + OwnerUri = randomUri, + Connection = connInfo.ConnectionDetails, + Type = ConnectionType.Default + }; + + Task workTask = Task.Run(async () => { + await ConnectionService.Connect(connectParams); + + ConnectionInfo newConn; + ConnectionService.TryFindConnection(randomUri, out newConn); + + Func queryCreateFailureAction = message => requestContext.SendError(message); + + ResultOnlyContext newContext = new ResultOnlyContext(requestContext); + + // handle sending event back when the query completes + Query.QueryAsyncEventHandler queryComplete = async query => + { + try + { + // check to make sure any results were recieved + if (query.Batches.Length == 0 + || query.Batches[0].ResultSets.Count == 0) + { + await requestContext.SendError(SR.QueryServiceResultSetHasNoResults); + return; + } + + long rowCount = query.Batches[0].ResultSets[0].RowCount; + // check to make sure there is a safe amount of rows to load into memory + if (rowCount > Int32.MaxValue) + { + await requestContext.SendError(SR.QueryServiceResultSetTooLarge); + return; + } + + SimpleExecuteResult result = new SimpleExecuteResult + { + RowCount = rowCount, + ColumnInfo = query.Batches[0].ResultSets[0].Columns, + Rows = new DbCellValue[0][] + }; + + if (rowCount > 0) + { + SubsetParams subsetRequestParams = new SubsetParams + { + OwnerUri = randomUri, + BatchIndex = 0, + ResultSetIndex = 0, + RowsStartIndex = 0, + RowsCount = Convert.ToInt32(rowCount) + }; + // get the data to send back + ResultSetSubset subset = await InterServiceResultSubset(subsetRequestParams); + result.Rows = subset.Rows; + } + await requestContext.SendResult(result); + } + finally + { + Query removedQuery; + Task removedTask; + // remove the active query since we are done with it + ActiveQueries.TryRemove(randomUri, out removedQuery); + ActiveSimpleExecuteRequests.TryRemove(randomUri, out removedTask); + ConnectionService.Disconnect(new DisconnectParams(){ + OwnerUri = randomUri, + Type = null + }); + } + }; + + // handle sending error back when query fails + Query.QueryAsyncErrorEventHandler queryFail = async (q, e) => + { + await requestContext.SendError(e); + }; + + await InterServiceExecuteQuery(executeStringParams, newConn, newContext, null, queryCreateFailureAction, queryComplete, queryFail); + }); + + ActiveSimpleExecuteRequests.TryAdd(randomUri, workTask); + } + catch (Exception ex) + { + await requestContext.SendError(ex.ToString()); + } + } + + /// + /// Handles a request to get a subset of the results of this query + /// + internal async Task HandleResultSubsetRequest(SubsetParams subsetParams, + RequestContext requestContext) + { + try + { + ResultSetSubset subset = await InterServiceResultSubset(subsetParams); + var result = new SubsetResult + { + ResultSubset = subset + }; + await requestContext.SendResult(result); + Logger.Write(TraceEventType.Stop, $"Done Handler for Subset request with for Query:'{subsetParams.OwnerUri}', Batch:'{subsetParams.BatchIndex}', ResultSetIndex:'{subsetParams.ResultSetIndex}', RowsStartIndex'{subsetParams.RowsStartIndex}', Requested RowsCount:'{subsetParams.RowsCount}'\r\n\t\t with subset response of:[ RowCount:'{subset.RowCount}', Rows array of length:'{subset.Rows.Length}']"); + } + catch (Exception e) + { + // This was unexpected, so send back as error + await requestContext.SendError(e.Message); + } + } + + + /// + /// Handles a request to set query execution options + /// + internal async Task HandleQueryExecutionOptionsRequest(QueryExecutionOptionsParams queryExecutionOptionsParams, + RequestContext requestContext) + { + try + { + string uri = queryExecutionOptionsParams.OwnerUri; + if (ActiveQueryExecutionSettings.ContainsKey(uri)) + { + QueryExecutionSettings settings; + ActiveQueryExecutionSettings.TryRemove(uri, out settings); + } + + ActiveQueryExecutionSettings.TryAdd(uri, queryExecutionOptionsParams.Options); + + await requestContext.SendResult(true); + } + catch (Exception e) + { + // This was unexpected, so send back as error + await requestContext.SendError(e.Message); + } + } + + /// + /// Handles a request to get an execution plan + /// + internal async Task HandleExecutionPlanRequest(QueryExecutionPlanParams planParams, + RequestContext requestContext) + { + try + { + // Attempt to load the query + Query query; + if (!ActiveQueries.TryGetValue(planParams.OwnerUri, out query)) + { + await requestContext.SendError(SR.QueryServiceRequestsNoQuery); + return; + } + + // Retrieve the requested execution plan and return it + var result = new QueryExecutionPlanResult + { + ExecutionPlan = await query.GetExecutionPlan(planParams.BatchIndex, planParams.ResultSetIndex) + }; + await requestContext.SendResult(result); + } + catch (Exception e) + { + // This was unexpected, so send back as error + await requestContext.SendError(e.Message); + } + } + + /// + /// Handles a request to dispose of this query + /// + internal async Task HandleDisposeRequest(QueryDisposeParams disposeParams, + RequestContext requestContext) + { + // Setup action for success and failure + Func successAction = () => requestContext.SendResult(new QueryDisposeResult()); + Func failureAction = message => requestContext.SendError(message); + + // Use the inter-service dispose functionality + await InterServiceDisposeQuery(disposeParams.OwnerUri, successAction, failureAction); + } + + /// + /// Handles a request to cancel this query if it is in progress + /// + internal async Task HandleCancelRequest(QueryCancelParams cancelParams, + RequestContext requestContext) + { + try + { + // Attempt to find the query for the owner uri + Query result; + if (!ActiveQueries.TryGetValue(cancelParams.OwnerUri, out result)) + { + await requestContext.SendResult(new QueryCancelResult + { + Messages = SR.QueryServiceRequestsNoQuery + }); + return; + } + + // Cancel the query and send a success message + result.Cancel(); + await requestContext.SendResult(new QueryCancelResult()); + } + catch (InvalidOperationException e) + { + // If this exception occurred, we most likely were trying to cancel a completed query + await requestContext.SendResult(new QueryCancelResult + { + Messages = e.Message + }); + } + catch (Exception e) + { + await requestContext.SendError(e.Message); + } + } + + /// + /// Process request to save a resultSet to a file in CSV format + /// + internal async Task HandleSaveResultsAsCsvRequest(SaveResultsAsCsvRequestParams saveParams, + RequestContext requestContext) + { + // Use the default CSV file factory if we haven't overridden it + IFileStreamFactory csvFactory = CsvFileFactory ?? new SaveAsCsvFileStreamFactory + { + SaveRequestParams = saveParams, + QueryExecutionSettings = Settings.QueryExecutionSettings + }; + await SaveResultsHelper(saveParams, requestContext, csvFactory); + } + + /// + /// Process request to save a resultSet to a file in Excel format + /// + internal async Task HandleSaveResultsAsExcelRequest(SaveResultsAsExcelRequestParams saveParams, + RequestContext requestContext) + { + // Use the default Excel file factory if we haven't overridden it + IFileStreamFactory excelFactory = ExcelFileFactory ?? new SaveAsExcelFileStreamFactory + { + SaveRequestParams = saveParams, + QueryExecutionSettings = Settings.QueryExecutionSettings + }; + await SaveResultsHelper(saveParams, requestContext, excelFactory); + } + + /// + /// Process request to save a resultSet to a file in JSON format + /// + internal async Task HandleSaveResultsAsJsonRequest(SaveResultsAsJsonRequestParams saveParams, + RequestContext requestContext) + { + // Use the default JSON file factory if we haven't overridden it + IFileStreamFactory jsonFactory = JsonFileFactory ?? new SaveAsJsonFileStreamFactory + { + SaveRequestParams = saveParams, + QueryExecutionSettings = Settings.QueryExecutionSettings + }; + await SaveResultsHelper(saveParams, requestContext, jsonFactory); + } + + /// + /// Process request to save a resultSet to a file in XML format + /// + internal async Task HandleSaveResultsAsXmlRequest(SaveResultsAsXmlRequestParams saveParams, + RequestContext requestContext) + { + // Use the default XML file factory if we haven't overridden it + IFileStreamFactory xmlFactory = XmlFileFactory ?? new SaveAsXmlFileStreamFactory + { + SaveRequestParams = saveParams, + QueryExecutionSettings = Settings.QueryExecutionSettings + }; + await SaveResultsHelper(saveParams, requestContext, xmlFactory); + } + + #endregion + + #region Inter-Service API Handlers + + /// + /// Query execution meant to be called from another service. Utilizes callbacks to allow + /// custom actions to be taken upon creation of query and failure to create query. + /// + /// Parameters for execution + /// Connection Info to use; will try and get the connection from owneruri if not provided + /// Event sender that will send progressive events during execution of the query + /// + /// Callback for when query has been created successfully. If result is true, query + /// will be executed asynchronously. If result is false, query will be disposed. May + /// be null + /// + /// + /// Callback for when query failed to be created successfully. Error message is provided. + /// May be null. + /// + /// + /// Callback to call when query has completed execution successfully. May be null. + /// + /// + /// Callback to call when query has completed execution with errors. May be null. + /// + public async Task InterServiceExecuteQuery(ExecuteRequestParamsBase executeParams, + ConnectionInfo connInfo, + IEventSender queryEventSender, + Func> queryCreateSuccessFunc, + Func queryCreateFailFunc, + Query.QueryAsyncEventHandler querySuccessFunc, + Query.QueryAsyncErrorEventHandler queryFailureFunc, + bool applyExecutionSettings = false) + { + Validate.IsNotNull(nameof(executeParams), executeParams); + Validate.IsNotNull(nameof(queryEventSender), queryEventSender); + + Query newQuery; + try + { + // Get a new active query + newQuery = CreateQuery(executeParams, connInfo, applyExecutionSettings); + if (queryCreateSuccessFunc != null && !await queryCreateSuccessFunc(newQuery)) + { + // The callback doesn't want us to continue, for some reason + // It's ok if we leave the query behind in the active query list, the next call + // to execute will replace it. + newQuery.Dispose(); + return; + } + } + catch (Exception e) + { + // Call the failure callback if it was provided + if (queryCreateFailFunc != null) + { + await queryCreateFailFunc(e.Message); + } + return; + } + + // Execute the query asynchronously + ExecuteAndCompleteQuery(executeParams.OwnerUri, newQuery, queryEventSender, querySuccessFunc, queryFailureFunc); + } + + /// + /// Query disposal meant to be called from another service. Utilizes callbacks to allow + /// custom actions to be performed on success or failure. + /// + /// The identifier of the query to be disposed + /// Action to perform on success + /// Action to perform on failure + public async Task InterServiceDisposeQuery(string ownerUri, Func successAction, + Func failureAction) + { + Validate.IsNotNull(nameof(successAction), successAction); + Validate.IsNotNull(nameof(failureAction), failureAction); + + try + { + // Attempt to remove the query for the owner uri + Query result; + if (!ActiveQueries.TryRemove(ownerUri, out result)) + { + await failureAction(SR.QueryServiceRequestsNoQuery); + return; + } + + // Cleanup the query + result.Dispose(); + + // Success + await successAction(); + } + catch (Exception e) + { + await failureAction(e.Message); + } + } + + /// + /// Retrieves the requested subset of rows from the requested result set. Intended to be + /// called by another service. + /// + /// Parameters for the subset to retrieve + /// The requested subset + /// The requested query does not exist + public async Task InterServiceResultSubset(SubsetParams subsetParams) + { + Validate.IsNotNullOrEmptyString(nameof(subsetParams.OwnerUri), subsetParams.OwnerUri); + + // Attempt to load the query + Query query; + if (!ActiveQueries.TryGetValue(subsetParams.OwnerUri, out query)) + { + throw new ArgumentOutOfRangeException(SR.QueryServiceRequestsNoQuery); + } + + // Retrieve the requested subset and return it + return await query.GetSubset(subsetParams.BatchIndex, subsetParams.ResultSetIndex, + subsetParams.RowsStartIndex, subsetParams.RowsCount); + } + + /// + /// Handle the file open notification + /// + /// + /// + /// + public async Task HandleDidCloseTextDocumentNotification( + string uri, + ScriptFile scriptFile, + EventContext eventContext) + { + try + { + // remove any query execution settings when an editor is closed + if (this.ActiveQueryExecutionSettings.ContainsKey(uri)) + { + QueryExecutionSettings settings; + this.ActiveQueryExecutionSettings.TryRemove(uri, out settings); + } + } + catch (Exception ex) + { + Logger.Write(TraceEventType.Error, "Unknown error " + ex.ToString()); + } + await Task.FromResult(true); + } + + #endregion + + #region Private Helpers + + private Query CreateQuery( + ExecuteRequestParamsBase executeParams, + ConnectionInfo connInfo, + bool applyExecutionSettings) + { + // Attempt to get the connection for the editor + ConnectionInfo connectionInfo; + if (connInfo != null) + { + connectionInfo = connInfo; + } + else if (!ConnectionService.TryFindConnection(executeParams.OwnerUri, out connectionInfo)) + { + throw new ArgumentOutOfRangeException(nameof(executeParams.OwnerUri), SR.QueryServiceQueryInvalidOwnerUri); + } + + // Attempt to clean out any old query on the owner URI + Query oldQuery; + // DevNote: + // if any oldQuery exists on the executeParams.OwnerUri but it has not yet executed, + // then shouldn't we cancel and clean out that query since we are about to create a new query object on the current OwnerUri. + // + if (ActiveQueries.TryGetValue(executeParams.OwnerUri, out oldQuery) && (oldQuery.HasExecuted || oldQuery.HasCancelled || oldQuery.HasErrored)) + { + oldQuery.Dispose(); + ActiveQueries.TryRemove(executeParams.OwnerUri, out oldQuery); + } + + // check if there are active query execution settings for the editor, otherwise, use the global settings + QueryExecutionSettings settings; + if (this.ActiveQueryExecutionSettings.TryGetValue(executeParams.OwnerUri, out settings)) + { + // special-case handling for query plan options to maintain compat with query execution API parameters + // the logic is that if either the query execute API parameters or the active query setttings + // request a plan then enable the query option + ExecutionPlanOptions executionPlanOptions = executeParams.ExecutionPlanOptions; + if (settings.IncludeActualExecutionPlanXml) + { + executionPlanOptions.IncludeActualExecutionPlanXml = settings.IncludeActualExecutionPlanXml; + } + if (settings.IncludeEstimatedExecutionPlanXml) + { + executionPlanOptions.IncludeEstimatedExecutionPlanXml = settings.IncludeEstimatedExecutionPlanXml; + } + settings.ExecutionPlanOptions = executionPlanOptions; + } + else + { + settings = Settings.QueryExecutionSettings; + settings.ExecutionPlanOptions = executeParams.ExecutionPlanOptions; + } + + // If we can't add the query now, it's assumed the query is in progress + Query newQuery = new Query( + GetSqlText(executeParams), + connectionInfo, + settings, + BufferFileFactory, + executeParams.GetFullColumnSchema, + applyExecutionSettings); + if (!ActiveQueries.TryAdd(executeParams.OwnerUri, newQuery)) + { + newQuery.Dispose(); + throw new InvalidOperationException(SR.QueryServiceQueryInProgress); + } + + Logger.Write(TraceEventType.Information, $"Query object for URI:'{executeParams.OwnerUri}' created"); + return newQuery; + } + + private static void ExecuteAndCompleteQuery(string ownerUri, Query query, + IEventSender eventSender, + Query.QueryAsyncEventHandler querySuccessCallback, + Query.QueryAsyncErrorEventHandler queryFailureCallback) + { + // Setup the callback to send the complete event + Query.QueryAsyncEventHandler completeCallback = async q => + { + // Send back the results + QueryCompleteParams eventParams = new QueryCompleteParams + { + OwnerUri = ownerUri, + BatchSummaries = q.BatchSummaries + }; + + Logger.Write(TraceEventType.Information, $"Query:'{ownerUri}' completed"); + await eventSender.SendEvent(QueryCompleteEvent.Type, eventParams); + }; + + // Setup the callback to send the failure event + Query.QueryAsyncErrorEventHandler failureCallback = async (q, e) => + { + // Send back the results + QueryCompleteParams eventParams = new QueryCompleteParams + { + OwnerUri = ownerUri, + BatchSummaries = q.BatchSummaries + }; + + Logger.Write(TraceEventType.Error, $"Query:'{ownerUri}' failed"); + await eventSender.SendEvent(QueryCompleteEvent.Type, eventParams); + }; + query.QueryCompleted += completeCallback; + query.QueryFailed += failureCallback; + + // Add the callbacks that were provided by the caller + // If they're null, that's no problem + query.QueryCompleted += querySuccessCallback; + query.QueryFailed += queryFailureCallback; + + // Setup the batch callbacks + Batch.BatchAsyncEventHandler batchStartCallback = async b => + { + BatchEventParams eventParams = new BatchEventParams + { + BatchSummary = b.Summary, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Batch:'{b.Summary}' on Query:'{ownerUri}' started"); + await eventSender.SendEvent(BatchStartEvent.Type, eventParams); + }; + query.BatchStarted += batchStartCallback; + + Batch.BatchAsyncEventHandler batchCompleteCallback = async b => + { + BatchEventParams eventParams = new BatchEventParams + { + BatchSummary = b.Summary, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Batch:'{b.Summary}' on Query:'{ownerUri}' completed"); + await eventSender.SendEvent(BatchCompleteEvent.Type, eventParams); + }; + query.BatchCompleted += batchCompleteCallback; + + Batch.BatchAsyncMessageHandler batchMessageCallback = async m => + { + MessageParams eventParams = new MessageParams + { + Message = m, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Message generated on Query:'{ownerUri}' :'{m}'"); + await eventSender.SendEvent(MessageEvent.Type, eventParams); + }; + query.BatchMessageSent += batchMessageCallback; + + // Setup the ResultSet available callback + ResultSet.ResultSetAsyncEventHandler resultAvailableCallback = async r => + { + ResultSetAvailableEventParams eventParams = new ResultSetAvailableEventParams + { + ResultSetSummary = r.Summary, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Result:'{r.Summary} on Query:'{ownerUri}' is available"); + await eventSender.SendEvent(ResultSetAvailableEvent.Type, eventParams); + }; + query.ResultSetAvailable += resultAvailableCallback; + + // Setup the ResultSet updated callback + ResultSet.ResultSetAsyncEventHandler resultUpdatedCallback = async r => + { + ResultSetUpdatedEventParams eventParams = new ResultSetUpdatedEventParams + { + ResultSetSummary = r.Summary, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Result:'{r.Summary} on Query:'{ownerUri}' is updated with additional rows"); + await eventSender.SendEvent(ResultSetUpdatedEvent.Type, eventParams); + }; + query.ResultSetUpdated += resultUpdatedCallback; + + // Setup the ResultSet completion callback + ResultSet.ResultSetAsyncEventHandler resultCompleteCallback = async r => + { + ResultSetCompleteEventParams eventParams = new ResultSetCompleteEventParams + { + ResultSetSummary = r.Summary, + OwnerUri = ownerUri + }; + + Logger.Write(TraceEventType.Information, $"Result:'{r.Summary} on Query:'{ownerUri}' is complete"); + await eventSender.SendEvent(ResultSetCompleteEvent.Type, eventParams); + }; + query.ResultSetCompleted += resultCompleteCallback; + + // Launch this as an asynchronous task + query.Execute(); + } + + private async Task SaveResultsHelper(SaveResultsRequestParams saveParams, + RequestContext requestContext, IFileStreamFactory fileFactory) + { + // retrieve query for OwnerUri + Query query; + if (!ActiveQueries.TryGetValue(saveParams.OwnerUri, out query)) + { + await requestContext.SendError(SR.QueryServiceQueryInvalidOwnerUri); + return; + } + + //Setup the callback for completion of the save task + ResultSet.SaveAsAsyncEventHandler successHandler = async parameters => + { + await requestContext.SendResult(new SaveResultRequestResult()); + }; + ResultSet.SaveAsFailureAsyncEventHandler errorHandler = async (parameters, reason) => + { + string message = SR.QueryServiceSaveAsFail(Path.GetFileName(parameters.FilePath), reason); + await requestContext.SendError(message); + }; + + try + { + // Launch the task + query.SaveAs(saveParams, fileFactory, successHandler, errorHandler); + } + catch (Exception e) + { + await errorHandler(saveParams, e.Message); + } + } + + // Internal for testing purposes + internal string GetSqlText(ExecuteRequestParamsBase request) + { + // If it is a document selection, we'll retrieve the text from the document + ExecuteDocumentSelectionParams docRequest = request as ExecuteDocumentSelectionParams; + if (docRequest != null) + { + return GetSqlTextFromSelectionData(docRequest.OwnerUri, docRequest.QuerySelection); + } + + // If it is a document statement, we'll retrieve the text from the document + ExecuteDocumentStatementParams stmtRequest = request as ExecuteDocumentStatementParams; + if (stmtRequest != null) + { + return GetSqlStatementAtPosition(stmtRequest.OwnerUri, stmtRequest.Line, stmtRequest.Column); + } + + // If it is an ExecuteStringParams, return the text as is + ExecuteStringParams stringRequest = request as ExecuteStringParams; + if (stringRequest != null) + { + return stringRequest.Query; + } + + // Note, this shouldn't be possible due to inheritance rules + throw new InvalidCastException("Invalid request type"); + } + + /// + /// Return portion of document corresponding to the selection range + /// + internal string GetSqlTextFromSelectionData(string ownerUri, SelectionData selection) + { + // Get the document from the parameters + ScriptFile queryFile = WorkspaceService.Workspace.GetFile(ownerUri); + if (queryFile == null) + { + return string.Empty; + } + // If a selection was not provided, use the entire document + if (selection == null) + { + return queryFile.Contents; + } + + // A selection was provided, so get the lines in the selected range + string[] queryTextArray = queryFile.GetLinesInRange( + new BufferRange( + new BufferPosition( + selection.StartLine + 1, + selection.StartColumn + 1 + ), + new BufferPosition( + selection.EndLine + 1, + selection.EndColumn + 1 + ) + ) + ); + return string.Join(Environment.NewLine, queryTextArray); + } + + /// + /// Return portion of document corresponding to the statement at the line and column + /// + internal string GetSqlStatementAtPosition(string ownerUri, int line, int column) + { + // Get the document from the parameters + ScriptFile queryFile = WorkspaceService.Workspace.GetFile(ownerUri); + if (queryFile == null) + { + return string.Empty; + } + + return LanguageServices.LanguageService.Instance.ParseStatementAtPosition( + queryFile.Contents, line, column); + } + + /// Internal for testing purposes + internal Task UpdateSettings(SqlToolsSettings newSettings, SqlToolsSettings oldSettings, EventContext eventContext) + { + Settings.QueryExecutionSettings.Update(newSettings.QueryExecutionSettings); + return Task.FromResult(0); + } + + #endregion + + #region IDisposable Implementation + + private bool disposed; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (disposed) + { + return; + } + + if (disposing) + { + foreach (var query in ActiveQueries) + { + if (!query.Value.HasExecuted) + { + try + { + query.Value.Cancel(); + } + catch (Exception e) + { + // We don't particularly care if we fail to cancel during shutdown + string message = string.Format("Failed to cancel query {0} during query service disposal: {1}", query.Key, e); + Logger.Write(TraceEventType.Warning, message); + } + } + query.Value.Dispose(); + } + ActiveQueries.Clear(); + } + + disposed = true; + } + + /// + /// Verify if the URI maps to a query editor document + /// + /// + /// + private bool isQueryEditor(string uri) + { + return (!string.IsNullOrWhiteSpace(uri) + && (uri.StartsWith("untitled:") + || uri.StartsWith("file:"))); + } + + ~QueryExecutionService() + { + Dispose(false); + } + + #endregion + } +} diff --git a/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QuerySettingsHelper.cs b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QuerySettingsHelper.cs new file mode 100644 index 0000000000..ccb54ab3c5 --- /dev/null +++ b/src/Microsoft.Kusto.ServiceLayer/QueryExecution/QuerySettingsHelper.cs @@ -0,0 +1,223 @@ +// +// 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 Microsoft.Kusto.ServiceLayer.SqlContext; + +namespace Microsoft.Kusto.ServiceLayer.QueryExecution +{ + /// + /// Service for executing queries + /// + public class QuerySettingsHelper + { + //strings for various "SET