├── tools ├── Publish.ps1 └── Publish-Local.ps1 ├── .gitignore ├── source ├── Horker.Data.Tests │ ├── UnitTest1.cs │ └── Horker.Data.Tests.csproj ├── Horker.Data │ ├── Horker.Data.csproj │ ├── Classes │ │ ├── ConnectionOpener.cs │ │ ├── Helpers.cs │ │ └── ConnectionSetting.cs │ ├── Cmdlets │ │ ├── Schema.cs │ │ ├── Connection.cs │ │ ├── Configuration.cs │ │ ├── DbProviderFactory.cs │ │ ├── CopyDataRow.cs │ │ ├── ConnectionString.cs │ │ ├── InvokeDataQuery.cs │ │ └── ExportDataTable.cs │ └── Horker.Data.xml └── dataquery.sln ├── docs ├── Get-DataQueryResult.md ├── Get-DataConnectionString.md ├── Close-DataConnection.md ├── Get-DataConnectionHistory.md ├── Unregister-DataConnectionString.md ├── Unregister-DbProviderFactory.md ├── Get-DbProviderFactory.md ├── Register-DataConfiguration.md ├── Register-DataConnectionString.md ├── New-DataConnection.md ├── New-DataConnectionString.md ├── Get-DataSchema.md ├── Register-DbProviderFactory.md ├── Export-DataTable.md ├── Copy-DataRow.md └── Invoke-DataQuery.md ├── LICENSE.txt ├── scripts ├── HorkerDataQuery.psm1 └── HorkerDataQuery.psd1 ├── tests ├── Copy-DataRow.Tests.ps1 └── Invoke-DataQuery.Tests.ps1 ├── .build.ps1 └── README.md /tools/Publish.ps1: -------------------------------------------------------------------------------- 1 | Publish-Module -Path $PSScriptRoot\..\module\release\HorkerDataQuery -NugetApiKey (cat private\NugetApiKey.txt) 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HorkerDataQuery/ 2 | debug/ 3 | 4 | .vs/ 5 | bin/ 6 | obj/ 7 | packages/ 8 | *.user 9 | 10 | private/ 11 | vendor/ 12 | 13 | *.sqlite 14 | *.accdb 15 | *.db 16 | -------------------------------------------------------------------------------- /source/Horker.Data.Tests/UnitTest1.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Xunit; 3 | 4 | namespace Horker.Data.Tests 5 | { 6 | public class UnitTest1 7 | { 8 | [Fact] 9 | public void Test1() 10 | { 11 | 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /tools/Publish-Local.ps1: -------------------------------------------------------------------------------- 1 | if (Test-Path ~\localpsrepo\HorkerDataQuery.*.nupkg) { 2 | rm ~\localpsrepo\HorkerDataQuery.*.nupkg 3 | } 4 | 5 | Publish-Module -path $PSScriptRoot\..\module\release\HorkerDataQuery -Repository LocalPSrepo -NuGetApiKey any -vb 6 | Install-Module HorkerDataQuery -force -Repository LocalPSRepo 7 | -------------------------------------------------------------------------------- /source/Horker.Data.Tests/Horker.Data.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp3.1 5 | 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /docs/Get-DataQueryResult.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-DataQueryResult 9 | 10 | ## SYNOPSIS 11 | 12 | Gets a result of the last SQL statement. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Get-DataQueryResult [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | Gets the number of records affected by the last statement by the Invoke-DataQuery cmdlet. If the previous statement is SELECT, the cmdlet will return -1. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### CommonParameters 29 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 30 | 31 | ## INPUTS 32 | 33 | ### None 34 | 35 | ## OUTPUTS 36 | 37 | ### System.Int32 38 | 39 | ## NOTES 40 | 41 | ## RELATED LINKS 42 | -------------------------------------------------------------------------------- /docs/Get-DataConnectionString.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-DataConnectionString 9 | 10 | ## SYNOPSIS 11 | 12 | Gets connection strings defined in the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Get-DataConnectionString [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Get-DataConnectionString cmdlet gets all connection strings defined in the ConfigurationManager. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### CommonParameters 29 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 30 | 31 | ## INPUTS 32 | 33 | ### None 34 | 35 | ## OUTPUTS 36 | 37 | ### System.Configuration.ConnectionStringSettings 38 | 39 | ## NOTES 40 | 41 | ## RELATED LINKS 42 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 horker 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /docs/Close-DataConnection.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Close-DataConnection 9 | 10 | ## SYNOPSIS 11 | 12 | Closes a database connection. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Close-DataConnection [-Connection] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Close-DataConnection cmdlet closes a database connection. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### -Connection 29 | 30 | A database connection. 31 | 32 | ```yaml 33 | Type: DbConnection 34 | Parameter Sets: (All) 35 | Aliases: 36 | 37 | Required: True 38 | Position: 0 39 | Default value: None 40 | Accept pipeline input: False 41 | Accept wildcard characters: False 42 | ``` 43 | 44 | ### CommonParameters 45 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 46 | 47 | ## INPUTS 48 | 49 | ### None 50 | 51 | ## OUTPUTS 52 | 53 | ### System.Void 54 | 55 | ## NOTES 56 | 57 | ## RELATED LINKS 58 | -------------------------------------------------------------------------------- /docs/Get-DataConnectionHistory.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-DataConnectionHistory 9 | 10 | ## SYNOPSIS 11 | 12 | Gets open database connections in the current session. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Get-DataConnectionHistory [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Get-DataConnectionHistory cmdlet gets open database connections in the current session that you have opened explicitly by the New-DataConnection cmdlet, or implicitly by the other cmdlets you invoked. 23 | 24 | This cmdlet is useful when you need to investigate untracked open connections causing a trouble (acquiring a file lock, for example). 25 | 26 | ## EXAMPLES 27 | 28 | ## PARAMETERS 29 | 30 | ### CommonParameters 31 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 32 | 33 | ## INPUTS 34 | 35 | ### None 36 | 37 | ## OUTPUTS 38 | 39 | ### System.Data.Common.DbConnection 40 | 41 | ## NOTES 42 | 43 | ## RELATED LINKS 44 | -------------------------------------------------------------------------------- /docs/Unregister-DataConnectionString.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Unregister-DataConnectionString 9 | 10 | ## SYNOPSIS 11 | 12 | Removes a connection string definition from the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Unregister-DataConnectionString [-Name] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Unregister-DataConnectionString cmdlet removes a connection string definition from the ConfigurationManager. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### -Name 29 | 30 | A connection string name. 31 | 32 | ```yaml 33 | Type: String 34 | Parameter Sets: (All) 35 | Aliases: 36 | 37 | Required: True 38 | Position: 0 39 | Default value: None 40 | Accept pipeline input: False 41 | Accept wildcard characters: False 42 | ``` 43 | 44 | ### CommonParameters 45 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 46 | 47 | ## INPUTS 48 | 49 | ### None 50 | 51 | ## OUTPUTS 52 | 53 | ### System.Void 54 | 55 | ## NOTES 56 | 57 | ## RELATED LINKS 58 | -------------------------------------------------------------------------------- /docs/Unregister-DbProviderFactory.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Unregister-DbProviderFactory 9 | 10 | ## SYNOPSIS 11 | 12 | Removes a database provider factory from the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Unregister-DbProviderFactory [-ProviderName] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Unregister-DbProviderFactory cmdlet removes a database provider factory from the ConfigurationManager. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### -ProviderName 29 | 30 | A database provider name. 31 | 32 | ```yaml 33 | Type: String 34 | Parameter Sets: (All) 35 | Aliases: 36 | 37 | Required: True 38 | Position: 0 39 | Default value: None 40 | Accept pipeline input: False 41 | Accept wildcard characters: False 42 | ``` 43 | 44 | ### CommonParameters 45 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 46 | 47 | ## INPUTS 48 | 49 | ### None 50 | 51 | ## OUTPUTS 52 | 53 | ### System.Void 54 | 55 | ## NOTES 56 | 57 | ## RELATED LINKS 58 | -------------------------------------------------------------------------------- /source/Horker.Data/Horker.Data.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.1 5 | Horker.Data 6 | Horker.Data 7 | AnyCPU;x64 8 | 9 | 10 | 11 | $(TargetDir)Horker.Data.xml 12 | 13 | 14 | 15 | 16 | $(TargetDir)Horker.Data.xml 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /docs/Get-DbProviderFactory.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-DbProviderFactory 9 | 10 | ## SYNOPSIS 11 | 12 | Gets database provider factories defined in the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Get-DbProviderFactory [[-ProviderName] ] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Get-DbProviderFactory cmdlet gets database provider factories defined in the ConfigurationManager. 23 | 24 | If the -ProviderName parameter is not specified, it returns all database provider factories. 25 | 26 | ## EXAMPLES 27 | 28 | ## PARAMETERS 29 | 30 | ### -ProviderName 31 | 32 | A database provider name. 33 | 34 | ```yaml 35 | Type: String 36 | Parameter Sets: (All) 37 | Aliases: 38 | 39 | Required: False 40 | Position: 0 41 | Default value: None 42 | Accept pipeline input: False 43 | Accept wildcard characters: False 44 | ``` 45 | 46 | ### CommonParameters 47 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 48 | 49 | ## INPUTS 50 | 51 | ### None 52 | 53 | ## OUTPUTS 54 | 55 | ### System.Data.DataTable 56 | 57 | ## NOTES 58 | 59 | ## RELATED LINKS 60 | -------------------------------------------------------------------------------- /scripts/HorkerDataQuery.psm1: -------------------------------------------------------------------------------- 1 | $script:DefaultDbProviderFactories = @( 2 | @{ 3 | Name = "Odbc Data Provider" 4 | InvariantName = "System.Data.Odbc" 5 | Description = ".Net Framework Data Provider for Odbc" 6 | Type = [System.Data.Odbc.OdbcFactory].AssemblyQualifiedName 7 | } 8 | @{ 9 | Name = "OleDb Data Provider" 10 | InvariantName = "System.Data.OleDb" 11 | Description = ".Net Framework Data Provider for OleDb" 12 | Type = [System.Data.OleDb.OleDbFactory].AssemblyQualifiedName 13 | } 14 | @{ 15 | Name = "SqlClient Data Provider" 16 | InvariantName = "System.Data.SqlClient" 17 | Description = ".Net Framework Data Provider for SqlServer" 18 | Type = [System.Data.SqlClient.SqlClientFactory].AssemblyQualifiedName 19 | } 20 | @{ 21 | Name = "SQLite Data Provider" 22 | InvariantName = "System.Data.SQLite" 23 | Description = ".NET Framework Data Provider for SQLite" 24 | Type = [System.Data.SQLite.SQLiteFactory].AssemblyQualifiedName 25 | } 26 | @{ 27 | Name = "Npgsql Data Provider" 28 | InvariantName = "Npgsql" 29 | Description = ".Net Data Provider for PostgreSQL" 30 | Type = [Npgsql.NpgsqlFactory].AssemblyQualifiedName 31 | } 32 | ) 33 | 34 | foreach ($f in $DefaultDbProviderFactories) { 35 | Register-DbProviderFactory $f["Name"] $f["InvariantName"] $f["Description"] $f["Type"] 36 | } 37 | 38 | Register-DataConnectionString "memory" "System.Data.SQLite" "Data Source=':memory:'" 39 | -------------------------------------------------------------------------------- /docs/Register-DataConfiguration.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Register-DataConfiguration 9 | 10 | ## SYNOPSIS 11 | 12 | Registers connection strings and database provider factories. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Register-DataConfiguration [-ConfigurationFile] [] 18 | ``` 19 | 20 | ## DESCRIPTION 21 | 22 | The Register-DataConfiguration cmdlet reads a configuration file (app.config or web.config in most cases), finds the /configuration/connectionStrings and /configuration/system.data/DbProviderFactories sections and, according to their contents, registers connection strings and database provider factories to the ConfigurationManager. 23 | 24 | ## EXAMPLES 25 | 26 | ## PARAMETERS 27 | 28 | ### -ConfigurationFile 29 | 30 | A configuration file name. 31 | 32 | ```yaml 33 | Type: String 34 | Parameter Sets: (All) 35 | Aliases: 36 | 37 | Required: True 38 | Position: 0 39 | Default value: None 40 | Accept pipeline input: False 41 | Accept wildcard characters: False 42 | ``` 43 | 44 | ### CommonParameters 45 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 46 | 47 | ## INPUTS 48 | 49 | ### None 50 | 51 | ## OUTPUTS 52 | 53 | ### System.Void 54 | 55 | ## NOTES 56 | 57 | ## RELATED LINKS 58 | -------------------------------------------------------------------------------- /source/Horker.Data/Classes/ConnectionOpener.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | 3 | #pragma warning disable CS1591 4 | 5 | namespace Horker.Data 6 | { 7 | public class ConnectionSpecifier 8 | { 9 | public DbConnection Connection { get; private set; } 10 | public bool ConnectionOpened { get; private set; } 11 | 12 | public ConnectionSpecifier(string fileOrName, DbConnection connection, string providerName, string connectionString) 13 | { 14 | if (fileOrName != null) { 15 | Connection = new FileConnectionSetting(fileOrName).GetConnection(); 16 | ConnectionOpened = true; 17 | } 18 | else if (connection != null) { 19 | Connection = connection; 20 | ConnectionOpened = false; 21 | } 22 | else { 23 | Connection = new ProviderConnectionSetting(providerName, connectionString).GetConnection(); 24 | ConnectionOpened = true; 25 | } 26 | 27 | if (ConnectionOpened) { 28 | GetDataConnectionHistory.AddToHistory(Connection); 29 | } 30 | } 31 | 32 | public void Close() 33 | { 34 | if (ConnectionOpened && Connection != null) 35 | Connection.Close(); 36 | ConnectionOpened = false; 37 | } 38 | 39 | public static implicit operator ConnectionSpecifier(string fileOrName) 40 | { 41 | return new ConnectionSpecifier(fileOrName, null, null, null); 42 | } 43 | 44 | public static implicit operator ConnectionSpecifier(DbConnection connection) 45 | { 46 | return new ConnectionSpecifier(null, connection, null, null); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /docs/Register-DataConnectionString.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Register-DataConnectionString 9 | 10 | ## SYNOPSIS 11 | 12 | Registers a connection string to the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Register-DataConnectionString [-Name] [-ProviderName] [-ConnectionString] 18 | [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | 23 | The Register-DataConnectionString cmdlet registers a connection string to the ConfigurationManager. 24 | 25 | ## EXAMPLES 26 | 27 | ## PARAMETERS 28 | 29 | ### -ConnectionString 30 | 31 | A connection string. 32 | 33 | ```yaml 34 | Type: String 35 | Parameter Sets: (All) 36 | Aliases: 37 | 38 | Required: True 39 | Position: 2 40 | Default value: None 41 | Accept pipeline input: False 42 | Accept wildcard characters: False 43 | ``` 44 | 45 | ### -Name 46 | 47 | A connection string name. 48 | 49 | ```yaml 50 | Type: String 51 | Parameter Sets: (All) 52 | Aliases: 53 | 54 | Required: True 55 | Position: 0 56 | Default value: None 57 | Accept pipeline input: False 58 | Accept wildcard characters: False 59 | ``` 60 | 61 | ### -ProviderName 62 | 63 | A database provider name. 64 | 65 | ```yaml 66 | Type: String 67 | Parameter Sets: (All) 68 | Aliases: 69 | 70 | Required: True 71 | Position: 1 72 | Default value: None 73 | Accept pipeline input: False 74 | Accept wildcard characters: False 75 | ``` 76 | 77 | ### CommonParameters 78 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 79 | 80 | ## INPUTS 81 | 82 | ### None 83 | 84 | ## OUTPUTS 85 | 86 | ### System.Void 87 | 88 | ## NOTES 89 | 90 | ## RELATED LINKS 91 | -------------------------------------------------------------------------------- /docs/New-DataConnection.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # New-DataConnection 9 | 10 | ## SYNOPSIS 11 | 12 | Opens a database connection. 13 | 14 | ## SYNTAX 15 | 16 | ### FileOrName (Default) 17 | ``` 18 | New-DataConnection [-FileOrName] [] 19 | ``` 20 | 21 | ### ConnectionString 22 | ``` 23 | New-DataConnection [-ProviderName] [-ConnectionString] [] 24 | ``` 25 | 26 | ## DESCRIPTION 27 | 28 | The New-DataConnection cmdlet opens a database connection. 29 | 30 | ## EXAMPLES 31 | 32 | ## PARAMETERS 33 | 34 | ### -ConnectionString 35 | 36 | A database provider name. 37 | 38 | ```yaml 39 | Type: String 40 | Parameter Sets: ConnectionString 41 | Aliases: 42 | 43 | Required: True 44 | Position: 1 45 | Default value: None 46 | Accept pipeline input: False 47 | Accept wildcard characters: False 48 | ``` 49 | 50 | ### -FileOrName 51 | 52 | A database file name or a connection string name. 53 | 54 | ```yaml 55 | Type: String 56 | Parameter Sets: FileOrName 57 | Aliases: 58 | 59 | Required: True 60 | Position: 0 61 | Default value: None 62 | Accept pipeline input: False 63 | Accept wildcard characters: False 64 | ``` 65 | 66 | ### -ProviderName 67 | 68 | A database provider name. 69 | 70 | ```yaml 71 | Type: String 72 | Parameter Sets: ConnectionString 73 | Aliases: 74 | 75 | Required: True 76 | Position: 0 77 | Default value: None 78 | Accept pipeline input: False 79 | Accept wildcard characters: False 80 | ``` 81 | 82 | ### CommonParameters 83 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 84 | 85 | ## INPUTS 86 | 87 | ### None 88 | 89 | ## OUTPUTS 90 | 91 | ### System.Data.Common.DbConnection 92 | 93 | ## NOTES 94 | 95 | ## RELATED LINKS 96 | -------------------------------------------------------------------------------- /tests/Copy-DataRow.Tests.ps1: -------------------------------------------------------------------------------- 1 | Set-StrictMode -Version 4 2 | 3 | $db1 = "$PSScriptRoot\testdb1.db" 4 | $db2 = "$PSScriptRoot\testdb2.db" 5 | 6 | Describe "Copy-DataRow" { 7 | 8 | BeforeEach { 9 | New-Item -Force $db1 10 | New-Item -Force $db2 11 | $conn1 = New-DataConnection $db1 12 | $conn2 = New-DataConnection $db2 13 | } 14 | 15 | AfterEach { 16 | Close-DataConnection $conn1 17 | Close-DataConnection $conn2 18 | Remove-Item $db1 19 | Remove-Item $db2 20 | } 21 | 22 | It "can copy data to another database by the specified SQL" { 23 | Invoke-DataQuery $conn1 "create table T (a, b, c)" 24 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (1, 'foo', 'bar')" 25 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (2, 'xxx', 'yyy')" 26 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (3, 'nnn', 'mmm')" 27 | 28 | Invoke-DataQuery $conn2 "create table U (x, y)" 29 | 30 | Copy-DataRow $conn1 "select a, c from T where a >= 2" $conn2 -TargetSql "insert into U values (@a, @c)" 31 | 32 | $result = Invoke-DataQuery $conn2 "select * from U" 33 | 34 | $result[0].x | Should -Be 2 35 | $result[0].y | Should -Be "yyy" 36 | $result[1].x | Should -Be 3 37 | $result[1].y | Should -Be "mmm" 38 | } 39 | 40 | It "can copy data to the specified table of another database" { 41 | Invoke-DataQuery $conn1 "create table T (a, b, c)" 42 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (1, 'foo', 'bar')" 43 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (2, 'xxx', 'yyy')" 44 | Invoke-DataQuery $conn1 "insert into T (a, b, c) values (3, 'nnn', 'mmm')" 45 | 46 | Invoke-DataQuery $conn2 "create table U (x, y)" 47 | 48 | Copy-DataRow $conn1 "select a as y, c as x from T where a >= 2" $conn2 "U" 49 | 50 | $result = Invoke-DataQuery $conn2 "select * from U" 51 | 52 | $result[0].x | Should -Be "yyy" 53 | $result[0].y | Should -Be 2 54 | $result[1].x | Should -Be "mmm" 55 | $result[1].y | Should -Be 3 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tests/Invoke-DataQuery.Tests.ps1: -------------------------------------------------------------------------------- 1 | Set-StrictMode -Version 4 2 | 3 | $ACCESS = "$PSScriptRoot\test.accdb" 4 | 5 | Describe "Invoke-DataQuery" { 6 | 7 | BeforeEach { 8 | $mem = New-DataConnection memory 9 | Invoke-DataQuery $mem "create table Test (a, b, c)" 10 | } 11 | 12 | AfterEach { 13 | Close-DataConnection $mem 14 | } 15 | 16 | It "can make a query to SQLite" { 17 | 18 | $result = Invoke-DataQuery $mem "insert into Test (a, b, c) values (10, 'abc', null)" 19 | $result | Should -BeNull 20 | Get-DataQueryResult | Should -Be 1 21 | 22 | $result = Invoke-DataQuery $mem "select * from Test" 23 | 24 | $result | Should -BeOfType [PSObject] 25 | $result[0].a | Should -Be 10 26 | $result[0].b | Should -Be 'abc' 27 | $result[0].c | Should -Be $null 28 | } 29 | 30 | It "can take parameters as hashtable" { 31 | 32 | $result = Invoke-DataQuery $mem "insert into Test (a, b, c) values (@a, @b, @c)" @{ a = 10; b = "xxx"; c = $null } 33 | $result | Should -BeNull 34 | Get-DataQueryResult | Should -Be 1 35 | 36 | $result = Invoke-DataQuery $mem "select * from Test" 37 | 38 | $result | Should -BeOfType [PSObject] 39 | $result[0].a | Should -Be 10 40 | $result[0].b | Should -Be 'xxx' 41 | $result[0].c | Should -Be $null 42 | } 43 | 44 | It "can take parameters as array" { 45 | 46 | $result = Invoke-DataQuery $mem "insert into Test (a, b, c) values (?, ?, ?)" @(10, "xxx", $null) 47 | $result | Should -BeNull 48 | Get-DataQueryResult | Should -Be 1 49 | 50 | $result = Invoke-DataQuery $mem "select * from Test" 51 | 52 | $result | Should -BeOfType [PSObject] 53 | $result[0].a | Should -Be 10 54 | $result[0].b | Should -Be 'xxx' 55 | $result[0].c | Should -Be $null 56 | } 57 | 58 | It "can take parameters as single object" { 59 | 60 | $result = Invoke-DataQuery $mem "insert into Test (a, b, c) values (?, 'xxx', 3)" 999 61 | $result | Should -BeNull 62 | Get-DataQueryResult | Should -Be 1 63 | 64 | $result = Invoke-DataQuery $mem "select * from Test" 65 | 66 | $result | Should -BeOfType [PSObject] 67 | $result[0].a | Should -Be 999 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /docs/New-DataConnectionString.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # New-DataConnectionString 9 | 10 | ## SYNOPSIS 11 | 12 | Creates a connection string based on the given parameters. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | New-DataConnectionString [-ProviderName] [-Parameters] [-TestConnection] 18 | [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | 23 | The New-DataConnectionString cmdlet creates a connection string based on parameters for a specific database provider. 24 | 25 | When the -TestConnection parameter is specified, the cmdlet tries to connect to a database with a newly created connection string. 26 | 27 | ## EXAMPLES 28 | 29 | ## PARAMETERS 30 | 31 | ### -Parameters 32 | 33 | A set of parameters that should be included in a connection string. 34 | 35 | ```yaml 36 | Type: Hashtable 37 | Parameter Sets: (All) 38 | Aliases: 39 | 40 | Required: True 41 | Position: 1 42 | Default value: None 43 | Accept pipeline input: False 44 | Accept wildcard characters: False 45 | ``` 46 | 47 | ### -ProviderName 48 | 49 | A database provider name. 50 | 51 | ```yaml 52 | Type: String 53 | Parameter Sets: (All) 54 | Aliases: 55 | 56 | Required: True 57 | Position: 0 58 | Default value: None 59 | Accept pipeline input: False 60 | Accept wildcard characters: False 61 | ``` 62 | 63 | ### -TestConnection 64 | 65 | Makes the cmdlet to test connectivity of a generated connection string. 66 | 67 | ```yaml 68 | Type: SwitchParameter 69 | Parameter Sets: (All) 70 | Aliases: 71 | 72 | Required: False 73 | Position: 2 74 | Default value: None 75 | Accept pipeline input: False 76 | Accept wildcard characters: False 77 | ``` 78 | 79 | ### CommonParameters 80 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 81 | 82 | ## INPUTS 83 | 84 | ### None 85 | 86 | ## OUTPUTS 87 | 88 | ### System.String 89 | 90 | ## NOTES 91 | 92 | ## RELATED LINKS 93 | -------------------------------------------------------------------------------- /docs/Get-DataSchema.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Get-DataSchema 9 | 10 | ## SYNOPSIS 11 | 12 | Gets database schema information. 13 | 14 | ## SYNTAX 15 | 16 | ### FileOrName 17 | ``` 18 | Get-DataSchema [-FileOrName] [[-CollectionName] ] [] 19 | ``` 20 | 21 | ### Connection 22 | ``` 23 | Get-DataSchema [-Connection] [[-CollectionName] ] [] 24 | ``` 25 | 26 | ## DESCRIPTION 27 | 28 | The Get-DataSchema cmdlet gets database schema information that the database engine provides. If a schema collection name (-CollectionName) is not specified, it returns the information of all available schemas. The provided information varies among database products. 29 | 30 | ## EXAMPLES 31 | 32 | ## PARAMETERS 33 | 34 | ### -CollectionName 35 | 36 | A schama collection name. 37 | 38 | ```yaml 39 | Type: String 40 | Parameter Sets: (All) 41 | Aliases: 42 | 43 | Required: False 44 | Position: 1 45 | Default value: None 46 | Accept pipeline input: False 47 | Accept wildcard characters: False 48 | ``` 49 | 50 | ### -Connection 51 | 52 | A database connection. 53 | 54 | ```yaml 55 | Type: DbConnection 56 | Parameter Sets: Connection 57 | Aliases: 58 | 59 | Required: True 60 | Position: 0 61 | Default value: None 62 | Accept pipeline input: False 63 | Accept wildcard characters: False 64 | ``` 65 | 66 | ### -FileOrName 67 | 68 | A database file name or a connection string name. 69 | 70 | ```yaml 71 | Type: String 72 | Parameter Sets: FileOrName 73 | Aliases: 74 | 75 | Required: True 76 | Position: 0 77 | Default value: None 78 | Accept pipeline input: False 79 | Accept wildcard characters: False 80 | ``` 81 | 82 | ### CommonParameters 83 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 84 | 85 | ## INPUTS 86 | 87 | ### None 88 | 89 | ## OUTPUTS 90 | 91 | ### System.Data.DataRow 92 | 93 | ## NOTES 94 | 95 | ## RELATED LINKS 96 | -------------------------------------------------------------------------------- /docs/Register-DbProviderFactory.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Register-DbProviderFactory 9 | 10 | ## SYNOPSIS 11 | 12 | Registers a database provider factory to the ConfigurationManager. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Register-DbProviderFactory [-Name] [-Invariant] [-Description] [-Type] 18 | [] 19 | ``` 20 | 21 | ## DESCRIPTION 22 | 23 | The Register-DbProviderFactory cmdlet registers a database provider factory to the ConfigurationManager. 24 | 25 | ## EXAMPLES 26 | 27 | ## PARAMETERS 28 | 29 | ### -Description 30 | 31 | A human readable description. 32 | 33 | ```yaml 34 | Type: String 35 | Parameter Sets: (All) 36 | Aliases: 37 | 38 | Required: True 39 | Position: 2 40 | Default value: None 41 | Accept pipeline input: False 42 | Accept wildcard characters: False 43 | ``` 44 | 45 | ### -Invariant 46 | 47 | An invariant name. 48 | 49 | ```yaml 50 | Type: String 51 | Parameter Sets: (All) 52 | Aliases: 53 | 54 | Required: True 55 | Position: 1 56 | Default value: None 57 | Accept pipeline input: False 58 | Accept wildcard characters: False 59 | ``` 60 | 61 | ### -Name 62 | 63 | A database provider name. 64 | 65 | ```yaml 66 | Type: String 67 | Parameter Sets: (All) 68 | Aliases: 69 | 70 | Required: True 71 | Position: 0 72 | Default value: None 73 | Accept pipeline input: False 74 | Accept wildcard characters: False 75 | ``` 76 | 77 | ### -Type 78 | 79 | An assembly qualified name of the provider's factory class. 80 | 81 | ```yaml 82 | Type: String 83 | Parameter Sets: (All) 84 | Aliases: 85 | 86 | Required: True 87 | Position: 3 88 | Default value: None 89 | Accept pipeline input: False 90 | Accept wildcard characters: False 91 | ``` 92 | 93 | ### CommonParameters 94 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 95 | 96 | ## INPUTS 97 | 98 | ### None 99 | 100 | ## OUTPUTS 101 | 102 | ### System.Void 103 | 104 | ## NOTES 105 | 106 | ## RELATED LINKS 107 | -------------------------------------------------------------------------------- /source/dataquery.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29709.97 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Horker.Data.Tests", "Horker.Data.Tests\Horker.Data.Tests.csproj", "{55113E39-5E2F-4707-AC7C-46301DB5EFA2}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Horker.Data", "Horker.Data\Horker.Data.csproj", "{68260625-65C8-47CA-ADCD-2764A55F7796}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|x64 = Debug|x64 14 | Release|Any CPU = Release|Any CPU 15 | Release|x64 = Release|x64 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Debug|x64.ActiveCfg = Debug|Any CPU 21 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Debug|x64.Build.0 = Debug|Any CPU 22 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Release|x64.ActiveCfg = Release|Any CPU 25 | {55113E39-5E2F-4707-AC7C-46301DB5EFA2}.Release|x64.Build.0 = Release|Any CPU 26 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Debug|x64.ActiveCfg = Debug|x64 29 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Debug|x64.Build.0 = Debug|x64 30 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Release|Any CPU.ActiveCfg = Release|Any CPU 31 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Release|Any CPU.Build.0 = Release|Any CPU 32 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Release|x64.ActiveCfg = Release|x64 33 | {68260625-65C8-47CA-ADCD-2764A55F7796}.Release|x64.Build.0 = Release|x64 34 | EndGlobalSection 35 | GlobalSection(SolutionProperties) = preSolution 36 | HideSolutionNode = FALSE 37 | EndGlobalSection 38 | GlobalSection(ExtensibilityGlobals) = postSolution 39 | SolutionGuid = {C9C90415-35AA-4028-8C28-5AE5BDFF44E1} 40 | EndGlobalSection 41 | EndGlobal 42 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/Schema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | using System.Data.Common; 4 | using System.Management.Automation; 5 | 6 | #pragma warning disable CS1591 7 | 8 | namespace Horker.Data 9 | { 10 | /// 11 | /// Gets database schema information. 12 | /// The Get-DataSchema cmdlet gets database schema information that the database engine provides. If a schema collection name (-CollectionName) is not specified, it returns the information of all available schemas. The provided information varies among database products. 13 | /// 14 | [Cmdlet("Get", "DataSchema")] 15 | [OutputType(typeof(DataRow))] 16 | public class GetDataSchema : PSCmdlet 17 | { 18 | /// 19 | /// A database file name or a connection string name. 20 | /// 21 | [Parameter(Position = 0, ParameterSetName = "FileOrName", Mandatory = true)] 22 | public string FileOrName { get; set; } 23 | 24 | /// 25 | /// A database connection. 26 | /// 27 | [Parameter(Position = 0, ParameterSetName = "Connection", Mandatory = true)] 28 | public DbConnection Connection { get; set; } 29 | 30 | /// 31 | /// A schama collection name. 32 | /// 33 | [Parameter(Position = 1, Mandatory = false)] 34 | public string CollectionName { get; set; } 35 | 36 | protected override void EndProcessing() 37 | { 38 | var opener = new ConnectionSpecifier(FileOrName, Connection, null, null); 39 | var connection = opener.Connection; 40 | var connectionOpen = opener.ConnectionOpened; 41 | 42 | try 43 | { 44 | DataTable schema; 45 | if (CollectionName != null && CollectionName != "") 46 | schema = connection.GetSchema(CollectionName); 47 | else 48 | schema = connection.GetSchema(); 49 | 50 | try 51 | { 52 | foreach (var row in schema.Rows) 53 | WriteObject(row); 54 | } 55 | finally 56 | { 57 | schema.Dispose(); 58 | } 59 | } 60 | catch (Exception ex) 61 | { 62 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 63 | } 64 | finally 65 | { 66 | if (connectionOpen) 67 | { 68 | connection.Close(); 69 | connection.Dispose(); 70 | } 71 | } 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /source/Horker.Data/Classes/Helpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Data.Common; 5 | using System.Linq; 6 | using System.Management.Automation; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Horker.Data.Classes 11 | { 12 | internal static class Helpers 13 | { 14 | public static void SetParameters(DbCommand cmd, object parameters) 15 | { 16 | if (parameters == null) 17 | return; 18 | 19 | if (parameters is IDictionary dictParam) 20 | { 21 | foreach (DictionaryEntry entry in dictParam) 22 | { 23 | object value; 24 | if (entry.Value is PSObject psobj) 25 | value = psobj.BaseObject; 26 | else 27 | value = entry.Value; 28 | 29 | var param = cmd.CreateParameter(); 30 | param.ParameterName = (string)entry.Key; 31 | param.Value = value; 32 | cmd.Parameters.Add(param); 33 | } 34 | } 35 | else if (parameters is IEnumerable enumParam) 36 | { 37 | foreach (var v in enumParam) 38 | { 39 | object value; 40 | if (v is PSObject psobj) 41 | value = psobj.BaseObject; 42 | else 43 | value = v; 44 | 45 | var param = cmd.CreateParameter(); 46 | param.Value = value; 47 | cmd.Parameters.Add(param); 48 | } 49 | } 50 | else 51 | throw new ArgumentException("Query parameters must be a IDictionary or an IEnumerable"); 52 | } 53 | 54 | public static DbProviderFactory GetDbProviderFactory(DbConnection connection) 55 | { 56 | DbProviderFactory factory = null; 57 | 58 | // ODBC, OLEDB and SQLite connections fail to obtain the corresponding factories. 59 | if (connection is System.Data.Odbc.OdbcConnection) 60 | { 61 | factory = DbProviderFactories.GetFactory("System.Data.Odbc"); 62 | } 63 | else if (connection is System.Data.OleDb.OleDbConnection) 64 | { 65 | factory = DbProviderFactories.GetFactory("System.Data.OleDb"); 66 | } 67 | else if (connection is System.Data.SQLite.SQLiteConnection) 68 | { 69 | factory = DbProviderFactories.GetFactory("System.Data.SQLite"); 70 | } 71 | else 72 | { 73 | factory = DbProviderFactories.GetFactory(connection); 74 | } 75 | 76 | if (factory == null) 77 | throw new RuntimeException("Failed to obtain a DbProviderFactory object"); 78 | 79 | return factory; 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /source/Horker.Data/Classes/ConnectionSetting.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.Data.Common; 4 | using System.IO; 5 | using System.Management.Automation; 6 | 7 | #pragma warning disable CS1591 8 | 9 | namespace Horker.Data 10 | { 11 | public abstract class ConnectionSetting 12 | { 13 | public abstract DbConnection GetConnection(); 14 | } 15 | 16 | public class ProviderConnectionSetting : ConnectionSetting 17 | { 18 | public string ProviderName { get; set; } 19 | public string ConnectionString { get; set; } 20 | 21 | public ProviderConnectionSetting(string providerName, string connectionString) 22 | { 23 | ProviderName = providerName; 24 | ConnectionString = connectionString; 25 | } 26 | 27 | public override DbConnection GetConnection() 28 | { 29 | DbProviderFactory factory = DbProviderFactories.GetFactory(ProviderName); 30 | 31 | var conn = factory.CreateConnection(); 32 | conn.ConnectionString = ConnectionString; 33 | conn.Open(); 34 | 35 | return conn; 36 | } 37 | } 38 | 39 | public class FileConnectionSetting : ConnectionSetting 40 | { 41 | public string FileOrName { get; private set; } 42 | 43 | public FileConnectionSetting(string fileOrName) 44 | { 45 | FileOrName = fileOrName; 46 | } 47 | 48 | public override DbConnection GetConnection() 49 | { 50 | // Look up configuration 51 | var cs = ConfigurationManager.ConnectionStrings[FileOrName]; 52 | if (cs != null) 53 | return new ProviderConnectionSetting(cs.ProviderName, cs.ConnectionString).GetConnection(); 54 | 55 | // Access file? 56 | if (FileOrName.EndsWith(".accdb") || FileOrName.EndsWith(".mdb")) 57 | { 58 | var builder = new System.Data.Odbc.OdbcConnectionStringBuilder(); 59 | builder.Add("Driver", "{Microsoft Access Driver (*.mdb, *.accdb)}"); 60 | builder.Add("Dbq", FileOrName); 61 | 62 | var conn = new System.Data.Odbc.OdbcConnection(); 63 | conn.ConnectionString = builder.ConnectionString; 64 | conn.Open(); 65 | 66 | return conn; 67 | } 68 | 69 | // Assume a SQLite file 70 | // Restricts to an exsiting file to prevent mistyping from creating a new database 71 | if (File.Exists(FileOrName)) 72 | { 73 | var builder = new System.Data.SQLite.SQLiteConnectionStringBuilder(); 74 | builder.Add("Data Source", FileOrName); 75 | 76 | var conn = new System.Data.SQLite.SQLiteConnection(); 77 | conn.ConnectionString = builder.ConnectionString; 78 | conn.Open(); 79 | 80 | return conn; 81 | } 82 | 83 | throw new RuntimeException(String.Format("'{0}' is not a database file name nor connection string name", FileOrName)); 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /.build.ps1: -------------------------------------------------------------------------------- 1 | task . Compile, Build, ImportDebug, Test 2 | 3 | Set-StrictMode -Version 4 4 | 5 | ############################################################ 6 | 7 | $SOURCE_PATH = "$PSScriptRoot\source" 8 | $SCRIPT_PATH = "$PSScriptRoot\scripts" 9 | 10 | $DLL_PATH = "$SOURCE_PATH\Horker.Data.Tests\bin\{0}\netcoreapp3.1" 11 | 12 | $MODULE_PATH = "$PSScriptRoot\module\{0}\HorkerDataQuery" 13 | 14 | $HELP_INPUT = "$SOURCE_PATH\Horker.Data.Tests\bin\Release\netcoreapp3.1\Horker.Data.dll" 15 | $HELP_INTERM = "$SOURCE_PATH\Horker.Data.Tests\bin\Release\netcoreapp3.1\Horker.Data.dll-Help.xml" 16 | $HELP_OUTPUT = "$MODULE_PATH\Horker.Data.dll-Help.xml" -f "Release" 17 | 18 | $HELPGEN = "$PSScriptRoot\vendor\XmlDoc2CmdletDoc.0.2.13\tools\XmlDoc2CmdletDoc.exe" 19 | 20 | $OBJECT_FILES = @( 21 | "Horker.Data.dll" 22 | "Horker.Data.pdb" 23 | "System.Data.Odbc.dll" 24 | "System.Data.OleDb.dll" 25 | "System.Data.SqlClient.dll" 26 | "System.Data.SQLite.dll" 27 | "Npgsql.dll" 28 | ) 29 | 30 | $NATIVE_PATH = "$PSScriptRoot\vendor\System.Data.SQLite.Core.1.0.112.0\runtimes\win-x64\native\netstandard2.0" 31 | 32 | ############################################################ 33 | 34 | function New-FolderSkip { 35 | param( 36 | [string]$Path 37 | ) 38 | 39 | try { 40 | $null = New-Item -Type Directory $Path -EA Stop 41 | Write-Host -ForegroundColor DarkCyan $Path 42 | } 43 | catch { 44 | Write-Host -ForegroundColor DarkYellow $_ 45 | } 46 | } 47 | 48 | function Copy-ItemSkip { 49 | param( 50 | [string]$Source, 51 | [string]$Dest 52 | ) 53 | 54 | try { 55 | Copy-Item $Source $Dest 56 | Write-Host -ForegroundColor DarkCyan "$Source => $Dest" 57 | } 58 | catch { 59 | Write-Host -ForegroundColor DarkYellow $_ 60 | } 61 | } 62 | 63 | ############################################################ 64 | 65 | task Compile { 66 | dotnet build "$SOURCE_PATH\dataquery.sln" -c Debug -nologo -v minimal 67 | dotnet build "$SOURCE_PATH\dataquery.sln" -c Release -nologo -v minimal 68 | } 69 | 70 | task Build { 71 | 72 | . { 73 | $ErrorActionPreference = "Continue" 74 | 75 | "Release", "Debug" | foreach { 76 | $modulePath = $MODULE_PATH -f $_ 77 | $dllPath = $DLL_PATH -f "Release" 78 | 79 | New-FolderSkip "$modulePath\x64" 80 | 81 | Copy-ItemSkip "$SCRIPT_PATH\*" $modulePath 82 | 83 | foreach ($f in $OBJECT_FILES) { 84 | Copy-ItemSkip "$dllPath\$f" $modulePath 85 | } 86 | 87 | Copy-ItemSkip "$NATIVE_PATH\*" "$modulePath\x64\" 88 | } 89 | } 90 | } 91 | 92 | task UpdateHelp { 93 | Update-MarkdownHelp HorkerDataQuery $PSScriptRoot\docs 94 | } 95 | task BuildHelp { 96 | $outputFolder = "$PSScriptRoot\module\release\HorkerDataQuery\en-US" 97 | New-ExternalHelp -Path $PSScriptRoot\docs -OutputPath $outputFolder 98 | Copy-Item $outputFolder\* $PSScriptRoot\module\debug\HorkerDataQuery\en-US\ 99 | } 100 | 101 | task Test { 102 | Invoke-Pester "$PSScriptRoot\tests" 103 | } 104 | 105 | task ImportDebug { 106 | Import-Module ($MODULE_PATH -f "Debug") -Force 107 | } 108 | 109 | task Clean { 110 | "Release", "Debug" | foreach { 111 | $modulePath = $MODULE_PATH -f $_ 112 | Remove-Item "$modulePath\*" -Force -Recurse -EA Continue 113 | } 114 | } 115 | -------------------------------------------------------------------------------- /docs/Export-DataTable.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Export-DataTable 9 | 10 | ## SYNOPSIS 11 | 12 | Inserts objects as data rows into a database table. 13 | 14 | ## SYNTAX 15 | 16 | ### FileOrName 17 | ``` 18 | Export-DataTable [-InputObject ] [-FileOrName] [-TableName] 19 | [[-AdditionalColumns] ] [[-TypeName] ] [] 20 | ``` 21 | 22 | ### Connection 23 | ``` 24 | Export-DataTable [-InputObject ] [-Connection] [-TableName] 25 | [[-AdditionalColumns] ] [[-TypeName] ] [] 26 | ``` 27 | 28 | ## DESCRIPTION 29 | 30 | The Export-DataTable cmdlet inserts pipeline objects into a database table specified by the -TableName parameter. 31 | 32 | The properties of the objects are mapped to the database columns with the same names. If there are no corresponding columns in the table, such properties are ignored. 33 | 34 | If the specified table does not exist, the cmdlet will create a new table based on the structure of the given object. In the current version, all columns are defined as a string type. (This does not matter for SQLite because it allows to apply arithmetic operations to string columns.) If you need a table with exact types, create a table manually by the Invoke-DataQuery cmdlet beforehand. 35 | 36 | ## EXAMPLES 37 | 38 | ## PARAMETERS 39 | 40 | ### -AdditionalColumns 41 | 42 | Additional column names. 43 | 44 | ```yaml 45 | Type: String[] 46 | Parameter Sets: (All) 47 | Aliases: 48 | 49 | Required: False 50 | Position: 2 51 | Default value: None 52 | Accept pipeline input: False 53 | Accept wildcard characters: False 54 | ``` 55 | 56 | ### -Connection 57 | 58 | A database connection. 59 | 60 | ```yaml 61 | Type: DbConnection 62 | Parameter Sets: Connection 63 | Aliases: 64 | 65 | Required: True 66 | Position: 0 67 | Default value: None 68 | Accept pipeline input: False 69 | Accept wildcard characters: False 70 | ``` 71 | 72 | ### -FileOrName 73 | 74 | A database file name or a connection string name. 75 | 76 | ```yaml 77 | Type: String 78 | Parameter Sets: FileOrName 79 | Aliases: 80 | 81 | Required: True 82 | Position: 0 83 | Default value: None 84 | Accept pipeline input: False 85 | Accept wildcard characters: False 86 | ``` 87 | 88 | ### -InputObject 89 | 90 | Objects to be inserted into a database table. 91 | 92 | ```yaml 93 | Type: Object 94 | Parameter Sets: (All) 95 | Aliases: 96 | 97 | Required: False 98 | Position: Named 99 | Default value: None 100 | Accept pipeline input: True (ByValue) 101 | Accept wildcard characters: False 102 | ``` 103 | 104 | ### -TableName 105 | 106 | A table name into which objects will be inserted. 107 | 108 | The value is used without being quoted when the cmdlet generates internal SQL statements. Thus, you should specify this parameter with explicit quotes if necessary. 109 | 110 | ```yaml 111 | Type: String 112 | Parameter Sets: (All) 113 | Aliases: 114 | 115 | Required: True 116 | Position: 1 117 | Default value: None 118 | Accept pipeline input: False 119 | Accept wildcard characters: False 120 | ``` 121 | 122 | ### -TypeName 123 | 124 | A type of columns of a newly created table. By default, it is one of 'varchar' (general databases), 'nvarchar' (SQL Server), 'varchar2' (Oracle), or an empty string (SQLite). 125 | 126 | ```yaml 127 | Type: String 128 | Parameter Sets: (All) 129 | Aliases: 130 | 131 | Required: False 132 | Position: 3 133 | Default value: None 134 | Accept pipeline input: False 135 | Accept wildcard characters: False 136 | ``` 137 | 138 | ### CommonParameters 139 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 140 | 141 | ## INPUTS 142 | 143 | ### System.Object 144 | 145 | ## OUTPUTS 146 | 147 | ### System.Void 148 | 149 | ## NOTES 150 | 151 | ## RELATED LINKS 152 | -------------------------------------------------------------------------------- /docs/Copy-DataRow.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Copy-DataRow 9 | 10 | ## SYNOPSIS 11 | 12 | Copy data from one database to another. 13 | 14 | ## SYNTAX 15 | 16 | ``` 17 | Copy-DataRow [-SourceConnection] [-SourceSql] 18 | [-TargetConnection] [[-TargetTable] ] [[-SourceParameters] ] 19 | [[-TargetSql] ] [[-Timeout] ] [] 20 | ``` 21 | 22 | ## DESCRIPTION 23 | 24 | The Copy-DataRow cmdlet obtains a dataset from a database specified by the -SourceConnection parameter by executing the -SourceSql statement and inserts them to another database specified bu the -TargetConnection parameter. 25 | 26 | When you specify a target table name by the -TargetTable parameter, the cmdlet assumes the table contains the same set of columns as the source dataset and inserts them into the corresponding columns. 27 | 28 | When you specify a SQL statement by the -TargetSql parameter, the cmdlet executes it for each data row of the source dataset. The SQL statement should contain named parameters corresponding to the columns of the source dataset. 29 | 30 | You can specify either one of the -TargetTable or -TargetSql parameters. 31 | 32 | ## EXAMPLES 33 | 34 | ## PARAMETERS 35 | 36 | ### -SourceConnection 37 | 38 | A DbConnection object, a connection string name or a database file name (SQLite or Access) of the source database. 39 | 40 | ```yaml 41 | Type: ConnectionSpecifier 42 | Parameter Sets: (All) 43 | Aliases: 44 | 45 | Required: True 46 | Position: 0 47 | Default value: None 48 | Accept pipeline input: False 49 | Accept wildcard characters: False 50 | ``` 51 | 52 | ### -SourceParameters 53 | 54 | Query parameters applied to the -SourceSql statement. 55 | 56 | ```yaml 57 | Type: Object 58 | Parameter Sets: (All) 59 | Aliases: 60 | 61 | Required: False 62 | Position: 4 63 | Default value: None 64 | Accept pipeline input: False 65 | Accept wildcard characters: False 66 | ``` 67 | 68 | ### -SourceSql 69 | 70 | An SQL statement to obtain data from the source database. 71 | 72 | ```yaml 73 | Type: String 74 | Parameter Sets: (All) 75 | Aliases: 76 | 77 | Required: True 78 | Position: 1 79 | Default value: None 80 | Accept pipeline input: False 81 | Accept wildcard characters: False 82 | ``` 83 | 84 | ### -TargetConnection 85 | 86 | A DbConnection object, a connection string name or a database file name (SQLite or Access) of the target database. 87 | 88 | ```yaml 89 | Type: ConnectionSpecifier 90 | Parameter Sets: (All) 91 | Aliases: 92 | 93 | Required: True 94 | Position: 2 95 | Default value: None 96 | Accept pipeline input: False 97 | Accept wildcard characters: False 98 | ``` 99 | 100 | ### -TargetSql 101 | 102 | An SQL statement to be used for copying the data. It is usually an INSERT or UPDATE statement with the corresponding named parameters to the columns of the source dataset. 103 | 104 | ```yaml 105 | Type: String 106 | Parameter Sets: (All) 107 | Aliases: 108 | 109 | Required: False 110 | Position: 5 111 | Default value: None 112 | Accept pipeline input: False 113 | Accept wildcard characters: False 114 | ``` 115 | 116 | ### -TargetTable 117 | 118 | A name of the table into which data will be inserted. 119 | 120 | ```yaml 121 | Type: String 122 | Parameter Sets: (All) 123 | Aliases: 124 | 125 | Required: False 126 | Position: 3 127 | Default value: None 128 | Accept pipeline input: False 129 | Accept wildcard characters: False 130 | ``` 131 | 132 | ### -Timeout 133 | 134 | A timeout in seconds. 135 | 136 | ```yaml 137 | Type: Int32 138 | Parameter Sets: (All) 139 | Aliases: 140 | 141 | Required: False 142 | Position: 6 143 | Default value: None 144 | Accept pipeline input: False 145 | Accept wildcard characters: False 146 | ``` 147 | 148 | ### CommonParameters 149 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 150 | 151 | ## INPUTS 152 | 153 | ### None 154 | 155 | ## OUTPUTS 156 | 157 | ### System.Void 158 | 159 | ## NOTES 160 | 161 | ## RELATED LINKS 162 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/Connection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Management.Automation; 4 | using System.Data; 5 | using System.Data.Common; 6 | 7 | #pragma warning disable CS1591 8 | 9 | namespace Horker.Data 10 | { 11 | /// 12 | /// Opens a database connection. 13 | /// The New-DataConnection cmdlet opens a database connection. 14 | /// 15 | [Cmdlet("New", "DataConnection", DefaultParameterSetName = "FileOrName")] 16 | [Alias("Open", "DataConnection")] 17 | [OutputType(typeof(DbConnection))] 18 | public class NewDataConnection : PSCmdlet 19 | { 20 | /// 21 | /// A database file name or a connection string name. 22 | /// 23 | [Parameter(Position = 0, ParameterSetName = "FileOrName", Mandatory = true)] 24 | public string FileOrName { get; set; } 25 | 26 | /// 27 | /// A database provider name. 28 | /// 29 | [Parameter(Position = 0, ParameterSetName = "ConnectionString", Mandatory = true)] 30 | public string ProviderName { get; set; } 31 | 32 | /// 33 | /// A connection string. 34 | /// 35 | [Parameter(Position = 1, ParameterSetName = "ConnectionString", Mandatory = true)] 36 | public string ConnectionString { get; set; } 37 | 38 | protected override void EndProcessing() 39 | { 40 | try { 41 | var opener = new ConnectionSpecifier(FileOrName, null, ProviderName, ConnectionString); 42 | 43 | WriteObject(opener.Connection); 44 | } 45 | catch (Exception ex) { 46 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 47 | } 48 | } 49 | } 50 | 51 | /// 52 | /// Closes a database connection. 53 | /// The Close-DataConnection cmdlet closes a database connection. 54 | /// 55 | [Cmdlet("Close", "DataConnection")] 56 | [OutputType(typeof(void))] 57 | public class CloseDataConnection : PSCmdlet 58 | { 59 | /// 60 | /// A database connection. 61 | /// 62 | [Parameter(Position = 0, Mandatory = true)] 63 | public DbConnection Connection; 64 | 65 | protected override void EndProcessing() 66 | { 67 | try { 68 | Connection.Close(); 69 | Connection.Dispose(); 70 | } 71 | catch (Exception ex) { 72 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, Connection)); 73 | } 74 | } 75 | } 76 | 77 | /// 78 | /// Gets open database connections in the current session. 79 | /// The Get-DataConnectionHistory cmdlet gets open database connections in the current session that you have opened explicitly by the New-DataConnection cmdlet, or implicitly by the other cmdlets you invoked. 80 | /// This cmdlet is useful when you need to investigate untracked open connections causing a trouble (acquiring a file lock, for example). 81 | /// 82 | [Cmdlet("Get", "DataConnectionHistory")] 83 | [OutputType(typeof(DbConnection))] 84 | public class GetDataConnectionHistory : PSCmdlet 85 | { 86 | private static List _connectionHistory = new List(); 87 | 88 | public static void AddToHistory(DbConnection conn) 89 | { 90 | RemoveClosedConnection(); 91 | _connectionHistory.Insert(0, conn); 92 | } 93 | 94 | protected override void EndProcessing() 95 | { 96 | RemoveClosedConnection(); 97 | foreach (var c in _connectionHistory) { 98 | WriteObject(c); 99 | } 100 | } 101 | 102 | private static void RemoveClosedConnection() 103 | { 104 | _connectionHistory.RemoveAll(c => { 105 | try 106 | { 107 | return c.State == ConnectionState.Closed; 108 | } 109 | catch (ObjectDisposedException) 110 | { 111 | return true; 112 | } 113 | }); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /docs/Invoke-DataQuery.md: -------------------------------------------------------------------------------- 1 | --- 2 | external help file: Horker.Data.dll-Help.xml 3 | Module Name: HorkerDataQuery 4 | online version: 5 | schema: 2.0.0 6 | --- 7 | 8 | # Invoke-DataQuery 9 | 10 | ## SYNOPSIS 11 | 12 | Executes a database query. 13 | 14 | ## SYNTAX 15 | 16 | ### FileOrName 17 | ``` 18 | Invoke-DataQuery [-FileOrName] [-Query] [[-Parameters] ] [[-Timeout] ] 19 | [-ShowRecordsAffected] [-PreserveDbNull] [-AsDataRow] [-AsDataTable] [] 20 | ``` 21 | 22 | ### Connection 23 | ``` 24 | Invoke-DataQuery [-Connection] [-Query] [[-Parameters] ] [[-Timeout] ] 25 | [-ShowRecordsAffected] [-PreserveDbNull] [-AsDataRow] [-AsDataTable] [] 26 | ``` 27 | 28 | ## DESCRIPTION 29 | 30 | The Invoke-DataQuery cmdlet executes an SQL statement to a database. 31 | 32 | Despite its name, this cmdlet can execute any SQL statement, including INSERT, DELETE and CREATE. When such a statement is executed, no result will return. By specifying the -ShowRecordsAffected parameter, you can get the number of records affected by the statement. You can always obtain the same value by the Get-DataQueryResult cmdlet. 33 | 34 | By default, the DBNull values in the result data set are replaced with normal null values, and the results are returned as a stream of PSObject values. You can change this behavior by the -PreserveDbNull, -AsDataRows and -AsDataTable switch parameters. 35 | 36 | ## EXAMPLES 37 | 38 | ## PARAMETERS 39 | 40 | ### -AsDataRow 41 | 42 | Indicates to return the result dataset as an array of System.Data.DataRow instead of PSObject. 43 | 44 | ```yaml 45 | Type: SwitchParameter 46 | Parameter Sets: (All) 47 | Aliases: 48 | 49 | Required: False 50 | Position: Named 51 | Default value: None 52 | Accept pipeline input: False 53 | Accept wildcard characters: False 54 | ``` 55 | 56 | ### -AsDataTable 57 | 58 | Indicates to return the result dataset as System.Data.DataTable instead of an array of PSObjects. 59 | 60 | ```yaml 61 | Type: SwitchParameter 62 | Parameter Sets: (All) 63 | Aliases: 64 | 65 | Required: False 66 | Position: Named 67 | Default value: None 68 | Accept pipeline input: False 69 | Accept wildcard characters: False 70 | ``` 71 | 72 | ### -Connection 73 | 74 | A database connection. 75 | 76 | ```yaml 77 | Type: DbConnection 78 | Parameter Sets: Connection 79 | Aliases: 80 | 81 | Required: True 82 | Position: 0 83 | Default value: None 84 | Accept pipeline input: False 85 | Accept wildcard characters: False 86 | ``` 87 | 88 | ### -FileOrName 89 | 90 | A database file name or a connection string name. 91 | 92 | ```yaml 93 | Type: String 94 | Parameter Sets: FileOrName 95 | Aliases: 96 | 97 | Required: True 98 | Position: 0 99 | Default value: None 100 | Accept pipeline input: False 101 | Accept wildcard characters: False 102 | ``` 103 | 104 | ### -Parameters 105 | 106 | Query parameters. 107 | 108 | ```yaml 109 | Type: Object 110 | Parameter Sets: (All) 111 | Aliases: 112 | 113 | Required: False 114 | Position: 2 115 | Default value: None 116 | Accept pipeline input: False 117 | Accept wildcard characters: False 118 | ``` 119 | 120 | ### -PreserveDbNull 121 | 122 | Stops replacing the DBNull values in the results with normal null values. 123 | 124 | ```yaml 125 | Type: SwitchParameter 126 | Parameter Sets: (All) 127 | Aliases: 128 | 129 | Required: False 130 | Position: Named 131 | Default value: None 132 | Accept pipeline input: False 133 | Accept wildcard characters: False 134 | ``` 135 | 136 | ### -Query 137 | 138 | An SQL statement to be executed. 139 | 140 | ```yaml 141 | Type: String 142 | Parameter Sets: (All) 143 | Aliases: 144 | 145 | Required: True 146 | Position: 1 147 | Default value: None 148 | Accept pipeline input: False 149 | Accept wildcard characters: False 150 | ``` 151 | 152 | ### -ShowRecordsAffected 153 | 154 | Specifies whether the number of records affected by the SQL statement should be returned. 155 | 156 | ```yaml 157 | Type: SwitchParameter 158 | Parameter Sets: (All) 159 | Aliases: 160 | 161 | Required: False 162 | Position: Named 163 | Default value: None 164 | Accept pipeline input: False 165 | Accept wildcard characters: False 166 | ``` 167 | 168 | ### -Timeout 169 | 170 | A query timeout in seconds. 171 | 172 | ```yaml 173 | Type: Int32 174 | Parameter Sets: (All) 175 | Aliases: 176 | 177 | Required: False 178 | Position: 3 179 | Default value: None 180 | Accept pipeline input: False 181 | Accept wildcard characters: False 182 | ``` 183 | 184 | ### CommonParameters 185 | This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). 186 | 187 | ## INPUTS 188 | 189 | ### None 190 | 191 | ## OUTPUTS 192 | 193 | ### System.Management.Automation.PSObject 194 | 195 | ### System.Data.DataRow 196 | 197 | ### System.Data.DataTable 198 | 199 | ## NOTES 200 | 201 | ## RELATED LINKS 202 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/Configuration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Management.Automation; 3 | using System.Xml; 4 | 5 | #pragma warning disable CS1591 6 | 7 | namespace Horker.Data 8 | { 9 | /// 10 | /// Registers connection strings and database provider factories. 11 | /// The Register-DataConfiguration cmdlet reads a configuration file (app.config or web.config in most cases), finds the /configuration/connectionStrings and /configuration/system.data/DbProviderFactories sections and, according to their contents, registers connection strings and database provider factories to the ConfigurationManager. 12 | /// 13 | [Cmdlet("Register", "DataConfiguration")] 14 | [OutputType(typeof(void))] 15 | public class RegisterDataConfiguration : PSCmdlet 16 | { 17 | /// 18 | /// A configuration file name. 19 | /// 20 | [Parameter(Position = 0, Mandatory = true)] 21 | public string ConfigurationFile { get; set; } 22 | 23 | protected override void EndProcessing() 24 | { 25 | try 26 | { 27 | LoadConfiguration(ConfigurationFile); 28 | } 29 | catch (Exception ex) 30 | { 31 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 32 | } 33 | } 34 | 35 | public static void LoadConfiguration(string configurationFile) 36 | { 37 | var doc = new XmlDocument(); 38 | doc.Load(configurationFile); 39 | 40 | RegisterDbProviderFactories(doc); 41 | RegisterConnectionString(doc); 42 | } 43 | 44 | private static void RegisterDbProviderFactories(XmlDocument doc) 45 | { 46 | var baseNodes = doc.DocumentElement.SelectNodes("/configuration/system.data/DbProviderFactories"); 47 | 48 | foreach (XmlNode node in baseNodes) 49 | { 50 | var nodes = node.ChildNodes; 51 | 52 | string invariant; 53 | foreach (XmlNode n in nodes) 54 | { 55 | switch (n.Name) 56 | { 57 | case "add": 58 | var name = n.Attributes["name"].InnerText; 59 | invariant = n.Attributes["invariant"].InnerText; 60 | var description = n.Attributes["description"].InnerText; 61 | var type = n.Attributes["type"].InnerText; 62 | RegisterDbProviderFactory.AddDbProviderFactory(name, invariant, description, type); 63 | break; 64 | 65 | case "remove": 66 | invariant = n.Attributes["invariant"].InnerText; 67 | try 68 | { 69 | UnregisterDbProviderFactory.RemoveDbProviderFactory(invariant); 70 | } 71 | catch (RuntimeException) 72 | { 73 | // Ignore error 74 | } 75 | break; 76 | 77 | case "clear": 78 | try 79 | { 80 | UnregisterDbProviderFactory.RemoveAllDbProviderFactories(); 81 | } 82 | catch (RuntimeException) 83 | { 84 | // Ignore error 85 | } 86 | break; 87 | 88 | default: 89 | throw new RuntimeException(String.Format("Unknown element '{0}' under system.data/DbProviderFactories", n.Name)); 90 | } 91 | } 92 | } 93 | } 94 | 95 | private static void RegisterConnectionString(XmlDocument doc) 96 | { 97 | var baseNodes = doc.DocumentElement.SelectNodes("/configuration/connectionStrings"); 98 | foreach (XmlNode node in baseNodes) 99 | { 100 | var nodes = node.ChildNodes; 101 | 102 | string name; 103 | foreach (XmlNode n in nodes) 104 | { 105 | switch (n.Name) 106 | { 107 | case "add": 108 | name = n.Attributes["name"].InnerText; 109 | var providerName = n.Attributes["providerName"].InnerText; 110 | var connectionString = n.Attributes["connectionString"].InnerText; 111 | RegisterDataConnectionString.AddConnectionString(name, providerName, connectionString); 112 | 113 | break; 114 | 115 | case "remove": 116 | name = n.Attributes["name"].InnerText; 117 | try 118 | { 119 | UnregisterDataConnectionString.RemoveConnectionString(name); 120 | } 121 | catch (RuntimeException) 122 | { 123 | // Ignore error 124 | } 125 | break; 126 | 127 | case "clear": 128 | try 129 | { 130 | UnregisterDataConnectionString.RemoveAllConnectionStrings(); 131 | } 132 | catch (RuntimeException) 133 | { 134 | // Ignore error 135 | } 136 | break; 137 | 138 | default: 139 | throw new RuntimeException(String.Format("Unknown element '{0}' under /connectionStrings", n.Name)); 140 | } 141 | } 142 | } 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /scripts/HorkerDataQuery.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'HorkerDataQuery' 3 | # 4 | # Generated by: horker 5 | # 6 | # Generated on: 2017/12/03 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'HorkerDataQuery.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '2.0.0' 16 | 17 | # Supported PSEditions 18 | CompatiblePSEditions = 'Core' 19 | 20 | # ID used to uniquely identify this module 21 | GUID = 'fb732285-38d2-40da-93d1-be7cde81ddf7' 22 | 23 | # Author of this module 24 | Author = 'horker' 25 | 26 | # Company or vendor of this module 27 | CompanyName = '' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) 2018-2020 horker. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = "Horker DataQuery is a database query utility based on System.Data classes of .NET Core. 34 | 35 | The main features are: 36 | - Written in C# so that it works fast for large data 37 | - Supports every database library that implements the System.Data interface, including SQL Server, Oracle, MySQL, PostgreSQL, SQLite, Access, OLEDB and ODBC 38 | - PowerShell interoperatability; gets query results as PowerShell objects and exports PowerShell objects into database tables 39 | - Reads app.config or web.config in your app to define database providers and connection strings 40 | - Gets information from the database schema 41 | - Provides the built-in ODBC, OLEDB and SQLite drivers 42 | 43 | This module would be helpful for software development, data analysis, and various data manipulation tasks. 44 | 45 | For more details, see the project site: https://github.com/horker/dataquery" 46 | 47 | # Minimum version of the Windows PowerShell engine required by this module 48 | PowerShellVersion = '6.0' 49 | 50 | # Name of the Windows PowerShell host required by this module 51 | # PowerShellHostName = '' 52 | 53 | # Minimum version of the Windows PowerShell host required by this module 54 | # PowerShellHostVersion = '' 55 | 56 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 57 | #DotNetFrameworkVersion = '4.5' 58 | 59 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 60 | # CLRVersion = '' 61 | 62 | # Processor architecture (None, X86, Amd64) required by this module 63 | # ProcessorArchitecture = '' 64 | 65 | # Modules that must be imported into the global environment prior to importing this module 66 | # RequiredModules = @() 67 | 68 | # Assemblies that must be loaded prior to importing this module 69 | RequiredAssemblies = @( 70 | "System.Data.Odbc.dll" 71 | "System.Data.OleDb.dll" 72 | "System.Data.SqlClient.dll" 73 | "System.Data.SQLite.dll" 74 | "Npgsql.dll" 75 | ) 76 | 77 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 78 | # ScriptsToProcess = @() 79 | 80 | # Type files (.ps1xml) to be loaded when importing this module 81 | # TypesToProcess = @() 82 | 83 | # Format files (.ps1xml) to be loaded when importing this module 84 | # FormatsToProcess = @() 85 | 86 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 87 | NestedModules = @( 88 | "Horker.Data.dll" 89 | ) 90 | 91 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 92 | FunctionsToExport = @() 93 | 94 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 95 | CmdletsToExport = @( 96 | "Invoke-DataQuery" 97 | "Get-DataQueryResult" 98 | "Export-DataTable" 99 | "Copy-DataRow" 100 | 101 | "New-DataConnection" 102 | "Close-DataConnection" 103 | "Get-DataConnectionHistory" 104 | 105 | "Register-DataConnectionString" 106 | "Unregister-DataConnectionString" 107 | "Get-DataConnectionString" 108 | "New-DataConnectionString" 109 | 110 | "Register-DbProviderFactory" 111 | "Unregister-DbProviderFactory" 112 | "Get-DbProviderFactory" 113 | 114 | "Register-DataConfiguration" 115 | 116 | "Get-DataSchema" 117 | ) 118 | 119 | # Variables to export from this module 120 | VariablesToExport = @() 121 | 122 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 123 | AliasesToExport = @( 124 | "idq" 125 | ) 126 | 127 | # DSC resources to export from this module 128 | # DscResourcesToExport = @() 129 | 130 | # List of all modules packaged with this module 131 | # ModuleList = @() 132 | 133 | # List of all files packaged with this module 134 | # FileList = @() 135 | 136 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 137 | PrivateData = @{ 138 | 139 | PSData = @{ 140 | 141 | # Tags applied to this module. These help with module discovery in online galleries. 142 | Tags = @( 143 | 'database', 'relational', 'rdb', 'rdbms', 'schema', 'table', 'column', 144 | 'data', 'analysis', 'conversion', 145 | 'query', 'select', 'insert', 'update', 'delete', 'create', 'drop', 146 | 'sql', 'server', 'sqlserver', 'oracle', 'mysql', 'postgresql', 147 | 'firebird', 'db2', 'sqlite', 'access', 'msaccess' 148 | ) 149 | 150 | # A URL to the license for this module. 151 | LicenseUri = 'https://opensource.org/licenses/MIT' 152 | 153 | # A URL to the main website for this project. 154 | ProjectUri = 'https://github.com/horker/dataquery' 155 | 156 | # A URL to an icon representing this module. 157 | # IconUri = '' 158 | 159 | # ReleaseNotes of this module 160 | ReleaseNotes = @" 161 | v2.0.0 162 | - Move to .NET Core and PowerShell Core 163 | - Define Copy-DataRow 164 | 165 | v1.0.5 166 | - Releasing native resources (database connections) in more timely manner 167 | - Improvements of data handling in Export-DataTable 168 | - Query results as System.Data.DataTable 169 | - Several improvements and bug fixes 170 | 171 | v1.0.1 - v1.0.4 172 | Bug fixes 173 | 174 | v1.0.0 175 | First release 176 | "@ 177 | 178 | } # End of PSData hashtable 179 | 180 | } # End of PrivateData hashtable 181 | 182 | # HelpInfo URI of this module 183 | # HelpInfoURI = '' 184 | 185 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 186 | # DefaultCommandPrefix = '' 187 | 188 | } 189 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/DbProviderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Configuration; 3 | using System.Data; 4 | using System.Data.Common; 5 | using System.Management.Automation; 6 | 7 | #pragma warning disable CS1591 8 | 9 | namespace Horker.Data 10 | { 11 | /// 12 | /// Registers a database provider factory to the ConfigurationManager. 13 | /// The Register-DbProviderFactory cmdlet registers a database provider factory to the ConfigurationManager. 14 | /// 15 | [Cmdlet("Register", "DbProviderFactory")] 16 | [OutputType(typeof(void))] 17 | public class RegisterDbProviderFactory : PSCmdlet 18 | { 19 | /// 20 | /// A database provider name. 21 | /// 22 | [Parameter(Position = 0, Mandatory = true)] 23 | public string Name { get; set; } 24 | 25 | /// 26 | /// An invariant name. 27 | /// 28 | [Parameter(Position = 1, Mandatory = true)] 29 | public string Invariant { get; set; } 30 | 31 | /// 32 | /// A human readable description. 33 | /// 34 | [Parameter(Position = 2, Mandatory = true)] 35 | public string Description { get; set; } 36 | 37 | /// 38 | /// Factory classes specification. 39 | /// 40 | [Parameter(Position = 3, Mandatory = true)] 41 | public string Type { get; set; } 42 | 43 | protected override void EndProcessing() 44 | { 45 | try 46 | { 47 | AddDbProviderFactory(Name, Invariant, Description, Type); 48 | } 49 | catch (Exception ex) 50 | { 51 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 52 | } 53 | } 54 | 55 | public static void AddDbProviderFactory(string name, string invariant, string description, string type) 56 | { 57 | using (DataSet dataSet = ConfigurationManager.GetSection("system.data") as DataSet) 58 | { 59 | if (dataSet == null) 60 | { 61 | // .NET Core 62 | DbProviderFactories.RegisterFactory(invariant, type); 63 | return; 64 | } 65 | 66 | var rows = dataSet.Tables[0].Rows; 67 | 68 | foreach (DataRow r in rows) 69 | { 70 | if (r["InvariantName"].ToString() == invariant) 71 | throw new RuntimeException("Invariant name already exists"); 72 | } 73 | 74 | rows.Add(name, description, invariant, type); 75 | } 76 | } 77 | } 78 | 79 | /// 80 | /// Removes a database provider factory from the ConfigurationManager. 81 | /// The Unregister-DbProviderFactory cmdlet removes a database provider factory from the ConfigurationManager. 82 | /// 83 | [Cmdlet("Unregister", "DbProviderFactory")] 84 | [OutputType(typeof(void))] 85 | public class UnregisterDbProviderFactory : PSCmdlet 86 | { 87 | /// 88 | /// A database provider name. 89 | /// 90 | [Parameter(Position = 0, Mandatory = true)] 91 | public string ProviderName { get; set; } 92 | 93 | protected override void EndProcessing() 94 | { 95 | try 96 | { 97 | RemoveDbProviderFactory(ProviderName); 98 | } 99 | catch (Exception ex) 100 | { 101 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 102 | } 103 | } 104 | 105 | public static void RemoveDbProviderFactory(string invariant) 106 | { 107 | using (DataSet dataSet = ConfigurationManager.GetSection("system.data") as DataSet) 108 | { 109 | if (dataSet == null) 110 | { 111 | // .NET Core 112 | DbProviderFactories.UnregisterFactory(invariant); 113 | return; 114 | } 115 | 116 | var rows = dataSet.Tables[0].Rows; 117 | 118 | foreach (DataRow r in rows) 119 | { 120 | if (r["InvariantName"].ToString() == invariant) 121 | { 122 | rows.Remove(r); 123 | return; 124 | } 125 | } 126 | } 127 | 128 | throw new RuntimeException("Invariant name not found"); 129 | } 130 | 131 | public static void RemoveAllDbProviderFactories() 132 | { 133 | using (DataSet dataSet = ConfigurationManager.GetSection("system.data") as DataSet) 134 | { 135 | if (dataSet == null) 136 | { 137 | // .NET Core 138 | foreach (var n in DbProviderFactories.GetProviderInvariantNames()) 139 | DbProviderFactories.UnregisterFactory(n); 140 | return; 141 | } 142 | 143 | var rows = dataSet.Tables[0].Rows; 144 | 145 | while (rows.Count > 0) 146 | rows.RemoveAt(rows.Count - 1); 147 | } 148 | } 149 | } 150 | 151 | /// 152 | /// Gets database provider factories defined in the ConfigurationManager. 153 | /// The Get-DbProviderFactory cmdlet gets database provider factories defined in the ConfigurationManager. 154 | /// If the -ProviderName parameter is not specified, it returns all database provider factories. 155 | /// 156 | [Cmdlet("Get", "DbProviderFactory")] 157 | [OutputType(typeof(DataTable))] 158 | public class GetDbProviderFactory : PSCmdlet 159 | { 160 | /// 161 | /// A database provider name. 162 | /// 163 | [Parameter(Position = 0, Mandatory = false)] 164 | public string ProviderName { get; set; } 165 | 166 | protected override void EndProcessing() 167 | { 168 | if (ProviderName != null && ProviderName != "") 169 | { 170 | WriteObject(DbProviderFactories.GetFactory(ProviderName)); 171 | return; 172 | } 173 | 174 | WriteObject(DbProviderFactories.GetFactoryClasses()); 175 | } 176 | } 177 | } -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/CopyDataRow.cs: -------------------------------------------------------------------------------- 1 | using Horker.Data.Classes; 2 | using System; 3 | using System.Collections; 4 | using System.Collections.Generic; 5 | using System.Data.Common; 6 | using System.Linq; 7 | using System.Management.Automation; 8 | using System.Text; 9 | using System.Threading.Tasks; 10 | 11 | #pragma warning disable CS1591 12 | 13 | namespace Horker.Data.Cmdlets 14 | { 15 | /// 16 | /// Copy data from a database to another. 17 | /// The Copy-DataRow cmdlet obtains a dataset from a database specified by the -SourceConnection parameter by executing the -SourceSql statement and inserts them to a table of another database spceified bu the -TargetConnection parameter. 18 | /// When you specify a target table name by the -TargetTable parameter, the cmdlet assumes the specified table contains the same set of columns as the source dataset and inserts them into the corresponding columns. 19 | /// When you specify a SQL statement for copying by the -TargetSql parameter, the cmdlet executes it for each data row of the source dataset. The SQL statement should contain named parameters corresponding to the columns of the source dataset. 20 | /// You can specify either one of the -TargetTable or -TargetSql parameters. 21 | /// 22 | [Cmdlet("Copy", "DataRow")] 23 | [OutputType(typeof(void))] 24 | public class CopyDataRow : PSCmdlet 25 | { 26 | /// 27 | /// A DbConnection object, a connection string name or a database file name (SQLite or Access) of the source database. 28 | /// 29 | [Parameter(Position = 0, Mandatory = true)] 30 | public ConnectionSpecifier SourceConnection { get; set; } 31 | 32 | /// 33 | /// An SQL statement to obtain data from the source database. 34 | /// 35 | [Parameter(Position = 1, Mandatory = true)] 36 | public string SourceSql { get; set; } 37 | 38 | /// 39 | /// A DbConnection object, a connection string name or a database file name (SQLite or Access) of the target database. 40 | /// 41 | [Parameter(Position = 2, Mandatory = true)] 42 | public ConnectionSpecifier TargetConnection { get; set; } 43 | 44 | /// 45 | /// A name of the table into which data will be inserted. 46 | /// 47 | [Parameter(Position = 3, Mandatory = false)] 48 | public string TargetTable { get; set; } 49 | 50 | /// 51 | /// Query parameters applied to the -SourceSql statement. 52 | /// 53 | [Parameter(Position = 4, Mandatory = false)] 54 | public object SourceParameters { get; set; } 55 | 56 | /// 57 | /// An SQL statement to be used for copying the data. It is usually an INSERT or UPDATE statement with the corresponding named parameters to the columns of the source dataset. 58 | /// 59 | [Parameter(Position = 5, Mandatory = false)] 60 | public string TargetSql { get; set; } 61 | 62 | /// 63 | /// A timeout in seconds. 64 | /// 65 | [Parameter(Position = 6, Mandatory = false)] 66 | public int Timeout { get; set; } 67 | 68 | protected override void BeginProcessing() 69 | { 70 | DbTransaction transaction = null; 71 | try 72 | { 73 | if ((TargetTable == null && TargetSql == null) || (TargetTable != null && TargetSql != null)) 74 | throw new ArgumentException("Specify either one of TargetTable or TargetSql"); 75 | 76 | bool timeoutGiven = MyInvocation.BoundParameters.ContainsKey("Timeout"); 77 | 78 | var connection = TargetConnection.Connection; 79 | 80 | transaction = connection.BeginTransaction(); 81 | 82 | using (var selectCmd = SourceConnection.Connection.CreateCommand()) 83 | { 84 | selectCmd.CommandText = SourceSql; 85 | 86 | if (timeoutGiven) 87 | selectCmd.CommandTimeout = Timeout; 88 | 89 | Helpers.SetParameters(selectCmd, SourceParameters); 90 | 91 | using (var reader = selectCmd.ExecuteReader()) 92 | { 93 | string[] paramNames = null; 94 | 95 | while (reader.Read()) 96 | { 97 | if (paramNames == null) 98 | { 99 | paramNames = new string[reader.FieldCount]; 100 | for (var i = 0; i < reader.FieldCount; ++i) 101 | paramNames[i] = reader.GetName(i); 102 | } 103 | 104 | using (var insertCmd = TargetConnection.Connection.CreateCommand()) 105 | { 106 | insertCmd.Transaction = transaction; 107 | 108 | if (TargetSql == null) 109 | { 110 | var factory = Helpers.GetDbProviderFactory(connection); 111 | using (var builder = factory.CreateCommandBuilder()) 112 | { 113 | var columns = string.Join(", ", paramNames.Select(p => builder.QuoteIdentifier(p))); 114 | var paras = "@" + string.Join(", @", paramNames); 115 | TargetSql = $"insert into {TargetTable} ({columns}) values ({paras})"; 116 | } 117 | } 118 | 119 | insertCmd.CommandText = TargetSql; 120 | 121 | for (var i = 0; i < reader.FieldCount; ++i) 122 | { 123 | var param = insertCmd.CreateParameter(); 124 | param.ParameterName = paramNames[i]; 125 | param.Value = reader.GetValue(i); 126 | insertCmd.Parameters.Add(param); 127 | } 128 | 129 | if (timeoutGiven) 130 | insertCmd.CommandTimeout = Timeout; 131 | 132 | insertCmd.ExecuteNonQuery(); 133 | } 134 | } 135 | } 136 | } 137 | 138 | transaction.Commit(); 139 | } 140 | catch (Exception e) 141 | { 142 | if (transaction != null) 143 | transaction.Rollback(); 144 | 145 | WriteError(new ErrorRecord(e, "", ErrorCategory.NotSpecified, null)); 146 | } 147 | finally 148 | { 149 | SourceConnection.Close(); 150 | TargetConnection.Close(); 151 | } 152 | } 153 | } 154 | } 155 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/ConnectionString.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Data.Common; 6 | using System.Management.Automation; 7 | using System.Reflection; 8 | 9 | #pragma warning disable CS1591 10 | 11 | namespace Horker.Data 12 | { 13 | /// 14 | /// Registers a connection string to the ConfigurationManager. 15 | /// The Register-DataConnectionString cmdlet registers a connection string to the ConfigurationManager. 16 | /// 17 | [Cmdlet("Register", "DataConnectionString")] 18 | [OutputType(typeof(void))] 19 | public class RegisterDataConnectionString : PSCmdlet 20 | { 21 | /// 22 | /// A connection string name. 23 | /// 24 | [Parameter(Position = 0, Mandatory = true)] 25 | public string Name { get; set; } 26 | 27 | /// 28 | /// A database provider name. 29 | /// 30 | [Parameter(Position = 1, Mandatory = true)] 31 | public string ProviderName { get; set; } 32 | 33 | /// 34 | /// A connection string. 35 | /// 36 | [Parameter(Position = 2, Mandatory = true)] 37 | public string ConnectionString { get; set; } 38 | 39 | protected override void EndProcessing() 40 | { 41 | try 42 | { 43 | AddConnectionString(Name, ProviderName, ConnectionString); 44 | } 45 | catch (Exception ex) 46 | { 47 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 48 | } 49 | } 50 | 51 | public static void AddConnectionString(string name, string providerName, string connectionString) 52 | { 53 | if (ConfigurationManager.ConnectionStrings[name] != null) 54 | throw new RuntimeException("Connection string name already exists"); 55 | 56 | // Source: 57 | // https://stackoverflow.com/questions/360024/how-do-i-set-a-connection-string-config-programmatically-in-net 58 | 59 | var collection = ConfigurationManager.ConnectionStrings; 60 | 61 | var elementReadOnlyField = 62 | // .NET Framework 63 | typeof(ConfigurationElementCollection).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic) ?? 64 | // .NET Core 65 | typeof(ConfigurationElementCollection).GetField("_readOnly", BindingFlags.Instance | BindingFlags.NonPublic); 66 | elementReadOnlyField.SetValue(collection, false); 67 | 68 | var collectionReadOnlyField = 69 | // .NET Framework 70 | typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic) ?? 71 | // .NET Core 72 | typeof(ConfigurationElementCollection).GetField("_readOnly", BindingFlags.Instance | BindingFlags.NonPublic); 73 | 74 | collectionReadOnlyField.SetValue(collection, false); 75 | 76 | collection.Add(new ConnectionStringSettings(name, connectionString, providerName)); 77 | 78 | collectionReadOnlyField.SetValue(collection, true); 79 | elementReadOnlyField.SetValue(collection, true); 80 | } 81 | } 82 | 83 | /// 84 | /// Removes a connection string definition from the ConfigurationManager. 85 | /// The Unregister-DataConnectionString cmdlet removes a connection string definition from the ConfigurationManager. 86 | /// 87 | [Cmdlet("Unregister", "DataConnectionString")] 88 | [OutputType(typeof(void))] 89 | public class UnregisterDataConnectionString : PSCmdlet 90 | { 91 | /// 92 | /// A connection string name. 93 | /// 94 | [Parameter(Position = 0, Mandatory = true)] 95 | public string Name { get; set; } 96 | 97 | protected override void EndProcessing() 98 | { 99 | try 100 | { 101 | RemoveConnectionString(Name); 102 | } 103 | catch (Exception ex) 104 | { 105 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 106 | } 107 | } 108 | 109 | public static void RemoveConnectionString(string name) 110 | { 111 | if (ConfigurationManager.ConnectionStrings[name] == null) 112 | throw new RuntimeException("Connection string name not found"); 113 | 114 | var collection = ConfigurationManager.ConnectionStrings; 115 | 116 | var elementReadOnlyField = typeof(ConfigurationElement). 117 | GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 118 | elementReadOnlyField.SetValue(collection, false); 119 | 120 | var collectionReadOnlyField = typeof(ConfigurationElementCollection). 121 | GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic); 122 | collectionReadOnlyField.SetValue(collection, false); 123 | 124 | 125 | collection.Remove(name); 126 | 127 | collectionReadOnlyField.SetValue(collection, true); 128 | elementReadOnlyField.SetValue(collection, true); 129 | } 130 | 131 | public static void RemoveAllConnectionStrings() 132 | { 133 | var collection = ConfigurationManager.ConnectionStrings; 134 | 135 | var names = new List(); 136 | foreach (ConnectionStringSettings cs in collection) 137 | names.Add(cs.Name); 138 | 139 | foreach (var name in names) 140 | RemoveConnectionString(name); 141 | } 142 | } 143 | 144 | /// 145 | /// Gets connection strings defined in the ConfigurationManager. 146 | /// The Get-DataConnectionString cmdlet gets connection strings defined in the ConfigurationManager. 147 | /// 148 | [Cmdlet("Get", "DataConnectionString")] 149 | [OutputType(typeof(ConnectionStringSettings))] 150 | public class GetDataConnectionString : PSCmdlet 151 | { 152 | protected override void EndProcessing() 153 | { 154 | WriteObject(ConfigurationManager.ConnectionStrings); 155 | } 156 | } 157 | 158 | /// 159 | /// Creates a connection string based on the given parameters. 160 | /// The New-DataConnectionString cmdlet creates a connection string based on parameters for a specific database provider. 161 | /// When the -TestConnection parameter is specified, the cmdlet tries to connect to a database with the newly created connection string. 162 | /// 163 | [Cmdlet("New", "DataConnectionString")] 164 | [OutputType(typeof(string))] 165 | public class NewDataConnectionString : PSCmdlet 166 | { 167 | /// 168 | /// A database provider name. 169 | /// 170 | [Parameter(Position = 0, Mandatory = true)] 171 | public string ProviderName { get; set; } 172 | 173 | /// 174 | /// A set of parameters that should be included in a connection string. 175 | /// 176 | [Parameter(Position = 1, Mandatory = true)] 177 | public Hashtable Parameters { get; set; } 178 | 179 | /// 180 | /// Makes the cmdlet to test connectivity of a generated connection string. 181 | /// 182 | [Parameter(Position = 2, Mandatory = false)] 183 | public SwitchParameter TestConnection { get; set; } 184 | 185 | protected override void EndProcessing() 186 | { 187 | var factory = DbProviderFactories.GetFactory(ProviderName); 188 | var builder = factory.CreateConnectionStringBuilder(); 189 | 190 | foreach (DictionaryEntry entry in Parameters) 191 | builder.Add(entry.Key.ToString(), entry.Value); 192 | 193 | var cs = builder.ConnectionString; 194 | 195 | if (TestConnection) 196 | { 197 | try 198 | { 199 | var connection = factory.CreateConnection(); 200 | connection.ConnectionString = cs; 201 | connection.Open(); 202 | connection.Close(); 203 | 204 | Host.UI.WriteLine(ConsoleColor.Cyan, Host.UI.RawUI.BackgroundColor, "Connection test succeeded"); 205 | } 206 | catch (DbException ex) 207 | { 208 | WriteError(new ErrorRecord(ex, "", ErrorCategory.NotSpecified, null)); 209 | } 210 | } 211 | 212 | WriteObject(builder.ConnectionString); 213 | } 214 | } 215 | } 216 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/InvokeDataQuery.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Management.Automation; 4 | using System.Data; 5 | using System.Data.Common; 6 | using System.Collections.Generic; 7 | 8 | #pragma warning disable CS1591 9 | 10 | namespace Horker.Data 11 | { 12 | /// 13 | /// Executes a database query. 14 | /// The Invoke-DataQuery cmdlet executes a query to a database. 15 | /// Despite its name, this cmdlet can execute any SQL statement, including INSERT, DELETE and CREATE. When such a statement is executed, no result will return. By specifying the -ShowRecordsAffected parameter, you can get the number of records affected by the statement. You can always obtain the same value by the Get-DataQueryResult cmdlet. 16 | /// By default, the DBNull values in the result data set are replaced with normal null values, and the results are returned as a stream of PSObject values. You can change this behavior by the -PreserveDbNull and -AsDataRows switch parameters. 17 | /// 18 | [Cmdlet("Invoke", "DataQuery")] 19 | [Alias("idq")] 20 | [OutputType(typeof(PSObject), typeof(DataRow), typeof(DataTable))] 21 | public class InvokeDataQuery : PSCmdlet 22 | { 23 | /// 24 | /// A database file name or a connection string name. 25 | /// 26 | [Parameter(Position = 0, ParameterSetName = "FileOrName", Mandatory = true)] 27 | public string FileOrName { get; set; } 28 | 29 | /// 30 | /// A database connection. 31 | /// 32 | [Parameter(Position = 0, ParameterSetName = "Connection", Mandatory = true)] 33 | public DbConnection Connection { get; set; } 34 | 35 | /// 36 | /// A query statement. 37 | /// 38 | [Parameter(Position = 1, Mandatory = true)] 39 | public string Query { get; set; } 40 | 41 | /// 42 | /// Query parameters. 43 | /// 44 | [Parameter(Position = 2, Mandatory = false)] 45 | public object Parameters { get; set; } 46 | 47 | /// 48 | /// A query timeout in seconds. 49 | /// 50 | [Parameter(Position = 3, Mandatory = false)] 51 | public int Timeout { get; set; } 52 | 53 | /// 54 | /// Specifies whether the number of records affected by the query should be returned. 55 | /// 56 | [Parameter(Mandatory = false)] 57 | public SwitchParameter ShowRecordsAffected { get; set; } 58 | 59 | /// 60 | /// Stops replacing the DBNull values in the results with normal null values. 61 | /// 62 | [Parameter(Mandatory = false)] 63 | public SwitchParameter PreserveDbNull { get; set; } 64 | 65 | /// 66 | /// Indicates to return the result data set as System.Data.DataRow instead of PSObject. 67 | /// 68 | [Parameter(Mandatory = false)] 69 | public SwitchParameter AsDataRow { get; set; } 70 | 71 | /// 72 | /// Indicates to return the result data set as System.Data.DataTable instead of an array of PSObjects. 73 | /// 74 | [Parameter(Mandatory = false)] 75 | public SwitchParameter AsDataTable { get; set; } 76 | 77 | protected override void EndProcessing() 78 | { 79 | var opener = new ConnectionSpecifier(FileOrName, Connection, null, null); 80 | var connection = opener.Connection; 81 | bool connectionOpened = opener.ConnectionOpened; 82 | 83 | try { 84 | using (DbCommand cmd = connection.CreateCommand()) 85 | { 86 | cmd.CommandText = Query; 87 | 88 | if (MyInvocation.BoundParameters.ContainsKey("Timeout")) 89 | cmd.CommandTimeout = Timeout; 90 | 91 | if (Parameters != null) 92 | { 93 | if (Parameters is IDictionary dictParam) 94 | { 95 | foreach (DictionaryEntry entry in dictParam) 96 | { 97 | object value; 98 | if (entry.Value is PSObject psobj) 99 | value = psobj.BaseObject; 100 | else 101 | value = entry.Value; 102 | 103 | var param = cmd.CreateParameter(); 104 | param.ParameterName = (string)entry.Key; 105 | param.Value = value; 106 | cmd.Parameters.Add(param); 107 | } 108 | } 109 | else 110 | { 111 | ICollection parameters; 112 | if (Parameters is ICollection col) 113 | parameters = col; 114 | else 115 | parameters = new object[] { Parameters }; 116 | 117 | foreach (var v in parameters) 118 | { 119 | object value; 120 | if (v is PSObject psobj) 121 | value = psobj.BaseObject; 122 | else 123 | value = v; 124 | 125 | var param = cmd.CreateParameter(); 126 | param.Value = value; 127 | cmd.Parameters.Add(param); 128 | } 129 | } 130 | } 131 | 132 | if (AsDataRow || AsDataTable) 133 | { 134 | var factory = DbProviderFactories.GetFactory(connection); 135 | using (var adaptor = factory.CreateDataAdapter()) 136 | using (var dataSet = new DataSet()) 137 | { 138 | adaptor.SelectCommand = cmd; 139 | adaptor.Fill(dataSet); 140 | GetDataQueryResult.RecordsAffected = -1; 141 | 142 | if (AsDataTable) 143 | WriteObject(dataSet.Tables[0]); 144 | else 145 | { 146 | foreach (var row in dataSet.Tables[0].Rows) 147 | WriteObject(row); 148 | } 149 | } 150 | } 151 | else 152 | { 153 | using (var reader = cmd.ExecuteReader()) 154 | { 155 | GetDataQueryResult.RecordsAffected = reader.RecordsAffected; 156 | 157 | var count = reader.FieldCount; 158 | 159 | string[] fieldNames = new string[count]; 160 | var nameHash = new HashSet(); 161 | for (int i = 0; i < count; ++i) 162 | { 163 | var name = reader.GetName(i); 164 | 165 | var suffix = 1; 166 | while (nameHash.Contains(name)) 167 | name = reader.GetName(i) + suffix++; 168 | 169 | fieldNames[i] = name; 170 | nameHash.Add(name); 171 | } 172 | 173 | while (reader.Read()) 174 | { 175 | var obj = new PSObject(); 176 | var exprCount = 1; 177 | for (int i = 0; i < count; ++i) 178 | { 179 | object value = null; 180 | if (PreserveDbNull || !reader.IsDBNull(i)) 181 | value = reader.GetValue(i); 182 | 183 | PSNoteProperty prop; 184 | try 185 | { 186 | prop = new PSNoteProperty(fieldNames[i], value); 187 | } 188 | catch (PSArgumentException) 189 | { 190 | prop = new PSNoteProperty("Expr" + exprCount, value); 191 | ++exprCount; 192 | } 193 | obj.Properties.Add(prop); 194 | } 195 | WriteObject(obj); 196 | } 197 | } 198 | } 199 | 200 | if (ShowRecordsAffected) 201 | WriteObject(GetDataQueryResult.RecordsAffected); 202 | } 203 | } 204 | catch (Exception e) { 205 | WriteError(new ErrorRecord(e, "", ErrorCategory.NotSpecified, null)); 206 | } 207 | finally { 208 | if (connectionOpened) { 209 | connection.Close(); 210 | connection.Dispose(); 211 | } 212 | } 213 | } 214 | } 215 | 216 | /// 217 | /// Gets a result of the last query statement. 218 | /// Gets the number of records affected by the last statement by the Invoke-DataQuery cmdlet. If the previous statement is SELECT, the cmdlet will return -1. 219 | /// 220 | [Cmdlet("Get", "DataQueryResult")] 221 | [OutputType(typeof(int))] 222 | public class GetDataQueryResult : PSCmdlet 223 | { 224 | static public int RecordsAffected { get; set; } 225 | 226 | protected override void EndProcessing() 227 | { 228 | WriteObject(RecordsAffected); 229 | } 230 | } 231 | 232 | 233 | 234 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Horker DataQuery 2 | 3 | Horker DataQuery is a database query utility based on ADO.NET. 4 | 5 | The main features are: 6 | - Written in C#, so that it works fast for large data 7 | - Supports every database product that provides the ADO.NET driver, including SQL Server, Oracle, MySQL, PostgreSQL, SQLite, Access, OLEDB, and ODBC 8 | - Returns query results as PowerShell objects, and exports PowerShell objects into database tables 9 | - Reads `app.config` or `web.config` to define database providers and connection strings 10 | - Gets information from the database schema 11 | - Provides the built-in SQLite driver 12 | 13 | ## Installation 14 | 15 | Horker DataQuery is available in [PowerShell Gallery](https://www.powershellgallery.com/packages/HorkerDataQuery) 16 | 17 | ```PowerShell 18 | Install-Module HorkerDataQuery 19 | ``` 20 | 21 | ## Quick Walkthrough 22 | 23 | ### Getting Started with SQLite 24 | 25 | The module is shipped with the built-in SQLite provider so that you can use SQLite databases out of the box. 26 | 27 | If you have no SQLite database files, create a new one: 28 | 29 | ```PowerShell 30 | PS> New-Item test.db 31 | ``` 32 | 33 | Then you can access it by the `Invoke-DataQuery` cmdlet (or its alias `idq`). 34 | 35 | ```PowerShell 36 | PS> idq test.db "create table Test (a, b, c)" 37 | PS> idq test.db "insert into Test (a, b, c) values (10, 20, 30)" 38 | PS> idq test.db "select * from Test" 39 | 40 | a b c 41 | - - - 42 | 10 20 30 43 | 44 | PS> 45 | ``` 46 | 47 | ### Using Other Databases 48 | 49 | To access different databases, you should define a connection string. 50 | 51 | To do so, you can use the `Register-DataConnectionString` cmdlet. For example: 52 | 53 | ```PowerShell 54 | PS> Register-DataConnectionString ` 55 | -Name localsql ` 56 | -ProviderName System.Data.SqlClient ` 57 | -ConnectionString "Data Source=localhost;Initial Catalog=AdventureWorks2014;Integrated Security=True" 58 | ``` 59 | 60 | The `Name` parameter is a name for this connection string. The `ProviderName` parameter specifies a database provider, such as `System.Data.SqlClient` for SQL Server, `System.Data.OracleClient` for Oracle, and `MySql.Data.MySqlClient` for MySQL. You can find a provider name by the `Get-DbProviderFactory` cmdlet; The `InvariantName` property is what you want. The `ConnectionString` parameter is a connection string, which differs depending on database providers. See the documentation for your database. 61 | 62 | After the registration, you can give a connection string name, such as `localsql` in the above example, to the first parameter of `Invoke-DataQuery`: 63 | 64 | ```PowerShell 65 | PS> idq localsql "select * from Production.Product" 66 | ``` 67 | 68 | You may want to put the connection string definition of your database in your `profile.ps1`. 69 | 70 | Another way to define a connection string is loading `app.config` or `web.config`. If you are developing a database application, you would have already had such a file. 71 | 72 | To load a configuration file, use the `Register-DataConfiguration` cmdlet. This cmdlet will read the file, find the `` and `` sections, and define connection strings (and database provider factories if the latter section exists) according to its contents. The cmdlet will safely ignore the other sections in the file. 73 | 74 | ```PowerShell 75 | PS> Register-DataConfiguration /app.config 76 | ``` 77 | 78 | ### Exporting Objects to Database Tables 79 | 80 | The `Export-DataTable` cmdlet inserts PowerShell objects into a database table. The properties of the objects are mapped to the database columns with the same names. If there are no corresponding columns in the table, such properties are ignored. 81 | 82 | If the specified table does not exist, the cmdlet will create a new table based on the structure of the given object. See the following example: 83 | 84 | ```PowerShell 85 | PS> dir -File C:\Windows | Export-DataTable test.db WindowsDir 86 | ``` 87 | 88 | If the `test.db` database does not contain the `WindowsDir` table, the above command will work as follows: 89 | 90 | 1. Creates a table with the name `WindowsDir` that has the same columns as the properties of the System.IO.FileInfo object, including `Name`, `FullName`, `Length`, and `LastWriteTime`. 91 | 92 | 1. Inserts data from the pipeline into the newly created table. 93 | 94 | As a result, the `WindowsDir` table will be created and filled with the information of the files in the `C:\Windows` folder. 95 | 96 | Now you can try various queries. For example, let's examine the number of files and the average file size for each file extension: 97 | 98 | ```PowerShell 99 | PS> idq test.db "select Extension, count(*), avg(Length) from WindowsDir group by Extension order by count(*) desc" 100 | 101 | Extension count(*) avg(Length) 102 | --------- -------- ----------- 103 | .exe 13 419171.692307692 104 | .log 13 193799.692307692 105 | .ini 8 346.125 106 | .xml 4 25531 107 | .INI 3 935.333333333333 108 | .LOG 3 379524.666666667 109 | .bin 2 21565.5 110 | .dll 2 72992 111 | .prx 2 169972 112 | .txt 2 234022 113 | .DMP 1 1780035540 114 | .SCR 1 301936 115 | .dat 1 67584 116 | .mif 1 1945 117 | .scr 1 516096 118 | 119 | PS> 120 | ``` 121 | 122 | (The result depends on the environment.) 123 | 124 | In the current version, all columns defined by `Export-DataTable` are of the string type. If you want to specify columns and types, create a table with the `CREATE TABLE` statement before export: 125 | 126 | ```PowerShell 127 | PS> idq test.db "drop table WindowsDir" 128 | PS> idq test.db "create table WindowsDir (Name text, Length int)" 129 | PS> dir C:\Windows -File | Export-DataTable test.db WindowsDir 130 | PS> idq test.db "select * from WindowsDir limit 3" | ft 131 | 132 | Name Length 133 | ---- ------ 134 | ativpsrm.bin 0 135 | bfsvc.exe 71168 136 | BlendSettings.ini 23 137 | 138 | PS> 139 | ``` 140 | 141 | ### In-memory Database 142 | 143 | The connection string `memory` is predefined to access an SQLite in-memory database. 144 | 145 | To use an in-memory database, you need to open a connection with the `New-DataConnection` cmdlet: 146 | 147 | ```PowerShell 148 | PS> $mem = New-DataConnection memory 149 | ``` 150 | 151 | Then you can use this connection instead of database files or connection string names: 152 | 153 | ```PowerShell 154 | PS> idq $mem "create table Test (a, b, c)" 155 | PS> idq $mem "select * from sqlite_master" | ft 156 | 157 | type name tbl_name rootpage sql 158 | ---- ---- -------- -------- --- 159 | table Test Test 2 CREATE TABLE Test (a, b, c) 160 | 161 | PS> 162 | ``` 163 | 164 | Note that the contents of the in-memory database will be lost when the current PowerShell session is terminated, or the connection is closed. 165 | 166 | You can explicitly close a connection with the `Close-DataConnection` cmdlet: 167 | 168 | ```PowerShell 169 | PS> Close-DataConnection $mem 170 | ``` 171 | 172 | ### File-based Databases 173 | 174 | The module gives special treatment to SQLite and Microsoft Access as file-based databases. It means that you specify a file name directly as the first parameter of several cmdlets, including `Invoke-DataQuery` or `New-DataConnection`, instead of a connection string name. 175 | 176 | Note that if you want to use the Microsoft Access provider, Microsoft Access should have been installed on your machine. Furthermore, Microsoft provides the only 32-bit version of the Access provider, so that you should activate the 32-bit version of PowerShell to make the provider effective. Select "Windows PowerShell (x86)" in the Start Menu. 177 | 178 | ### Database schemas 179 | 180 | You can obtain database schema information by using the `Get-DataSchema` cmdlet. If you execute this cmdlet without the `CollectionName` parameter, it shows a list of available kinds of schema information: 181 | 182 | ```PowerShell 183 | PS> Get-DataSchema test.db 184 | 185 | CollectionName NumberOfRestrictions NumberOfIdentifierParts 186 | -------------- -------------------- ----------------------- 187 | MetaDataCollections 0 0 188 | DataSourceInformation 0 0 189 | DataTypes 0 0 190 | ReservedWords 0 0 191 | Catalogs 1 1 192 | Columns 4 4 193 | Indexes 4 3 194 | IndexColumns 5 4 195 | Tables 4 3 196 | Views 3 3 197 | ViewColumns 4 4 198 | ForeignKeys 4 3 199 | Triggers 4 200 | 201 | PS> 202 | ``` 203 | 204 | You can specify a kind of information that you want to know: 205 | 206 | ```PowerShell 207 | PS> Get-DataSchema test.db columns 208 | 209 | TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME COLUMN_GUID COLUMN_PROPID ORDINAL_POSITION COLUMN_HASDEFAULT 210 | ------------- ------------ ---------- ----------- ----------- ------------- ---------------- ----------------- 211 | main sqlite_default_schema Test a 0 False 212 | main sqlite_default_schema Test b 1 False 213 | main sqlite_default_schema Test c 2 False 214 | main sqlite_default_schema WindowsDir Extension 0 False 215 | main sqlite_default_schema WindowsDir Name 1 False 216 | main sqlite_default_schema WindowsDir Length 2 False 217 | 218 | PS> 219 | ``` 220 | 221 | Information that the cmdlet will return varies depending on the database provider. 222 | 223 | ## Cmdlets 224 | 225 | The module provides the following cmdlets. Help topics are available for all cmdlets; Try `help` for detailed information. 226 | 227 | - Data query 228 | - `Invoke-DataQuery`: Executes a database query. 229 | - `Get-DataQueryResult`: Gets a result of the last query statement. 230 | 231 | - Export 232 | - `Export-DataTable`: Inserts objects into a database table. 233 | 234 | - Database connection 235 | - `New-DataConnection`: Opens a database connection. 236 | - `Close-DataConnection`: Closes a database connection. 237 | - `Get-DataConnectionHistory`: Gets open database connections in the current session. 238 | 239 | - Connection string 240 | - `New-DataConnectionString`: Creates a connection string based on the given parameters. 241 | - `Get-DataConnectionString`: Gets connection strings defined in the ConfigurationManager. 242 | - `Register-DataConnectionString`: Registers a connection string to the ConfigurationManager. 243 | - `Unregister-DataConnectionString`: Removes a connection string definition from the ConfigurationManager. 244 | 245 | - Database provider factory 246 | - `Get-DbProviderFactory`: Gets database provider factories defined in the ConfigurationManager. 247 | - `Register-DbProviderFactory`: Registers a database provider factory to the ConfigurationManager. 248 | - `Unregister-DbProviderFactory`: Removes a database provider factory from the ConfigurationManager. 249 | 250 | - Configuration Manager 251 | - `Register-DataConfiguration`: Registers connection strings and database provider factories. 252 | 253 | - Database Schema 254 | - `Get-DataSchema`: Gets database schema information. 255 | 256 | ## License 257 | 258 | Licensed under the MIT License. 259 | -------------------------------------------------------------------------------- /source/Horker.Data/Horker.Data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Horker.Data 5 | 6 | 7 | 8 | 9 | Registers connection strings and database provider factories. 10 | The Register-DataConfiguration cmdlet reads a configuration file (app.config or web.config in most cases), finds the /configuration/connectionStrings and /configuration/system.data/DbProviderFactories sections and, according to their contents, registers connection strings and database provider factories to the ConfigurationManager. 11 | 12 | 13 | 14 | 15 | A configuration file name. 16 | 17 | 18 | 19 | 20 | Opens a database connection. 21 | The New-DataConnection cmdlet opens a database connection. 22 | 23 | 24 | 25 | 26 | A database file name or a connection string name. 27 | 28 | 29 | 30 | 31 | A database provider name. 32 | 33 | 34 | 35 | 36 | A connection string. 37 | 38 | 39 | 40 | 41 | Closes a database connection. 42 | The Close-DataConnection cmdlet closes a database connection. 43 | 44 | 45 | 46 | 47 | A database connection. 48 | 49 | 50 | 51 | 52 | Gets open database connections in the current session. 53 | The Get-DataConnectionHistory cmdlet gets open database connections in the current session that you have opened explicitly by the New-DataConnection cmdlet, or implicitly by the other cmdlets you invoked. 54 | This cmdlet is useful when you need to investigate untracked open connections causing a trouble (acquiring a file lock, for example). 55 | 56 | 57 | 58 | 59 | Registers a connection string to the ConfigurationManager. 60 | The Register-DataConnectionString cmdlet registers a connection string to the ConfigurationManager. 61 | 62 | 63 | 64 | 65 | A connection string name. 66 | 67 | 68 | 69 | 70 | A database provider name. 71 | 72 | 73 | 74 | 75 | A connection string. 76 | 77 | 78 | 79 | 80 | Removes a connection string definition from the ConfigurationManager. 81 | The Unregister-DataConnectionString cmdlet removes a connection string definition from the ConfigurationManager. 82 | 83 | 84 | 85 | 86 | A connection string name. 87 | 88 | 89 | 90 | 91 | Gets connection strings defined in the ConfigurationManager. 92 | The Get-DataConnectionString cmdlet gets connection strings defined in the ConfigurationManager. 93 | 94 | 95 | 96 | 97 | Creates a connection string based on the given parameters. 98 | The New-DataConnectionString cmdlet creates a connection string based on parameters for a specific database provider. 99 | When the -TestConnection parameter is specified, the cmdlet tries to connect to a database with the newly created connection string. 100 | 101 | 102 | 103 | 104 | A database provider name. 105 | 106 | 107 | 108 | 109 | A set of parameters that should be included in a connection string. 110 | 111 | 112 | 113 | 114 | Makes the cmdlet to test connectivity of a generated connection string. 115 | 116 | 117 | 118 | 119 | Copy data from a database to another. 120 | The Copy-DataRow cmdlet obtains a dataset from a database specified by the -SourceConnection parameter by executing the -SourceSql statement and inserts them to a table of another database spceified bu the -TargetConnection parameter. 121 | When you specify a target table name by the -TargetTable parameter, the cmdlet assumes the specified table contains the same set of columns as the source dataset and inserts them into the corresponding columns. 122 | When you specify a SQL statement for copying by the -TargetSql parameter, the cmdlet executes it for each data row of the source dataset. The SQL statement should contain named parameters corresponding to the columns of the source dataset. 123 | You can specify either one of the -TargetTable or -TargetSql parameters. 124 | 125 | 126 | 127 | 128 | A DbConnection object, a connection string name or a database file name (SQLite or Access) of the source database. 129 | 130 | 131 | 132 | 133 | An SQL statement to obtain data from the source database. 134 | 135 | 136 | 137 | 138 | A DbConnection object, a connection string name or a database file name (SQLite or Access) of the target database. 139 | 140 | 141 | 142 | 143 | A name of the table into which data will be inserted. 144 | 145 | 146 | 147 | 148 | Query parameters applied to the -SourceSql statement. 149 | 150 | 151 | 152 | 153 | An SQL statement to be used for copying the data. It is usually an INSERT or UPDATE statement with the corresponding named parameters to the columns of the source dataset. 154 | 155 | 156 | 157 | 158 | A timeout in seconds. 159 | 160 | 161 | 162 | 163 | Registers a database provider factory to the ConfigurationManager. 164 | The Register-DbProviderFactory cmdlet registers a database provider factory to the ConfigurationManager. 165 | 166 | 167 | 168 | 169 | A database provider name. 170 | 171 | 172 | 173 | 174 | An invariant name. 175 | 176 | 177 | 178 | 179 | A human readable description. 180 | 181 | 182 | 183 | 184 | Factory classes specification. 185 | 186 | 187 | 188 | 189 | Removes a database provider factory from the ConfigurationManager. 190 | The Unregister-DbProviderFactory cmdlet removes a database provider factory from the ConfigurationManager. 191 | 192 | 193 | 194 | 195 | A database provider name. 196 | 197 | 198 | 199 | 200 | Gets database provider factories defined in the ConfigurationManager. 201 | The Get-DbProviderFactory cmdlet gets database provider factories defined in the ConfigurationManager. 202 | If the -ProviderName parameter is not specified, it returns all database provider factories. 203 | 204 | 205 | 206 | 207 | A database provider name. 208 | 209 | 210 | 211 | 212 | Inserts objects into a database table. 213 | The Export-DataTable cmdlet inserts objects from the pipeline into a database table specified by the -TableName parameter. 214 | The properties of the objects are mapped to the database columns with the same names. If there are no corresponding columns in the table, such properties are ignored. 215 | If the specified table does not exist, the cmdlet will create a new table based on the structure of the given object. In the current version, all columns are defined as a string type. (This does not matter for SQLite because it allows to apply arithmetic operations to string columns.) If you need a table with exact types, create a table manually by the Invoke-DataQuery cmdlet beforehand. 216 | 217 | 218 | 219 | 220 | Objects to be inserted into a database table. 221 | 222 | 223 | 224 | 225 | A database file name or a connection string name. 226 | 227 | 228 | 229 | 230 | A database connection. 231 | 232 | 233 | 234 | 235 | A table name into which objects will be inserted. The value is embeded without being quoted into SQL statements that the cmdlet generates internally. 236 | 237 | 238 | 239 | 240 | Additional column names. 241 | 242 | 243 | 244 | 245 | A type of columns of a newly created table. By default, it is one of 'varchar' (general databases), 'nvarchar' (SQL Server), 'varchar2' (Oracle), or an empty string (SQLite). 246 | 247 | 248 | 249 | 250 | Executes a database query. 251 | The Invoke-DataQuery cmdlet executes a query to a database. 252 | Despite its name, this cmdlet can execute any SQL statement, including INSERT, DELETE and CREATE. When such a statement is executed, no result will return. By specifying the -ShowRecordsAffected parameter, you can get the number of records affected by the statement. You can always obtain the same value by the Get-DataQueryResult cmdlet. 253 | By default, the DBNull values in the result data set are replaced with normal null values, and the results are returned as a stream of PSObject values. You can change this behavior by the -PreserveDbNull and -AsDataRows switch parameters. 254 | 255 | 256 | 257 | 258 | A database file name or a connection string name. 259 | 260 | 261 | 262 | 263 | A database connection. 264 | 265 | 266 | 267 | 268 | A query statement. 269 | 270 | 271 | 272 | 273 | Query parameters. 274 | 275 | 276 | 277 | 278 | A query timeout in seconds. 279 | 280 | 281 | 282 | 283 | Specifies whether the number of records affected by the query should be returned. 284 | 285 | 286 | 287 | 288 | Stops replacing the DBNull values in the results with normal null values. 289 | 290 | 291 | 292 | 293 | Indicates to return the result data set as System.Data.DataRow instead of PSObject. 294 | 295 | 296 | 297 | 298 | Indicates to return the result data set as System.Data.DataTable instead of an array of PSObjects. 299 | 300 | 301 | 302 | 303 | Gets a result of the last query statement. 304 | Gets the number of records affected by the last statement by the Invoke-DataQuery cmdlet. If the previous statement is SELECT, the cmdlet will return -1. 305 | 306 | 307 | 308 | 309 | Gets database schema information. 310 | The Get-DataSchema cmdlet gets database schema information that the database engine provides. If a schema collection name (-CollectionName) is not specified, it returns the information of all available schemas. The provided information varies among database products. 311 | 312 | 313 | 314 | 315 | A database file name or a connection string name. 316 | 317 | 318 | 319 | 320 | A database connection. 321 | 322 | 323 | 324 | 325 | A schama collection name. 326 | 327 | 328 | 329 | 330 | -------------------------------------------------------------------------------- /source/Horker.Data/Cmdlets/ExportDataTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Data; 4 | using System.Data.Common; 5 | using System.Management.Automation; 6 | using System.Text; 7 | 8 | #pragma warning disable CS1591 9 | 10 | namespace Horker.Data 11 | { 12 | /// 13 | /// Inserts objects into a database table. 14 | /// The Export-DataTable cmdlet inserts objects from the pipeline into a database table specified by the -TableName parameter. 15 | /// The properties of the objects are mapped to the database columns with the same names. If there are no corresponding columns in the table, such properties are ignored. 16 | /// If the specified table does not exist, the cmdlet will create a new table based on the structure of the given object. In the current version, all columns are defined as a string type. (This does not matter for SQLite because it allows to apply arithmetic operations to string columns.) If you need a table with exact types, create a table manually by the Invoke-DataQuery cmdlet beforehand. 17 | /// 18 | [Cmdlet("Export", "DataTable")] 19 | [OutputType(typeof(void))] 20 | public class ExportDataTable : PSCmdlet 21 | { 22 | /// 23 | /// Objects to be inserted into a database table. 24 | /// 25 | [Parameter(ValueFromPipeline = true)] 26 | public object InputObject { get; set; } 27 | 28 | /// 29 | /// A database file name or a connection string name. 30 | /// 31 | [Parameter(Position = 0, ParameterSetName = "FileOrName", Mandatory = true)] 32 | public string FileOrName { get; set; } 33 | 34 | /// 35 | /// A database connection. 36 | /// 37 | [Parameter(Position = 0, ParameterSetName = "Connection", Mandatory = true)] 38 | public DbConnection Connection { get; set; } 39 | 40 | /// 41 | /// A table name into which objects will be inserted. The value is embeded without being quoted into SQL statements that the cmdlet generates internally. 42 | /// 43 | [Parameter(Position = 1, Mandatory = true)] 44 | public string TableName { get; set; } 45 | 46 | /// 47 | /// Additional column names. 48 | /// 49 | [Parameter(Position = 2, Mandatory = false)] 50 | public string[] AdditionalColumns { get; set; } 51 | 52 | /// 53 | /// A type of columns of a newly created table. By default, it is one of 'varchar' (general databases), 'nvarchar' (SQL Server), 'varchar2' (Oracle), or an empty string (SQLite). 54 | /// 55 | [Parameter(Position = 3, Mandatory = false)] 56 | public string TypeName { get; set; } 57 | 58 | private DbConnection _connection; 59 | private bool _connectionOpened; 60 | private DbProviderFactory _factory; 61 | private DbCommandBuilder _builder; 62 | 63 | private string _qualifiedTableName; 64 | 65 | private HashSet _fieldSet; 66 | private string _insertStmt; 67 | 68 | private bool _useNamedParameters; 69 | 70 | private DbTransaction _transaction; 71 | 72 | private void DisposeResources() 73 | { 74 | if (_connectionOpened) 75 | { 76 | if (_connection.State == ConnectionState.Open) 77 | _connection.Close(); 78 | 79 | try 80 | { 81 | _connection.Dispose(); 82 | } 83 | catch (ObjectDisposedException) {} 84 | } 85 | 86 | if (_builder != null) 87 | { 88 | try 89 | { 90 | _builder.Dispose(); 91 | } 92 | catch (ObjectDisposedException) {} 93 | } 94 | 95 | if (_transaction != null) 96 | { 97 | try 98 | { 99 | _transaction.Dispose(); 100 | } 101 | catch (ObjectDisposedException) {} 102 | } 103 | } 104 | 105 | protected override void BeginProcessing() 106 | { 107 | var opener = new ConnectionSpecifier(FileOrName, Connection, null, null); 108 | _connection = opener.Connection; 109 | _connectionOpened = opener.ConnectionOpened; 110 | 111 | try 112 | { 113 | if (_connection == null) 114 | { 115 | WriteError(new ErrorRecord(new RuntimeException("Can't open a connection"), "", ErrorCategory.NotSpecified, null)); 116 | throw new PipelineStoppedException(); 117 | } 118 | 119 | // ODBC and OLEDB Access connections fail to obtain the corresponding factories. 120 | if (_connection is System.Data.Odbc.OdbcConnection) 121 | { 122 | _factory = DbProviderFactories.GetFactory("System.Data.Odbc"); 123 | } 124 | else if (_connection is System.Data.OleDb.OleDbConnection) 125 | { 126 | _factory = DbProviderFactories.GetFactory("System.Data.OleDb"); 127 | } 128 | else 129 | { 130 | _factory = DbProviderFactories.GetFactory(_connection); 131 | } 132 | 133 | if (_factory == null) 134 | { 135 | WriteError(new ErrorRecord(new RuntimeException("Failed to obtain a DbProviderFactory object"), "", ErrorCategory.NotSpecified, null)); 136 | throw new PipelineStoppedException(); 137 | } 138 | 139 | _builder = _factory.CreateCommandBuilder(); 140 | 141 | // Supply a command builder with an adaptor object because some providers' builders 142 | // (including those of ODBC and OLEDB Access) require an active connection to make QuoteIndentifier() work. 143 | using (var adaptor = _factory.CreateDataAdapter()) 144 | using (var cmd = _connection.CreateCommand()) 145 | { 146 | cmd.CommandText = "select 1"; 147 | adaptor.SelectCommand = cmd; 148 | _builder.DataAdapter = adaptor; 149 | } 150 | 151 | _useNamedParameters = false; 152 | } 153 | catch (Exception e) 154 | { 155 | DisposeResources(); 156 | 157 | WriteError(new ErrorRecord(e, "", ErrorCategory.NotSpecified, null)); 158 | throw new PipelineStoppedException(); 159 | } 160 | } 161 | 162 | protected override void ProcessRecord() 163 | { 164 | try 165 | { 166 | if (InputObject == null) 167 | return; 168 | 169 | if (_fieldSet == null) 170 | { 171 | _qualifiedTableName = GetQualifiedTableName(); 172 | 173 | CreateTable(); 174 | 175 | _useNamedParameters = TestNamedParameterSupport(); 176 | 177 | _insertStmt = "insert into " + _qualifiedTableName + " ("; 178 | 179 | _transaction = _connection.BeginTransaction(); 180 | } 181 | 182 | using (var cmd = _connection.CreateCommand()) 183 | { 184 | cmd.CommandText = _insertStmt; 185 | cmd.Transaction = _transaction; 186 | 187 | var buffer = new StringBuilder(_insertStmt); 188 | var placeholders = new StringBuilder(); 189 | 190 | string pa = "?"; 191 | var count = 0; 192 | if (InputObject is PSObject) 193 | { 194 | var obj = (PSObject)InputObject; 195 | foreach (var p in obj.Properties) 196 | { 197 | if (!p.IsGettable || !p.IsInstance) 198 | continue; 199 | 200 | if (_fieldSet.Contains(p.Name)) 201 | { 202 | if (count > 0) 203 | { 204 | buffer.Append(','); 205 | placeholders.Append(','); 206 | } 207 | ++count; 208 | 209 | var qualified = _builder.QuoteIdentifier(p.Name); 210 | buffer.Append(qualified); 211 | 212 | var param = cmd.CreateParameter(); 213 | if (_useNamedParameters) 214 | { 215 | pa = "@" + count.ToString(); 216 | param.ParameterName = pa; 217 | } 218 | 219 | var value = p.Value; 220 | if (value != null) 221 | { 222 | if (value is PSObject) 223 | value = (value as PSObject).BaseObject; 224 | param.Value = value; 225 | } 226 | 227 | cmd.Parameters.Add(param); 228 | 229 | placeholders.Append(pa); 230 | } 231 | } 232 | } 233 | else 234 | { 235 | foreach (var p in InputObject.GetType().GetProperties()) 236 | { 237 | if (!p.CanRead) 238 | continue; 239 | 240 | if (_fieldSet.Contains(p.Name)) 241 | { 242 | if (count > 0) 243 | { 244 | buffer.Append(','); 245 | placeholders.Append(','); 246 | } 247 | ++count; 248 | 249 | var qualified = _builder.QuoteIdentifier(p.Name); 250 | buffer.Append(qualified); 251 | 252 | var param = cmd.CreateParameter(); 253 | if (_useNamedParameters) 254 | { 255 | pa = "@" + count.ToString(); 256 | param.ParameterName = pa; 257 | } 258 | 259 | var value = p.GetValue(InputObject); 260 | if (value != null) 261 | { 262 | if (value is PSObject) 263 | value = (value as PSObject).BaseObject; 264 | param.Value = value; 265 | } 266 | 267 | cmd.Parameters.Add(param); 268 | 269 | placeholders.Append(pa); 270 | } 271 | } 272 | } 273 | 274 | // If there are no columns to be inserted, just skip. 275 | if (placeholders.Length == 0) 276 | return; 277 | 278 | buffer.Append(") values ("); 279 | buffer.Append(placeholders); 280 | buffer.Append(')'); 281 | var stmt = buffer.ToString(); 282 | WriteVerbose(stmt); 283 | 284 | cmd.CommandText = stmt; 285 | 286 | var rowsAffected = cmd.ExecuteNonQuery(); 287 | if (rowsAffected != 1) 288 | throw new RuntimeException("Insertion failed"); 289 | } 290 | } 291 | catch (Exception e) 292 | { 293 | if (_transaction != null) 294 | _transaction.Rollback(); 295 | 296 | DisposeResources(); 297 | 298 | WriteError(new ErrorRecord(e, "", ErrorCategory.NotSpecified, null)); 299 | throw new PipelineStoppedException(); 300 | } 301 | } 302 | 303 | protected override void EndProcessing() 304 | { 305 | try 306 | { 307 | if (_transaction != null) 308 | _transaction.Commit(); 309 | } 310 | catch (Exception e) 311 | { 312 | WriteError(new ErrorRecord(e, "", ErrorCategory.NotSpecified, null)); 313 | throw new PipelineStoppedException(); 314 | } 315 | finally 316 | { 317 | DisposeResources(); 318 | } 319 | } 320 | 321 | protected override void StopProcessing() 322 | { 323 | DisposeResources(); 324 | } 325 | 326 | private string GetQualifiedTableName() 327 | { 328 | // Do nothing. Because TableName is a paramater, users can quote it appropriately. 329 | return TableName; 330 | } 331 | 332 | private void CreateTable() 333 | { 334 | string stmt; 335 | 336 | // Try to select from a table given by TableName in order to find whether such a table exists. 337 | 338 | bool tableExists = false; 339 | try 340 | { 341 | stmt = "select * from " + _qualifiedTableName; 342 | WriteVerbose(stmt); 343 | 344 | using (var cmd = _connection.CreateCommand()) 345 | using (var adaptor = _factory.CreateDataAdapter()) 346 | { 347 | cmd.CommandText = stmt; 348 | adaptor.SelectCommand = cmd; 349 | 350 | using (var dataSet = new DataSet()) 351 | { 352 | adaptor.FillSchema(dataSet, SchemaType.Mapped); 353 | 354 | var table = dataSet.Tables[0]; 355 | 356 | _fieldSet = new HashSet(); 357 | foreach (DataColumn c in table.Columns) 358 | _fieldSet.Add(c.ColumnName); 359 | } 360 | 361 | tableExists = true; 362 | } 363 | } 364 | catch (DbException) 365 | { 366 | // Ignore an exception 367 | } 368 | 369 | if (tableExists) 370 | return; 371 | 372 | // Collect field names from the input object 373 | 374 | var fields = new List(); 375 | if (InputObject is PSObject) 376 | { 377 | var obj = (PSObject)InputObject; 378 | foreach (var p in obj.Properties) 379 | fields.Add(p.Name); 380 | } 381 | else 382 | { 383 | foreach (var p in InputObject.GetType().GetProperties()) 384 | { 385 | if (!p.CanRead) 386 | continue; 387 | fields.Add(p.Name); 388 | } 389 | } 390 | 391 | if (AdditionalColumns != null) 392 | { 393 | foreach (var c in AdditionalColumns) 394 | fields.Add(c); 395 | } 396 | 397 | _fieldSet = new HashSet(fields); 398 | 399 | // Create a table 400 | 401 | string stringType = "varchar(4000)"; // ANSI SQL standard 402 | 403 | if (TypeName != null) 404 | { 405 | // User-specified type name 406 | stringType = TypeName; 407 | } 408 | else if (_connection is System.Data.SQLite.SQLiteConnection) 409 | { 410 | // SQLite can omit a type 411 | stringType = ""; 412 | } 413 | else if (_connection is System.Data.SqlClient.SqlConnection) 414 | { 415 | // SQL Server supports nvarchar that represents a UTF-16 string. 416 | // It is safe for any database encoding. 417 | stringType = "nvarchar(4000)"; 418 | } 419 | else if (_connection.GetType().FullName.Contains("Oracle")) 420 | { 421 | // Conventional type name of string for Oracle 422 | stringType = "nvarchar2(4000)"; 423 | } 424 | else 425 | { 426 | long length = 4000; 427 | try 428 | { 429 | using (var schema = _connection.GetSchema("DataTypes")) 430 | { 431 | foreach (DataRow row in schema.Rows) 432 | { 433 | var columnName = (string)row["TypeName"]; 434 | if (columnName == "varchar" || columnName == "VARCHAR" || columnName == "Varchar") 435 | { 436 | long l = (long)row["ColumnSize"]; 437 | length = Math.Min(4000, l); 438 | break; 439 | } 440 | } 441 | } 442 | stringType = String.Format("varchar({0})", length); 443 | } 444 | catch (Exception) 445 | { 446 | // Because schema information varies from provider to provider, 447 | // when an error occurs, just ignore it and apply standard type definition. 448 | } 449 | } 450 | 451 | var templ = new StringBuilder(); 452 | templ.Append("create table "); 453 | templ.Append(_qualifiedTableName); 454 | templ.Append(" (\r\n"); 455 | bool first = true; 456 | foreach (var f in fields) 457 | { 458 | if (!first) 459 | templ.AppendLine(","); 460 | 461 | first = false; 462 | templ.Append(" "); 463 | templ.Append(_builder.QuoteIdentifier(f)); 464 | templ.Append(" {0}"); 465 | } 466 | templ.AppendLine("\r\n)"); 467 | 468 | stmt = String.Format(templ.ToString(), stringType); 469 | WriteVerbose(stmt); 470 | 471 | using (var cmd = _connection.CreateCommand()) 472 | { 473 | cmd.CommandText = stmt; 474 | cmd.ExecuteNonQuery(); 475 | } 476 | } 477 | 478 | private bool TestNamedParameterSupport() 479 | { 480 | using (var cmd = _connection.CreateCommand()) 481 | { 482 | try 483 | { 484 | var stmt = "select 1 + @param"; 485 | cmd.CommandText = stmt; 486 | WriteVerbose(stmt); 487 | 488 | var param = cmd.CreateParameter(); 489 | param.ParameterName = "@param"; 490 | param.Value = 1; 491 | 492 | cmd.Parameters.Add(param); 493 | 494 | using (var reader = cmd.ExecuteReader()) 495 | { 496 | reader.Read(); 497 | reader.GetValue(0); 498 | } 499 | 500 | return true; 501 | } 502 | catch (DbException) 503 | { 504 | return false; 505 | } 506 | } 507 | } 508 | } 509 | } 510 | --------------------------------------------------------------------------------