├── .hgignore ├── Converter ├── AuthorMessageForm.Designer.cs ├── AuthorMessageForm.cs ├── AuthorMessageForm.resx ├── Converter.csproj ├── MainForm.Designer.cs ├── MainForm.cs ├── MainForm.resx ├── Program.cs ├── TableSelectionDialog.Designer.cs ├── TableSelectionDialog.cs ├── TableSelectionDialog.resx ├── ViewFailureDialog.Designer.cs ├── ViewFailureDialog.cs ├── ViewFailureDialog.resx └── app.config ├── DbAccess ├── ColumnSchema.cs ├── DatabaseSchema.cs ├── DbAccess.csproj ├── ForeignKeySchema.cs ├── IndexSchema.cs ├── SqlServerToSQLite.cs ├── TableSchema.cs ├── TriggerBuilder.cs ├── TriggerSchema.cs └── ViewSchema.cs ├── README.md ├── SolutionInfo.cs ├── SqlConverter.sln ├── System.Data.SQLite.dll └── log4net.dll /.hgignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elerch/Convert-SQL-Server-to-SQLite/95436df861744d69630e642f42635f5b1669d108/.hgignore -------------------------------------------------------------------------------- /Converter/AuthorMessageForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Converter 2 | { 3 | partial class AuthorMessageForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AuthorMessageForm)); 32 | this.label1 = new System.Windows.Forms.Label(); 33 | this.label2 = new System.Windows.Forms.Label(); 34 | this.lnkWebsite = new System.Windows.Forms.LinkLabel(); 35 | this.label3 = new System.Windows.Forms.Label(); 36 | this.label4 = new System.Windows.Forms.Label(); 37 | this.btnClose = new System.Windows.Forms.Button(); 38 | this.SuspendLayout(); 39 | // 40 | // label1 41 | // 42 | this.label1.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 43 | this.label1.Location = new System.Drawing.Point(12, 19); 44 | this.label1.Name = "label1"; 45 | this.label1.Size = new System.Drawing.Size(430, 91); 46 | this.label1.TabIndex = 0; 47 | this.label1.Text = resources.GetString("label1.Text"); 48 | // 49 | // label2 50 | // 51 | this.label2.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 52 | this.label2.Location = new System.Drawing.Point(12, 114); 53 | this.label2.Name = "label2"; 54 | this.label2.Size = new System.Drawing.Size(209, 21); 55 | this.label2.TabIndex = 1; 56 | this.label2.Text = "You can see the details here:"; 57 | // 58 | // lnkWebsite 59 | // 60 | this.lnkWebsite.AutoSize = true; 61 | this.lnkWebsite.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold); 62 | this.lnkWebsite.Location = new System.Drawing.Point(227, 114); 63 | this.lnkWebsite.Name = "lnkWebsite"; 64 | this.lnkWebsite.Size = new System.Drawing.Size(215, 16); 65 | this.lnkWebsite.TabIndex = 2; 66 | this.lnkWebsite.TabStop = true; 67 | this.lnkWebsite.Text = "http://www.sqlitecompare.com"; 68 | this.lnkWebsite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkWebsite_LinkClicked); 69 | // 70 | // label3 71 | // 72 | this.label3.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 73 | this.label3.Location = new System.Drawing.Point(12, 151); 74 | this.label3.Name = "label3"; 75 | this.label3.Size = new System.Drawing.Size(143, 21); 76 | this.label3.TabIndex = 3; 77 | this.label3.Text = "Have a great day!"; 78 | // 79 | // label4 80 | // 81 | this.label4.Font = new System.Drawing.Font("Tahoma", 9.75F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); 82 | this.label4.Location = new System.Drawing.Point(12, 181); 83 | this.label4.Name = "label4"; 84 | this.label4.Size = new System.Drawing.Size(143, 21); 85 | this.label4.TabIndex = 4; 86 | this.label4.Text = "Liron Levi"; 87 | // 88 | // btnClose 89 | // 90 | this.btnClose.DialogResult = System.Windows.Forms.DialogResult.Cancel; 91 | this.btnClose.Location = new System.Drawing.Point(367, 182); 92 | this.btnClose.Name = "btnClose"; 93 | this.btnClose.Size = new System.Drawing.Size(75, 23); 94 | this.btnClose.TabIndex = 5; 95 | this.btnClose.Text = "Close"; 96 | this.btnClose.UseVisualStyleBackColor = true; 97 | this.btnClose.Click += new System.EventHandler(this.btnClose_Click); 98 | // 99 | // AuthorMessageForm 100 | // 101 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 102 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 103 | this.CancelButton = this.btnClose; 104 | this.ClientSize = new System.Drawing.Size(454, 217); 105 | this.Controls.Add(this.btnClose); 106 | this.Controls.Add(this.label4); 107 | this.Controls.Add(this.label3); 108 | this.Controls.Add(this.lnkWebsite); 109 | this.Controls.Add(this.label2); 110 | this.Controls.Add(this.label1); 111 | this.MaximizeBox = false; 112 | this.MinimizeBox = false; 113 | this.Name = "AuthorMessageForm"; 114 | this.ShowIcon = false; 115 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 116 | this.Text = "Author Message"; 117 | this.ResumeLayout(false); 118 | this.PerformLayout(); 119 | 120 | } 121 | 122 | #endregion 123 | 124 | private System.Windows.Forms.Label label1; 125 | private System.Windows.Forms.Label label2; 126 | private System.Windows.Forms.LinkLabel lnkWebsite; 127 | private System.Windows.Forms.Label label3; 128 | private System.Windows.Forms.Label label4; 129 | private System.Windows.Forms.Button btnClose; 130 | } 131 | } -------------------------------------------------------------------------------- /Converter/AuthorMessageForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using System.Diagnostics; 9 | 10 | namespace Converter 11 | { 12 | public partial class AuthorMessageForm : Form 13 | { 14 | public AuthorMessageForm() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | private void btnClose_Click(object sender, EventArgs e) 20 | { 21 | this.DialogResult = DialogResult.Cancel; 22 | } 23 | 24 | private void lnkWebsite_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 25 | { 26 | OpenPage("http://sqlitecompare.com"); 27 | } 28 | 29 | public static void OpenPage(string url) 30 | { 31 | Process p = new Process(); 32 | ProcessStartInfo psi = new ProcessStartInfo(url); 33 | p.StartInfo = psi; 34 | psi.UseShellExecute = true; 35 | p.Start(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /Converter/AuthorMessageForm.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | I hope that this small utility has made your life a bit easier. 122 | 123 | If you need a fast and cheap utility for comparing and merging SQLite databases then maybe you'll want to check out another utility that I wrote, called SQLite Compare. 124 | 125 | 126 | -------------------------------------------------------------------------------- /Converter/Converter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.50727 7 | 2.0 8 | {1D389047-977D-4278-8357-AC0AC751B95E} 9 | WinExe 10 | Properties 11 | Converter 12 | SqlLiteConverter 13 | v2.0 14 | 15 | 16 | 2.0 17 | 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | false 32 | true 33 | 34 | 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | x86 43 | AllRules.ruleset 44 | 45 | 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | AllRules.ruleset 53 | x86 54 | 55 | 56 | 57 | False 58 | ..\log4net.dll 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | Properties\SolutionInfo.cs 70 | 71 | 72 | Form 73 | 74 | 75 | AuthorMessageForm.cs 76 | 77 | 78 | Form 79 | 80 | 81 | MainForm.cs 82 | 83 | 84 | 85 | Form 86 | 87 | 88 | TableSelectionDialog.cs 89 | 90 | 91 | Form 92 | 93 | 94 | ViewFailureDialog.cs 95 | 96 | 97 | Designer 98 | AuthorMessageForm.cs 99 | 100 | 101 | Designer 102 | MainForm.cs 103 | 104 | 105 | TableSelectionDialog.cs 106 | Designer 107 | 108 | 109 | Designer 110 | ViewFailureDialog.cs 111 | 112 | 113 | 114 | 115 | 116 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288} 117 | DbAccess 118 | 119 | 120 | 121 | 122 | False 123 | .NET Framework 3.5 SP1 Client Profile 124 | false 125 | 126 | 127 | False 128 | .NET Framework 3.5 SP1 129 | true 130 | 131 | 132 | False 133 | Windows Installer 3.1 134 | true 135 | 136 | 137 | 138 | 145 | 146 | 147 | 148 | 149 | 150 | -------------------------------------------------------------------------------- /Converter/MainForm.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Converter 2 | { 3 | partial class MainForm 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label1 = new System.Windows.Forms.Label(); 32 | this.txtSqlAddress = new System.Windows.Forms.TextBox(); 33 | this.label2 = new System.Windows.Forms.Label(); 34 | this.txtSQLitePath = new System.Windows.Forms.TextBox(); 35 | this.btnBrowseSQLitePath = new System.Windows.Forms.Button(); 36 | this.btnStart = new System.Windows.Forms.Button(); 37 | this.saveFileDialog1 = new System.Windows.Forms.SaveFileDialog(); 38 | this.label3 = new System.Windows.Forms.Label(); 39 | this.cboDatabases = new System.Windows.Forms.ComboBox(); 40 | this.btnSet = new System.Windows.Forms.Button(); 41 | this.pbrProgress = new System.Windows.Forms.ProgressBar(); 42 | this.lblMessage = new System.Windows.Forms.Label(); 43 | this.btnCancel = new System.Windows.Forms.Button(); 44 | this.cbxEncrypt = new System.Windows.Forms.CheckBox(); 45 | this.txtPassword = new System.Windows.Forms.TextBox(); 46 | this.cbxIntegrated = new System.Windows.Forms.CheckBox(); 47 | this.txtUserDB = new System.Windows.Forms.TextBox(); 48 | this.txtPassDB = new System.Windows.Forms.TextBox(); 49 | this.lblUser = new System.Windows.Forms.Label(); 50 | this.lblPassword = new System.Windows.Forms.Label(); 51 | this.cbxTriggers = new System.Windows.Forms.CheckBox(); 52 | this.lnkMessage = new System.Windows.Forms.LinkLabel(); 53 | this.SuspendLayout(); 54 | // 55 | // label1 56 | // 57 | this.label1.AutoSize = true; 58 | this.label1.Location = new System.Drawing.Point(12, 20); 59 | this.label1.Name = "label1"; 60 | this.label1.Size = new System.Drawing.Size(106, 13); 61 | this.label1.TabIndex = 0; 62 | this.label1.Text = "SQL Server Address:"; 63 | // 64 | // txtSqlAddress 65 | // 66 | this.txtSqlAddress.Location = new System.Drawing.Point(154, 17); 67 | this.txtSqlAddress.Name = "txtSqlAddress"; 68 | this.txtSqlAddress.Size = new System.Drawing.Size(313, 20); 69 | this.txtSqlAddress.TabIndex = 1; 70 | this.txtSqlAddress.TextChanged += new System.EventHandler(this.txtSqlAddress_TextChanged); 71 | // 72 | // label2 73 | // 74 | this.label2.AutoSize = true; 75 | this.label2.Location = new System.Drawing.Point(12, 101); 76 | this.label2.Name = "label2"; 77 | this.label2.Size = new System.Drawing.Size(135, 13); 78 | this.label2.TabIndex = 10; 79 | this.label2.Text = "SQLite Database File Path:"; 80 | // 81 | // txtSQLitePath 82 | // 83 | this.txtSQLitePath.Location = new System.Drawing.Point(154, 98); 84 | this.txtSQLitePath.Name = "txtSQLitePath"; 85 | this.txtSQLitePath.Size = new System.Drawing.Size(313, 20); 86 | this.txtSQLitePath.TabIndex = 11; 87 | this.txtSQLitePath.TextChanged += new System.EventHandler(this.txtSQLitePath_TextChanged); 88 | // 89 | // btnBrowseSQLitePath 90 | // 91 | this.btnBrowseSQLitePath.Location = new System.Drawing.Point(472, 97); 92 | this.btnBrowseSQLitePath.Name = "btnBrowseSQLitePath"; 93 | this.btnBrowseSQLitePath.Size = new System.Drawing.Size(75, 23); 94 | this.btnBrowseSQLitePath.TabIndex = 12; 95 | this.btnBrowseSQLitePath.Text = "Browse..."; 96 | this.btnBrowseSQLitePath.UseVisualStyleBackColor = true; 97 | this.btnBrowseSQLitePath.Click += new System.EventHandler(this.btnBrowseSQLitePath_Click); 98 | // 99 | // btnStart 100 | // 101 | this.btnStart.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 102 | this.btnStart.Location = new System.Drawing.Point(171, 216); 103 | this.btnStart.Name = "btnStart"; 104 | this.btnStart.Size = new System.Drawing.Size(198, 23); 105 | this.btnStart.TabIndex = 17; 106 | this.btnStart.Text = "Start The Conversion Process"; 107 | this.btnStart.UseVisualStyleBackColor = true; 108 | this.btnStart.Click += new System.EventHandler(this.btnStart_Click); 109 | // 110 | // saveFileDialog1 111 | // 112 | this.saveFileDialog1.DefaultExt = "db"; 113 | this.saveFileDialog1.Filter = "SQLite Files|*.db|All Files|*.*"; 114 | this.saveFileDialog1.RestoreDirectory = true; 115 | // 116 | // label3 117 | // 118 | this.label3.AutoSize = true; 119 | this.label3.Location = new System.Drawing.Point(12, 46); 120 | this.label3.Name = "label3"; 121 | this.label3.Size = new System.Drawing.Size(58, 13); 122 | this.label3.TabIndex = 3; 123 | this.label3.Text = "Select DB:"; 124 | // 125 | // cboDatabases 126 | // 127 | this.cboDatabases.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 128 | this.cboDatabases.Enabled = false; 129 | this.cboDatabases.FormattingEnabled = true; 130 | this.cboDatabases.Location = new System.Drawing.Point(154, 43); 131 | this.cboDatabases.Name = "cboDatabases"; 132 | this.cboDatabases.Size = new System.Drawing.Size(135, 21); 133 | this.cboDatabases.TabIndex = 4; 134 | this.cboDatabases.SelectedIndexChanged += new System.EventHandler(this.cboDatabases_SelectedIndexChanged); 135 | // 136 | // btnSet 137 | // 138 | this.btnSet.Location = new System.Drawing.Point(472, 16); 139 | this.btnSet.Name = "btnSet"; 140 | this.btnSet.Size = new System.Drawing.Size(75, 23); 141 | this.btnSet.TabIndex = 2; 142 | this.btnSet.Text = "Set"; 143 | this.btnSet.UseVisualStyleBackColor = true; 144 | this.btnSet.Click += new System.EventHandler(this.btnSet_Click); 145 | // 146 | // pbrProgress 147 | // 148 | this.pbrProgress.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 149 | this.pbrProgress.Location = new System.Drawing.Point(12, 195); 150 | this.pbrProgress.Name = "pbrProgress"; 151 | this.pbrProgress.Size = new System.Drawing.Size(529, 18); 152 | this.pbrProgress.TabIndex = 16; 153 | // 154 | // lblMessage 155 | // 156 | this.lblMessage.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 157 | this.lblMessage.Location = new System.Drawing.Point(12, 177); 158 | this.lblMessage.Name = "lblMessage"; 159 | this.lblMessage.Size = new System.Drawing.Size(529, 13); 160 | this.lblMessage.TabIndex = 15; 161 | this.lblMessage.TextAlign = System.Drawing.ContentAlignment.MiddleCenter; 162 | // 163 | // btnCancel 164 | // 165 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 166 | this.btnCancel.Location = new System.Drawing.Point(446, 216); 167 | this.btnCancel.Name = "btnCancel"; 168 | this.btnCancel.Size = new System.Drawing.Size(95, 23); 169 | this.btnCancel.TabIndex = 18; 170 | this.btnCancel.Text = "Cancel"; 171 | this.btnCancel.UseVisualStyleBackColor = true; 172 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); 173 | // 174 | // cbxEncrypt 175 | // 176 | this.cbxEncrypt.AutoSize = true; 177 | this.cbxEncrypt.Location = new System.Drawing.Point(15, 127); 178 | this.cbxEncrypt.Name = "cbxEncrypt"; 179 | this.cbxEncrypt.Size = new System.Drawing.Size(127, 17); 180 | this.cbxEncrypt.TabIndex = 13; 181 | this.cbxEncrypt.Text = "Encryption password:"; 182 | this.cbxEncrypt.UseVisualStyleBackColor = true; 183 | this.cbxEncrypt.CheckedChanged += new System.EventHandler(this.cbxEncrypt_CheckedChanged); 184 | // 185 | // txtPassword 186 | // 187 | this.txtPassword.Location = new System.Drawing.Point(154, 125); 188 | this.txtPassword.Name = "txtPassword"; 189 | this.txtPassword.PasswordChar = '*'; 190 | this.txtPassword.Size = new System.Drawing.Size(121, 20); 191 | this.txtPassword.TabIndex = 14; 192 | this.txtPassword.TextChanged += new System.EventHandler(this.txtPassword_TextChanged); 193 | // 194 | // cbxIntegrated 195 | // 196 | this.cbxIntegrated.Checked = true; 197 | this.cbxIntegrated.CheckState = System.Windows.Forms.CheckState.Checked; 198 | this.cbxIntegrated.Location = new System.Drawing.Point(15, 71); 199 | this.cbxIntegrated.Name = "cbxIntegrated"; 200 | this.cbxIntegrated.Size = new System.Drawing.Size(130, 21); 201 | this.cbxIntegrated.TabIndex = 5; 202 | this.cbxIntegrated.Text = "Integrated security"; 203 | this.cbxIntegrated.UseVisualStyleBackColor = true; 204 | this.cbxIntegrated.CheckedChanged += new System.EventHandler(this.ChkIntegratedCheckedChanged); 205 | // 206 | // txtUserDB 207 | // 208 | this.txtUserDB.Location = new System.Drawing.Point(189, 71); 209 | this.txtUserDB.Name = "txtUserDB"; 210 | this.txtUserDB.Size = new System.Drawing.Size(100, 20); 211 | this.txtUserDB.TabIndex = 7; 212 | this.txtUserDB.Visible = false; 213 | // 214 | // txtPassDB 215 | // 216 | this.txtPassDB.Location = new System.Drawing.Point(354, 71); 217 | this.txtPassDB.Name = "txtPassDB"; 218 | this.txtPassDB.PasswordChar = '*'; 219 | this.txtPassDB.Size = new System.Drawing.Size(113, 20); 220 | this.txtPassDB.TabIndex = 9; 221 | this.txtPassDB.Visible = false; 222 | // 223 | // lblUser 224 | // 225 | this.lblUser.AutoSize = true; 226 | this.lblUser.Location = new System.Drawing.Point(151, 74); 227 | this.lblUser.Name = "lblUser"; 228 | this.lblUser.Size = new System.Drawing.Size(32, 13); 229 | this.lblUser.TabIndex = 6; 230 | this.lblUser.Text = "User:"; 231 | this.lblUser.Visible = false; 232 | // 233 | // lblPassword 234 | // 235 | this.lblPassword.AutoSize = true; 236 | this.lblPassword.Location = new System.Drawing.Point(295, 74); 237 | this.lblPassword.Name = "lblPassword"; 238 | this.lblPassword.Size = new System.Drawing.Size(56, 13); 239 | this.lblPassword.TabIndex = 8; 240 | this.lblPassword.Text = "Password:"; 241 | this.lblPassword.Visible = false; 242 | // 243 | // cbxTriggers 244 | // 245 | this.cbxTriggers.AutoSize = true; 246 | this.cbxTriggers.Location = new System.Drawing.Point(15, 151); 247 | this.cbxTriggers.Name = "cbxTriggers"; 248 | this.cbxTriggers.Size = new System.Drawing.Size(201, 17); 249 | this.cbxTriggers.TabIndex = 19; 250 | this.cbxTriggers.Text = "Create triggers enforcing foreign keys"; 251 | this.cbxTriggers.UseVisualStyleBackColor = true; 252 | // 253 | // lnkMessage 254 | // 255 | this.lnkMessage.AutoSize = true; 256 | this.lnkMessage.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177))); 257 | this.lnkMessage.Location = new System.Drawing.Point(371, 151); 258 | this.lnkMessage.Name = "lnkMessage"; 259 | this.lnkMessage.Size = new System.Drawing.Size(170, 13); 260 | this.lnkMessage.TabIndex = 20; 261 | this.lnkMessage.TabStop = true; 262 | this.lnkMessage.Text = "A message from the author..."; 263 | this.lnkMessage.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.lnkMessage_LinkClicked); 264 | // 265 | // MainForm 266 | // 267 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 268 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 269 | this.ClientSize = new System.Drawing.Size(555, 242); 270 | this.Controls.Add(this.lnkMessage); 271 | this.Controls.Add(this.cbxTriggers); 272 | this.Controls.Add(this.txtPassDB); 273 | this.Controls.Add(this.txtUserDB); 274 | this.Controls.Add(this.cbxIntegrated); 275 | this.Controls.Add(this.txtPassword); 276 | this.Controls.Add(this.cbxEncrypt); 277 | this.Controls.Add(this.btnCancel); 278 | this.Controls.Add(this.lblMessage); 279 | this.Controls.Add(this.pbrProgress); 280 | this.Controls.Add(this.btnSet); 281 | this.Controls.Add(this.cboDatabases); 282 | this.Controls.Add(this.lblPassword); 283 | this.Controls.Add(this.lblUser); 284 | this.Controls.Add(this.label3); 285 | this.Controls.Add(this.btnStart); 286 | this.Controls.Add(this.btnBrowseSQLitePath); 287 | this.Controls.Add(this.txtSQLitePath); 288 | this.Controls.Add(this.label2); 289 | this.Controls.Add(this.txtSqlAddress); 290 | this.Controls.Add(this.label1); 291 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 292 | this.MaximizeBox = false; 293 | this.Name = "MainForm"; 294 | this.Text = "SQL Server To SQLite DB Converter"; 295 | this.Load += new System.EventHandler(this.MainForm_Load); 296 | this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing); 297 | this.ResumeLayout(false); 298 | this.PerformLayout(); 299 | 300 | } 301 | private System.Windows.Forms.Label lblPassword; 302 | private System.Windows.Forms.Label lblUser; 303 | private System.Windows.Forms.TextBox txtPassDB; 304 | private System.Windows.Forms.TextBox txtUserDB; 305 | private System.Windows.Forms.CheckBox cbxIntegrated; 306 | 307 | #endregion 308 | 309 | private System.Windows.Forms.Label label1; 310 | private System.Windows.Forms.TextBox txtSqlAddress; 311 | private System.Windows.Forms.Label label2; 312 | private System.Windows.Forms.TextBox txtSQLitePath; 313 | private System.Windows.Forms.Button btnBrowseSQLitePath; 314 | private System.Windows.Forms.Button btnStart; 315 | private System.Windows.Forms.SaveFileDialog saveFileDialog1; 316 | private System.Windows.Forms.Label label3; 317 | private System.Windows.Forms.ComboBox cboDatabases; 318 | private System.Windows.Forms.Button btnSet; 319 | private System.Windows.Forms.ProgressBar pbrProgress; 320 | private System.Windows.Forms.Label lblMessage; 321 | private System.Windows.Forms.Button btnCancel; 322 | private System.Windows.Forms.CheckBox cbxEncrypt; 323 | private System.Windows.Forms.TextBox txtPassword; 324 | private System.Windows.Forms.CheckBox cbxTriggers; 325 | private System.Windows.Forms.LinkLabel lnkMessage; 326 | } 327 | } 328 | 329 | -------------------------------------------------------------------------------- /Converter/MainForm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Drawing; 7 | using System.Text; 8 | using System.Windows.Forms; 9 | using System.Data.SqlClient; 10 | using System.IO; 11 | using DbAccess; 12 | 13 | namespace Converter 14 | { 15 | public partial class MainForm : Form 16 | { 17 | #region Constructor 18 | public MainForm() 19 | { 20 | InitializeComponent(); 21 | } 22 | #endregion 23 | 24 | #region Event Handler 25 | private void btnBrowseSQLitePath_Click(object sender, EventArgs e) 26 | { 27 | DialogResult res = saveFileDialog1.ShowDialog(this); 28 | if (res == DialogResult.Cancel) 29 | return; 30 | 31 | string fpath = saveFileDialog1.FileName; 32 | txtSQLitePath.Text = fpath; 33 | pbrProgress.Value = 0; 34 | lblMessage.Text = string.Empty; 35 | } 36 | 37 | private void cboDatabases_SelectedIndexChanged(object sender, EventArgs e) 38 | { 39 | UpdateSensitivity(); 40 | pbrProgress.Value = 0; 41 | lblMessage.Text = string.Empty; 42 | } 43 | 44 | private void btnSet_Click(object sender, EventArgs e) 45 | { 46 | try 47 | { 48 | string constr; 49 | if (cbxIntegrated.Checked) { 50 | constr = GetSqlServerConnectionString(txtSqlAddress.Text, "master"); 51 | } else { 52 | constr = GetSqlServerConnectionString(txtSqlAddress.Text, "master", txtUserDB.Text, txtPassDB.Text); 53 | } 54 | using (SqlConnection conn = new SqlConnection(constr)) 55 | { 56 | conn.Open(); 57 | 58 | // Get the names of all DBs in the database server. 59 | SqlCommand query = new SqlCommand(@"select distinct [name] from sysdatabases", conn); 60 | using (SqlDataReader reader = query.ExecuteReader()) 61 | { 62 | cboDatabases.Items.Clear(); 63 | while (reader.Read()) 64 | cboDatabases.Items.Add((string)reader[0]); 65 | if (cboDatabases.Items.Count > 0) 66 | cboDatabases.SelectedIndex = 0; 67 | } // using 68 | } // using 69 | 70 | cboDatabases.Enabled = true; 71 | 72 | pbrProgress.Value = 0; 73 | lblMessage.Text = string.Empty; 74 | } 75 | catch (Exception ex) 76 | { 77 | MessageBox.Show(this, 78 | ex.Message, 79 | "Failed To Connect", 80 | MessageBoxButtons.OK, 81 | MessageBoxIcon.Error); 82 | } // catch 83 | } 84 | 85 | private void txtSQLitePath_TextChanged(object sender, EventArgs e) 86 | { 87 | UpdateSensitivity(); 88 | } 89 | 90 | private void MainForm_Load(object sender, EventArgs e) 91 | { 92 | UpdateSensitivity(); 93 | 94 | string version = Assembly.GetExecutingAssembly().GetName().Version.ToString(); 95 | this.Text = "SQL Server To SQLite DB Converter (" + version + ")"; 96 | } 97 | 98 | private void txtSqlAddress_TextChanged(object sender, EventArgs e) 99 | { 100 | UpdateSensitivity(); 101 | } 102 | 103 | private void btnCancel_Click(object sender, EventArgs e) 104 | { 105 | SqlServerToSQLite.CancelConversion(); 106 | } 107 | 108 | private void MainForm_FormClosing(object sender, FormClosingEventArgs e) 109 | { 110 | if (SqlServerToSQLite.IsActive) 111 | { 112 | SqlServerToSQLite.CancelConversion(); 113 | _shouldExit = true; 114 | e.Cancel = true; 115 | } 116 | else 117 | e.Cancel = false; 118 | } 119 | 120 | private void cbxEncrypt_CheckedChanged(object sender, EventArgs e) 121 | { 122 | UpdateSensitivity(); 123 | } 124 | 125 | private void txtPassword_TextChanged(object sender, EventArgs e) 126 | { 127 | UpdateSensitivity(); 128 | } 129 | 130 | private void ChkIntegratedCheckedChanged(object sender, EventArgs e) 131 | { 132 | if (cbxIntegrated.Checked) 133 | { 134 | lblPassword.Visible = false; 135 | lblUser.Visible = false; 136 | txtPassDB.Visible = false; 137 | txtUserDB.Visible = false; 138 | } 139 | else 140 | { 141 | lblPassword.Visible = true; 142 | lblUser.Visible = true; 143 | txtPassDB.Visible = true; 144 | txtUserDB.Visible = true; 145 | } 146 | } 147 | 148 | private void btnStart_Click(object sender, EventArgs e) 149 | { 150 | string sqlConnString; 151 | if (cbxIntegrated.Checked) { 152 | sqlConnString = GetSqlServerConnectionString(txtSqlAddress.Text, (string)cboDatabases.SelectedItem); 153 | } else { 154 | sqlConnString = GetSqlServerConnectionString(txtSqlAddress.Text, (string)cboDatabases.SelectedItem, txtUserDB.Text, txtPassDB.Text); 155 | } 156 | 157 | string sqlitePath = txtSQLitePath.Text.Trim(); 158 | this.Cursor = Cursors.WaitCursor; 159 | SqlConversionHandler handler = new SqlConversionHandler(delegate(bool done, 160 | bool success, int percent, string msg) { 161 | Invoke(new MethodInvoker(delegate() { 162 | UpdateSensitivity(); 163 | lblMessage.Text = msg; 164 | pbrProgress.Value = percent; 165 | 166 | if (done) 167 | { 168 | btnStart.Enabled = true; 169 | this.Cursor = Cursors.Default; 170 | UpdateSensitivity(); 171 | 172 | if (success) 173 | { 174 | MessageBox.Show(this, 175 | msg, 176 | "Conversion Finished", 177 | MessageBoxButtons.OK, 178 | MessageBoxIcon.Information); 179 | pbrProgress.Value = 0; 180 | lblMessage.Text = string.Empty; 181 | } 182 | else 183 | { 184 | if (!_shouldExit) 185 | { 186 | MessageBox.Show(this, 187 | msg, 188 | "Conversion Failed", 189 | MessageBoxButtons.OK, 190 | MessageBoxIcon.Error); 191 | pbrProgress.Value = 0; 192 | lblMessage.Text = string.Empty; 193 | } 194 | else 195 | Application.Exit(); 196 | } 197 | } 198 | })); 199 | }); 200 | SqlTableSelectionHandler selectionHandler = new SqlTableSelectionHandler(delegate(List schema) 201 | { 202 | List updated = null; 203 | Invoke(new MethodInvoker(delegate 204 | { 205 | // Allow the user to select which tables to include by showing him the 206 | // table selection dialog. 207 | TableSelectionDialog dlg = new TableSelectionDialog(); 208 | DialogResult res = dlg.ShowTables(schema, this); 209 | if (res == DialogResult.OK) 210 | updated = dlg.IncludedTables; 211 | })); 212 | return updated; 213 | }); 214 | 215 | FailedViewDefinitionHandler viewFailureHandler = new FailedViewDefinitionHandler(delegate(ViewSchema vs) 216 | { 217 | string updated = null; 218 | Invoke(new MethodInvoker(delegate 219 | { 220 | ViewFailureDialog dlg = new ViewFailureDialog(); 221 | dlg.View = vs; 222 | DialogResult res = dlg.ShowDialog(this); 223 | if (res == DialogResult.OK) 224 | updated = dlg.ViewSQL; 225 | else 226 | updated = null; 227 | })); 228 | 229 | return updated; 230 | }); 231 | 232 | string password = txtPassword.Text.Trim(); 233 | if (!cbxEncrypt.Checked) 234 | password = null; 235 | SqlServerToSQLite.ConvertSqlServerToSQLiteDatabase(sqlConnString, sqlitePath, password, handler, 236 | selectionHandler, viewFailureHandler, cbxTriggers.Checked); 237 | } 238 | 239 | private void lnkMessage_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 240 | { 241 | AuthorMessageForm frm = new AuthorMessageForm(); 242 | frm.ShowDialog(this); 243 | } 244 | 245 | #endregion 246 | 247 | #region Private Methods 248 | private void UpdateSensitivity() 249 | { 250 | if (txtSQLitePath.Text.Trim().Length > 0 && cboDatabases.Enabled && 251 | (!cbxEncrypt.Checked || txtPassword.Text.Trim().Length > 0)) 252 | btnStart.Enabled = true && !SqlServerToSQLite.IsActive; 253 | else 254 | btnStart.Enabled = false; 255 | 256 | btnSet.Enabled = txtSqlAddress.Text.Trim().Length > 0 && !SqlServerToSQLite.IsActive; 257 | btnCancel.Visible = SqlServerToSQLite.IsActive; 258 | txtSqlAddress.Enabled = !SqlServerToSQLite.IsActive; 259 | txtSQLitePath.Enabled = !SqlServerToSQLite.IsActive; 260 | btnBrowseSQLitePath.Enabled = !SqlServerToSQLite.IsActive; 261 | cbxEncrypt.Enabled = !SqlServerToSQLite.IsActive; 262 | cboDatabases.Enabled = cboDatabases.Items.Count > 0 && !SqlServerToSQLite.IsActive; 263 | txtPassword.Enabled = cbxEncrypt.Checked && cbxEncrypt.Enabled; 264 | cbxIntegrated.Enabled = !SqlServerToSQLite.IsActive; 265 | txtPassDB.Enabled = !SqlServerToSQLite.IsActive; 266 | txtUserDB.Enabled = !SqlServerToSQLite.IsActive; 267 | } 268 | 269 | private static string GetSqlServerConnectionString(string address, string db) 270 | { 271 | string res = @"Data Source=" + address.Trim() + 272 | ";Initial Catalog="+db.Trim()+";Integrated Security=SSPI;"; 273 | return res; 274 | } 275 | private static string GetSqlServerConnectionString(string address, string db, string user, string pass) 276 | { 277 | string res = @"Data Source=" + address.Trim() + 278 | ";Initial Catalog="+db.Trim()+";User ID=" + user.Trim() + ";Password=" + pass.Trim(); 279 | return res; 280 | } 281 | #endregion 282 | 283 | #region Private Variables 284 | private bool _shouldExit = false; 285 | #endregion 286 | } 287 | } -------------------------------------------------------------------------------- /Converter/MainForm.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | 17, 17 122 | 123 | -------------------------------------------------------------------------------- /Converter/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Windows.Forms; 4 | using log4net; 5 | using log4net.Config; 6 | 7 | // Configure LOG4NET Using configuration file. 8 | [assembly: log4net.Config.XmlConfigurator(Watch = true)] 9 | 10 | namespace Converter 11 | { 12 | static class Program 13 | { 14 | /// 15 | /// The main entry point for the application. 16 | /// 17 | [STAThread] 18 | static void Main() 19 | { 20 | BasicConfigurator.Configure(); 21 | 22 | Application.EnableVisualStyles(); 23 | Application.SetCompatibleTextRenderingDefault(false); 24 | Application.Run(new MainForm()); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /Converter/TableSelectionDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Converter 2 | { 3 | partial class TableSelectionDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.grdTables = new System.Windows.Forms.DataGridView(); 32 | this.colInclude = new System.Windows.Forms.DataGridViewCheckBoxColumn(); 33 | this.colTableName = new System.Windows.Forms.DataGridViewTextBoxColumn(); 34 | this.btnSelectAll = new System.Windows.Forms.Button(); 35 | this.btnDeselectAll = new System.Windows.Forms.Button(); 36 | this.btnCancel = new System.Windows.Forms.Button(); 37 | this.btnOK = new System.Windows.Forms.Button(); 38 | ((System.ComponentModel.ISupportInitialize)(this.grdTables)).BeginInit(); 39 | this.SuspendLayout(); 40 | // 41 | // grdTables 42 | // 43 | this.grdTables.AllowUserToAddRows = false; 44 | this.grdTables.AllowUserToDeleteRows = false; 45 | this.grdTables.AllowUserToResizeColumns = false; 46 | this.grdTables.AllowUserToResizeRows = false; 47 | this.grdTables.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 48 | | System.Windows.Forms.AnchorStyles.Left) 49 | | System.Windows.Forms.AnchorStyles.Right))); 50 | this.grdTables.BackgroundColor = System.Drawing.Color.White; 51 | this.grdTables.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; 52 | this.grdTables.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { 53 | this.colInclude, 54 | this.colTableName}); 55 | this.grdTables.Location = new System.Drawing.Point(12, 12); 56 | this.grdTables.Name = "grdTables"; 57 | this.grdTables.RowHeadersVisible = false; 58 | this.grdTables.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.CellSelect; 59 | this.grdTables.Size = new System.Drawing.Size(407, 328); 60 | this.grdTables.TabIndex = 0; 61 | // 62 | // colInclude 63 | // 64 | this.colInclude.HeaderText = ""; 65 | this.colInclude.Name = "colInclude"; 66 | this.colInclude.Resizable = System.Windows.Forms.DataGridViewTriState.False; 67 | this.colInclude.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; 68 | this.colInclude.Width = 30; 69 | // 70 | // colTableName 71 | // 72 | this.colTableName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; 73 | this.colTableName.HeaderText = "Table Name"; 74 | this.colTableName.Name = "colTableName"; 75 | this.colTableName.ReadOnly = true; 76 | this.colTableName.Resizable = System.Windows.Forms.DataGridViewTriState.False; 77 | // 78 | // btnSelectAll 79 | // 80 | this.btnSelectAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 81 | this.btnSelectAll.Location = new System.Drawing.Point(12, 346); 82 | this.btnSelectAll.Name = "btnSelectAll"; 83 | this.btnSelectAll.Size = new System.Drawing.Size(75, 23); 84 | this.btnSelectAll.TabIndex = 1; 85 | this.btnSelectAll.Text = "Select All"; 86 | this.btnSelectAll.UseVisualStyleBackColor = true; 87 | this.btnSelectAll.Click += new System.EventHandler(this.btnSelectAll_Click); 88 | // 89 | // btnDeselectAll 90 | // 91 | this.btnDeselectAll.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); 92 | this.btnDeselectAll.Location = new System.Drawing.Point(93, 346); 93 | this.btnDeselectAll.Name = "btnDeselectAll"; 94 | this.btnDeselectAll.Size = new System.Drawing.Size(89, 23); 95 | this.btnDeselectAll.TabIndex = 2; 96 | this.btnDeselectAll.Text = "Deselect All"; 97 | this.btnDeselectAll.UseVisualStyleBackColor = true; 98 | this.btnDeselectAll.Click += new System.EventHandler(this.btnDeselectAll_Click); 99 | // 100 | // btnCancel 101 | // 102 | this.btnCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 103 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 104 | this.btnCancel.Location = new System.Drawing.Point(343, 346); 105 | this.btnCancel.Name = "btnCancel"; 106 | this.btnCancel.Size = new System.Drawing.Size(76, 23); 107 | this.btnCancel.TabIndex = 3; 108 | this.btnCancel.Text = "Cancel"; 109 | this.btnCancel.UseVisualStyleBackColor = true; 110 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); 111 | // 112 | // btnOK 113 | // 114 | this.btnOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); 115 | this.btnOK.Location = new System.Drawing.Point(261, 346); 116 | this.btnOK.Name = "btnOK"; 117 | this.btnOK.Size = new System.Drawing.Size(76, 23); 118 | this.btnOK.TabIndex = 4; 119 | this.btnOK.Text = "OK"; 120 | this.btnOK.UseVisualStyleBackColor = true; 121 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 122 | // 123 | // TableSelectionDialog 124 | // 125 | this.AcceptButton = this.btnOK; 126 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 127 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 128 | this.CancelButton = this.btnCancel; 129 | this.ClientSize = new System.Drawing.Size(433, 377); 130 | this.Controls.Add(this.btnOK); 131 | this.Controls.Add(this.btnCancel); 132 | this.Controls.Add(this.btnDeselectAll); 133 | this.Controls.Add(this.btnSelectAll); 134 | this.Controls.Add(this.grdTables); 135 | this.Name = "TableSelectionDialog"; 136 | this.ShowIcon = false; 137 | this.ShowInTaskbar = false; 138 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 139 | this.Text = "Select Tables To Convert"; 140 | ((System.ComponentModel.ISupportInitialize)(this.grdTables)).EndInit(); 141 | this.ResumeLayout(false); 142 | 143 | } 144 | 145 | #endregion 146 | 147 | private System.Windows.Forms.DataGridView grdTables; 148 | private System.Windows.Forms.DataGridViewCheckBoxColumn colInclude; 149 | private System.Windows.Forms.DataGridViewTextBoxColumn colTableName; 150 | private System.Windows.Forms.Button btnSelectAll; 151 | private System.Windows.Forms.Button btnDeselectAll; 152 | private System.Windows.Forms.Button btnCancel; 153 | private System.Windows.Forms.Button btnOK; 154 | } 155 | } -------------------------------------------------------------------------------- /Converter/TableSelectionDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using DbAccess; 9 | 10 | namespace Converter 11 | { 12 | /// 13 | /// The dialog allows the user to select which tables to include in the 14 | /// converstion process. 15 | /// 16 | public partial class TableSelectionDialog : Form 17 | { 18 | #region Constructors 19 | public TableSelectionDialog() 20 | { 21 | InitializeComponent(); 22 | } 23 | #endregion 24 | 25 | #region Public Properties 26 | /// 27 | /// Returns the list of included table schema objects. 28 | /// 29 | public List IncludedTables 30 | { 31 | get 32 | { 33 | List res = new List(); 34 | foreach (DataGridViewRow row in grdTables.Rows) 35 | { 36 | bool include = (bool)row.Cells[0].Value; 37 | if (include) 38 | res.Add((TableSchema)row.Tag); 39 | } // foreach 40 | 41 | return res; 42 | } 43 | } 44 | #endregion 45 | 46 | #region Public Methods 47 | /// 48 | /// Opens the table selection dialog and uses the specified schema list in order 49 | /// to update the tables grid. 50 | /// 51 | /// The DB schema to display in the grid 52 | /// The owner form 53 | /// dialog result according to user decision. 54 | public DialogResult ShowTables(List schema, IWin32Window owner) 55 | { 56 | UpdateGuiFromSchema(schema); 57 | return this.ShowDialog(owner); 58 | } 59 | #endregion 60 | 61 | #region Event Handlers 62 | private void btnOK_Click(object sender, EventArgs e) 63 | { 64 | DialogResult = DialogResult.OK; 65 | } 66 | 67 | private void btnCancel_Click(object sender, EventArgs e) 68 | { 69 | DialogResult = DialogResult.Cancel; 70 | } 71 | 72 | private void btnDeselectAll_Click(object sender, EventArgs e) 73 | { 74 | foreach (DataGridViewRow row in grdTables.Rows) 75 | { 76 | // Uncheck the [V] for this row. 77 | row.Cells[0].Value = false; 78 | } // foreach 79 | } 80 | 81 | private void btnSelectAll_Click(object sender, EventArgs e) 82 | { 83 | foreach (DataGridViewRow row in grdTables.Rows) 84 | { 85 | // Check the [V] for this row. 86 | row.Cells[0].Value = true; 87 | } // foreach 88 | } 89 | #endregion 90 | 91 | #region Private Methods 92 | private void UpdateGuiFromSchema(List schema) 93 | { 94 | grdTables.Rows.Clear(); 95 | foreach (TableSchema table in schema) 96 | { 97 | grdTables.Rows.Add(true, table.TableName); 98 | grdTables.Rows[grdTables.Rows.Count - 1].Tag = table; 99 | } // foreach 100 | } 101 | #endregion 102 | } 103 | } -------------------------------------------------------------------------------- /Converter/TableSelectionDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | 121 | True 122 | 123 | 124 | True 125 | 126 | 127 | True 128 | 129 | 130 | True 131 | 132 | -------------------------------------------------------------------------------- /Converter/ViewFailureDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Converter 2 | { 3 | partial class ViewFailureDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | this.label1 = new System.Windows.Forms.Label(); 32 | this.txtSQL = new System.Windows.Forms.TextBox(); 33 | this.btnCancel = new System.Windows.Forms.Button(); 34 | this.btnOK = new System.Windows.Forms.Button(); 35 | this.SuspendLayout(); 36 | // 37 | // label1 38 | // 39 | this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(177))); 40 | this.label1.ForeColor = System.Drawing.Color.Red; 41 | this.label1.Location = new System.Drawing.Point(9, 9); 42 | this.label1.Name = "label1"; 43 | this.label1.Size = new System.Drawing.Size(491, 30); 44 | this.label1.TabIndex = 0; 45 | this.label1.Text = "View syntax cannot be transferred automatically to SQLite. Please edit the view d" + 46 | "efinition or press Cancel to discard the view from the generated SQLite database" + 47 | "."; 48 | // 49 | // txtSQL 50 | // 51 | this.txtSQL.Location = new System.Drawing.Point(12, 45); 52 | this.txtSQL.Multiline = true; 53 | this.txtSQL.Name = "txtSQL"; 54 | this.txtSQL.Size = new System.Drawing.Size(488, 125); 55 | this.txtSQL.TabIndex = 1; 56 | // 57 | // btnCancel 58 | // 59 | this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; 60 | this.btnCancel.Location = new System.Drawing.Point(425, 181); 61 | this.btnCancel.Name = "btnCancel"; 62 | this.btnCancel.Size = new System.Drawing.Size(75, 23); 63 | this.btnCancel.TabIndex = 2; 64 | this.btnCancel.Text = "Cancel"; 65 | this.btnCancel.UseVisualStyleBackColor = true; 66 | this.btnCancel.Click += new System.EventHandler(this.btnCancel_Click); 67 | // 68 | // btnOK 69 | // 70 | this.btnOK.Location = new System.Drawing.Point(344, 181); 71 | this.btnOK.Name = "btnOK"; 72 | this.btnOK.Size = new System.Drawing.Size(75, 23); 73 | this.btnOK.TabIndex = 3; 74 | this.btnOK.Text = "OK"; 75 | this.btnOK.UseVisualStyleBackColor = true; 76 | this.btnOK.Click += new System.EventHandler(this.btnOK_Click); 77 | // 78 | // ViewFailureDialog 79 | // 80 | this.AcceptButton = this.btnOK; 81 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 82 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 83 | this.CancelButton = this.btnCancel; 84 | this.ClientSize = new System.Drawing.Size(515, 216); 85 | this.Controls.Add(this.btnOK); 86 | this.Controls.Add(this.btnCancel); 87 | this.Controls.Add(this.txtSQL); 88 | this.Controls.Add(this.label1); 89 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 90 | this.MaximizeBox = false; 91 | this.MinimizeBox = false; 92 | this.Name = "ViewFailureDialog"; 93 | this.ShowIcon = false; 94 | this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; 95 | this.ResumeLayout(false); 96 | this.PerformLayout(); 97 | 98 | } 99 | 100 | #endregion 101 | 102 | private System.Windows.Forms.Label label1; 103 | private System.Windows.Forms.TextBox txtSQL; 104 | private System.Windows.Forms.Button btnCancel; 105 | private System.Windows.Forms.Button btnOK; 106 | } 107 | } -------------------------------------------------------------------------------- /Converter/ViewFailureDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel; 4 | using System.Data; 5 | using System.Drawing; 6 | using System.Text; 7 | using System.Windows.Forms; 8 | using DbAccess; 9 | 10 | namespace Converter 11 | { 12 | public partial class ViewFailureDialog : Form 13 | { 14 | public ViewFailureDialog() 15 | { 16 | InitializeComponent(); 17 | } 18 | 19 | public ViewSchema View 20 | { 21 | get { return _view; } 22 | set 23 | { 24 | _view = value; 25 | this.Text = "SQL Error: "+_view.ViewName; 26 | txtSQL.Text = _view.ViewSQL; 27 | } 28 | } 29 | 30 | public string ViewSQL 31 | { 32 | get { return txtSQL.Text; } 33 | } 34 | 35 | 36 | private void btnOK_Click(object sender, EventArgs e) 37 | { 38 | this.DialogResult = DialogResult.OK; 39 | } 40 | 41 | private void btnCancel_Click(object sender, EventArgs e) 42 | { 43 | this.DialogResult = DialogResult.Cancel; 44 | } 45 | 46 | private ViewSchema _view; 47 | } 48 | } -------------------------------------------------------------------------------- /Converter/ViewFailureDialog.resx: -------------------------------------------------------------------------------- 1 | 2 | 3 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | text/microsoft-resx 110 | 111 | 112 | 2.0 113 | 114 | 115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | 118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 119 | 120 | -------------------------------------------------------------------------------- /Converter/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /DbAccess/ColumnSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | /// 8 | /// Contains the schema of a single DB column. 9 | /// 10 | public class ColumnSchema 11 | { 12 | public string ColumnName; 13 | 14 | public string ColumnType; 15 | 16 | public int Length; 17 | 18 | public bool IsNullable; 19 | 20 | public string DefaultValue; 21 | 22 | public bool IsIdentity; 23 | 24 | public bool? IsCaseSensitivite = null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /DbAccess/DatabaseSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | /// 8 | /// Contains the entire database schema 9 | /// 10 | public class DatabaseSchema 11 | { 12 | public List Tables = new List(); 13 | public List Views = new List(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /DbAccess/DbAccess.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.50727 7 | 2.0 8 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288} 9 | Library 10 | Properties 11 | DbAccess 12 | DbAccess 13 | v2.0 14 | 15 | 16 | 2.0 17 | 18 | publish\ 19 | true 20 | Disk 21 | false 22 | Foreground 23 | 7 24 | Days 25 | false 26 | false 27 | true 28 | 0 29 | 1.0.0.%2a 30 | false 31 | false 32 | true 33 | 34 | 35 | true 36 | full 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | prompt 41 | 4 42 | x86 43 | AllRules.ruleset 44 | 45 | 46 | pdbonly 47 | true 48 | bin\Release\ 49 | TRACE 50 | prompt 51 | 4 52 | AllRules.ruleset 53 | 54 | 55 | 56 | False 57 | ..\log4net.dll 58 | 59 | 60 | 61 | 62 | False 63 | ..\System.Data.SQLite.dll 64 | 65 | 66 | 67 | 68 | 69 | Properties\SolutionInfo.cs 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | False 84 | .NET Framework 3.5 SP1 Client Profile 85 | false 86 | 87 | 88 | False 89 | .NET Framework 3.5 SP1 90 | true 91 | 92 | 93 | False 94 | Windows Installer 3.1 95 | true 96 | 97 | 98 | 99 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /DbAccess/ForeignKeySchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | public class ForeignKeySchema 8 | { 9 | public string TableName; 10 | 11 | public string ColumnName; 12 | 13 | public string ForeignTableName; 14 | 15 | public string ForeignColumnName; 16 | 17 | public bool CascadeOnDelete; 18 | 19 | public bool IsNullable; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DbAccess/IndexSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | public class IndexSchema 8 | { 9 | public string IndexName; 10 | 11 | public bool IsUnique; 12 | 13 | public List Columns; 14 | } 15 | 16 | public class IndexColumn 17 | { 18 | public string ColumnName; 19 | public bool IsAscending; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DbAccess/SqlServerToSQLite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using System.Data; 5 | using System.Data.SqlClient; 6 | using System.Data.SQLite; 7 | using System.Threading; 8 | using System.Text.RegularExpressions; 9 | using System.IO; 10 | using log4net; 11 | 12 | namespace DbAccess 13 | { 14 | /// 15 | /// This class is resposible to take a single SQL Server database 16 | /// and convert it to an SQLite database file. 17 | /// 18 | /// The class knows how to convert table and index structures only. 19 | public class SqlServerToSQLite 20 | { 21 | #region Public Properties 22 | /// 23 | /// Gets a value indicating whether this instance is active. 24 | /// 25 | /// true if this instance is active; otherwise, false. 26 | public static bool IsActive 27 | { 28 | get { return _isActive; } 29 | } 30 | #endregion 31 | 32 | #region Public Methods 33 | /// 34 | /// Cancels the conversion. 35 | /// 36 | public static void CancelConversion() 37 | { 38 | _cancelled = true; 39 | } 40 | 41 | /// 42 | /// This method takes as input the connection string to an SQL Server database 43 | /// and creates a corresponding SQLite database file with a schema derived from 44 | /// the SQL Server database. 45 | /// 46 | /// The connection string to the SQL Server database. 47 | /// The path to the SQLite database file that needs to get created. 48 | /// The password to use or NULL if no password should be used to encrypt the DB 49 | /// A handler delegate for progress notifications. 50 | /// The selection handler that allows the user to select which 51 | /// tables to convert 52 | /// The method continues asynchronously in the background and the caller returned 53 | /// immediatly. 54 | public static void ConvertSqlServerToSQLiteDatabase(string sqlServerConnString, 55 | string sqlitePath, string password, SqlConversionHandler handler, 56 | SqlTableSelectionHandler selectionHandler, 57 | FailedViewDefinitionHandler viewFailureHandler, 58 | bool createTriggers) 59 | { 60 | // Clear cancelled flag 61 | _cancelled = false; 62 | 63 | WaitCallback wc = new WaitCallback(delegate(object state) 64 | { 65 | try 66 | { 67 | _isActive = true; 68 | ConvertSqlServerDatabaseToSQLiteFile(sqlServerConnString, sqlitePath, password, handler, selectionHandler, viewFailureHandler, createTriggers); 69 | _isActive = false; 70 | handler(true, true, 100, "Finished converting database"); 71 | } 72 | catch (Exception ex) 73 | { 74 | _log.Error("Failed to convert SQL Server database to SQLite database", ex); 75 | _isActive = false; 76 | handler(true, false, 100, ex.Message); 77 | } // catch 78 | }); 79 | ThreadPool.QueueUserWorkItem(wc); 80 | } 81 | #endregion 82 | 83 | #region Private Methods 84 | /// 85 | /// Do the entire process of first reading the SQL Server schema, creating a corresponding 86 | /// SQLite schema, and copying all rows from the SQL Server database to the SQLite database. 87 | /// 88 | /// The SQL Server connection string 89 | /// The path to the generated SQLite database file 90 | /// The password to use or NULL if no password should be used to encrypt the DB 91 | /// A handler to handle progress notifications. 92 | /// The selection handler which allows the user to select which tables to 93 | /// convert. 94 | private static void ConvertSqlServerDatabaseToSQLiteFile( 95 | string sqlConnString, string sqlitePath, string password, SqlConversionHandler handler, 96 | SqlTableSelectionHandler selectionHandler, 97 | FailedViewDefinitionHandler viewFailureHandler, 98 | bool createTriggers) 99 | { 100 | // Delete the target file if it exists already. 101 | if (File.Exists(sqlitePath)) 102 | File.Delete(sqlitePath); 103 | 104 | // Read the schema of the SQL Server database into a memory structure 105 | DatabaseSchema ds = ReadSqlServerSchema(sqlConnString, handler, selectionHandler); 106 | 107 | // Create the SQLite database and apply the schema 108 | CreateSQLiteDatabase(sqlitePath, ds, password, handler, viewFailureHandler); 109 | 110 | // Copy all rows from SQL Server tables to the newly created SQLite database 111 | CopySqlServerRowsToSQLiteDB(sqlConnString, sqlitePath, ds.Tables, password, handler); 112 | 113 | // Add triggers based on foreign key constraints 114 | if (createTriggers) 115 | AddTriggersForForeignKeys(sqlitePath, ds.Tables, password, handler); 116 | 117 | } 118 | 119 | /// 120 | /// Copies table rows from the SQL Server database to the SQLite database. 121 | /// 122 | /// The SQL Server connection string 123 | /// The path to the SQLite database file. 124 | /// The schema of the SQL Server database. 125 | /// The password to use for encrypting the file 126 | /// A handler to handle progress notifications. 127 | private static void CopySqlServerRowsToSQLiteDB( 128 | string sqlConnString, string sqlitePath, List schema, 129 | string password, SqlConversionHandler handler) 130 | { 131 | CheckCancelled(); 132 | handler(false, true, 0, "Preparing to insert tables..."); 133 | _log.Debug("preparing to insert tables ..."); 134 | 135 | // Connect to the SQL Server database 136 | using (SqlConnection ssconn = new SqlConnection(sqlConnString)) 137 | { 138 | ssconn.Open(); 139 | 140 | // Connect to the SQLite database next 141 | string sqliteConnString = CreateSQLiteConnectionString(sqlitePath, password); 142 | using (SQLiteConnection sqconn = new SQLiteConnection(sqliteConnString)) 143 | { 144 | sqconn.Open(); 145 | 146 | // Go over all tables in the schema and copy their rows 147 | for (int i = 0; i < schema.Count; i++) 148 | { 149 | SQLiteTransaction tx = sqconn.BeginTransaction(); 150 | try 151 | { 152 | string tableQuery = BuildSqlServerTableQuery(schema[i]); 153 | SqlCommand query = new SqlCommand(tableQuery, ssconn); 154 | using (SqlDataReader reader = query.ExecuteReader()) 155 | { 156 | SQLiteCommand insert = BuildSQLiteInsert(schema[i]); 157 | int counter = 0; 158 | while (reader.Read()) 159 | { 160 | insert.Connection = sqconn; 161 | insert.Transaction = tx; 162 | List pnames = new List(); 163 | for (int j = 0; j < schema[i].Columns.Count; j++) 164 | { 165 | string pname = "@" + GetNormalizedName(schema[i].Columns[j].ColumnName, pnames); 166 | insert.Parameters[pname].Value = CastValueForColumn(reader[j], schema[i].Columns[j]); 167 | pnames.Add(pname); 168 | } 169 | insert.ExecuteNonQuery(); 170 | counter++; 171 | if (counter % 1000 == 0) 172 | { 173 | CheckCancelled(); 174 | tx.Commit(); 175 | handler(false, true, (int)(100.0 * i / schema.Count), 176 | "Added " + counter + " rows to table "+schema[i].TableName+" so far"); 177 | tx = sqconn.BeginTransaction(); 178 | } 179 | } // while 180 | } // using 181 | 182 | CheckCancelled(); 183 | tx.Commit(); 184 | 185 | handler(false, true, (int)(100.0 * i / schema.Count), "Finished inserting rows for table " + schema[i].TableName); 186 | _log.Debug("finished inserting all rows for table [" + schema[i].TableName + "]"); 187 | } 188 | catch (Exception ex) 189 | { 190 | _log.Error("unexpected exception", ex); 191 | tx.Rollback(); 192 | throw; 193 | } // catch 194 | } 195 | } // using 196 | } // using 197 | } 198 | 199 | /// 200 | /// Used in order to adjust the value received from SQL Servr for the SQLite database. 201 | /// 202 | /// The value object 203 | /// The corresponding column schema 204 | /// SQLite adjusted value. 205 | private static object CastValueForColumn(object val, ColumnSchema columnSchema) 206 | { 207 | if (val is DBNull) 208 | return null; 209 | 210 | DbType dt = GetDbTypeOfColumn(columnSchema); 211 | 212 | switch (dt) 213 | { 214 | case DbType.Int32: 215 | if (val is short) 216 | return (int)(short)val; 217 | if (val is byte) 218 | return (int)(byte)val; 219 | if (val is long) 220 | return (int)(long)val; 221 | if (val is decimal) 222 | return (int)(decimal)val; 223 | break; 224 | 225 | case DbType.Int16: 226 | if (val is int) 227 | return (short)(int)val; 228 | if (val is byte) 229 | return (short)(byte)val; 230 | if (val is long) 231 | return (short)(long)val; 232 | if (val is decimal) 233 | return (short)(decimal)val; 234 | break; 235 | 236 | case DbType.Int64: 237 | if (val is int) 238 | return (long)(int)val; 239 | if (val is short) 240 | return (long)(short)val; 241 | if (val is byte) 242 | return (long)(byte)val; 243 | if (val is decimal) 244 | return (long)(decimal)val; 245 | break; 246 | 247 | case DbType.Single: 248 | if (val is double) 249 | return (float)(double)val; 250 | if (val is decimal) 251 | return (float)(decimal)val; 252 | break; 253 | 254 | case DbType.Double: 255 | if (val is float) 256 | return (double)(float)val; 257 | if (val is double) 258 | return (double)val; 259 | if (val is decimal) 260 | return (double)(decimal)val; 261 | break; 262 | 263 | case DbType.String: 264 | if (val is Guid) 265 | return ((Guid)val).ToString(); 266 | break; 267 | 268 | case DbType.Guid: 269 | if (val is string) 270 | return ParseStringAsGuid((string)val); 271 | if (val is byte[]) 272 | return ParseBlobAsGuid((byte[])val); 273 | break; 274 | 275 | case DbType.Time: 276 | case DbType.DateTime: 277 | case DbType.Date: 278 | case DbType.DateTime2: 279 | if (val is TimeSpan) 280 | return DateTime.MinValue + (TimeSpan)val; 281 | break; 282 | case DbType.Binary: 283 | case DbType.Boolean: 284 | break; 285 | 286 | default: 287 | _log.Error("argument exception - illegal database type"); 288 | throw new ArgumentException("Illegal database type [" + Enum.GetName(typeof(DbType), dt) + "]"); 289 | } // switch 290 | 291 | return val; 292 | } 293 | 294 | private static Guid ParseBlobAsGuid(byte[] blob) 295 | { 296 | byte[] data = blob; 297 | if (blob.Length > 16) 298 | { 299 | data = new byte[16]; 300 | for (int i = 0; i < 16; i++) 301 | data[i] = blob[i]; 302 | } 303 | else if (blob.Length < 16) 304 | { 305 | data = new byte[16]; 306 | for (int i = 0; i < blob.Length; i++) 307 | data[i] = blob[i]; 308 | } 309 | 310 | return new Guid(data); 311 | } 312 | 313 | private static Guid ParseStringAsGuid(string str) 314 | { 315 | try 316 | { 317 | return new Guid(str); 318 | } 319 | catch (Exception ex) 320 | { 321 | return Guid.Empty; 322 | } // catch 323 | } 324 | 325 | /// 326 | /// Creates a command object needed to insert values into a specific SQLite table. 327 | /// 328 | /// The table schema object for the table. 329 | /// A command object with the required functionality. 330 | private static SQLiteCommand BuildSQLiteInsert(TableSchema ts) 331 | { 332 | SQLiteCommand res = new SQLiteCommand(); 333 | 334 | StringBuilder sb = new StringBuilder(); 335 | sb.Append("INSERT INTO [" + ts.TableName + "] ("); 336 | for (int i = 0; i < ts.Columns.Count; i++) 337 | { 338 | sb.Append("[" + ts.Columns[i].ColumnName + "]"); 339 | if (i < ts.Columns.Count - 1) 340 | sb.Append(", "); 341 | } // for 342 | sb.Append(") VALUES ("); 343 | 344 | List pnames = new List(); 345 | for (int i = 0; i < ts.Columns.Count; i++) 346 | { 347 | string pname = "@" + GetNormalizedName(ts.Columns[i].ColumnName, pnames); 348 | sb.Append(pname); 349 | if (i < ts.Columns.Count - 1) 350 | sb.Append(", "); 351 | 352 | DbType dbType = GetDbTypeOfColumn(ts.Columns[i]); 353 | SQLiteParameter prm = new SQLiteParameter(pname, dbType, ts.Columns[i].ColumnName); 354 | res.Parameters.Add(prm); 355 | 356 | // Remember the parameter name in order to avoid duplicates 357 | pnames.Add(pname); 358 | } // for 359 | sb.Append(")"); 360 | res.CommandText = sb.ToString(); 361 | res.CommandType = CommandType.Text; 362 | return res; 363 | } 364 | 365 | /// 366 | /// Used in order to avoid breaking naming rules (e.g., when a table has 367 | /// a name in SQL Server that cannot be used as a basis for a matching index 368 | /// name in SQLite). 369 | /// 370 | /// The name to change if necessary 371 | /// Used to avoid duplicate names 372 | /// A normalized name 373 | private static string GetNormalizedName(string str, List names) 374 | { 375 | StringBuilder sb = new StringBuilder(); 376 | for (int i = 0; i < str.Length; i++) 377 | { 378 | if (Char.IsLetterOrDigit(str[i]) || str[i] == '_') 379 | sb.Append(str[i]); 380 | else 381 | sb.Append("_"); 382 | } // for 383 | 384 | // Avoid returning duplicate name 385 | if (names.Contains(sb.ToString())) 386 | return GetNormalizedName(sb.ToString() + "_", names); 387 | else 388 | return sb.ToString(); 389 | } 390 | 391 | /// 392 | /// Matches SQL Server types to general DB types 393 | /// 394 | /// The column schema to use for the match 395 | /// The matched DB type 396 | private static DbType GetDbTypeOfColumn(ColumnSchema cs) 397 | { 398 | if (cs.ColumnType == "tinyint") 399 | return DbType.Byte; 400 | if (cs.ColumnType == "int") 401 | return DbType.Int32; 402 | if (cs.ColumnType == "smallint") 403 | return DbType.Int16; 404 | if (cs.ColumnType == "bigint") 405 | return DbType.Int64; 406 | if (cs.ColumnType == "bit") 407 | return DbType.Boolean; 408 | if (cs.ColumnType == "nvarchar" || cs.ColumnType == "varchar" || 409 | cs.ColumnType == "text" || cs.ColumnType == "ntext") 410 | return DbType.String; 411 | if (cs.ColumnType == "float") 412 | return DbType.Double; 413 | if (cs.ColumnType == "real") 414 | return DbType.Single; 415 | if (cs.ColumnType == "blob") 416 | return DbType.Binary; 417 | if (cs.ColumnType == "numeric") 418 | return DbType.Double; 419 | if (cs.ColumnType == "timestamp" || cs.ColumnType == "datetime") 420 | return DbType.DateTime; 421 | if (cs.ColumnType == "date") 422 | return DbType.Date; 423 | if (cs.ColumnType == "datetime2") 424 | return DbType.DateTime2; 425 | if (cs.ColumnType == "nchar" || cs.ColumnType == "char") 426 | return DbType.String; 427 | if (cs.ColumnType == "uniqueidentifier" || cs.ColumnType == "guid") 428 | return DbType.Guid; 429 | if (cs.ColumnType == "xml") 430 | return DbType.String; 431 | if (cs.ColumnType == "sql_variant") 432 | return DbType.Object; 433 | if (cs.ColumnType == "integer") 434 | return DbType.Int64; 435 | if (cs.ColumnType == "time") 436 | return DbType.Time; 437 | 438 | _log.Error("illegal db type found"); 439 | throw new ApplicationException("Illegal DB type found (" + cs.ColumnType + ")"); 440 | } 441 | 442 | /// 443 | /// Builds a SELECT query for a specific table. Needed in the process of copying rows 444 | /// from the SQL Server database to the SQLite database. 445 | /// 446 | /// The table schema of the table for which we need the query. 447 | /// The SELECT query for the table. 448 | private static string BuildSqlServerTableQuery(TableSchema ts) 449 | { 450 | StringBuilder sb = new StringBuilder(); 451 | sb.Append("SELECT "); 452 | for (int i = 0; i < ts.Columns.Count; i++) 453 | { 454 | sb.Append("[" + ts.Columns[i].ColumnName + "]"); 455 | if (i < ts.Columns.Count - 1) 456 | sb.Append(", "); 457 | } // for 458 | sb.Append(" FROM "+ts.TableSchemaName+"."+"["+ts.TableName + "]"); 459 | return sb.ToString(); 460 | } 461 | 462 | /// 463 | /// Creates the SQLite database from the schema read from the SQL Server. 464 | /// 465 | /// The path to the generated DB file. 466 | /// The schema of the SQL server database. 467 | /// The password to use for encrypting the DB or null if non is needed. 468 | /// A handle for progress notifications. 469 | private static void CreateSQLiteDatabase(string sqlitePath, DatabaseSchema schema, string password, 470 | SqlConversionHandler handler, 471 | FailedViewDefinitionHandler viewFailureHandler) 472 | { 473 | _log.Debug("Creating SQLite database..."); 474 | 475 | // Create the SQLite database file 476 | SQLiteConnection.CreateFile(sqlitePath); 477 | 478 | _log.Debug("SQLite file was created successfully at [" + sqlitePath + "]"); 479 | 480 | // Connect to the newly created database 481 | string sqliteConnString = CreateSQLiteConnectionString(sqlitePath, password); 482 | using (SQLiteConnection conn = new SQLiteConnection(sqliteConnString)) 483 | { 484 | conn.Open(); 485 | 486 | // Create all tables in the new database 487 | int count = 0; 488 | foreach (TableSchema dt in schema.Tables) 489 | { 490 | try 491 | { 492 | AddSQLiteTable(conn, dt); 493 | } 494 | catch (Exception ex) 495 | { 496 | _log.Error("AddSQLiteTable failed", ex); 497 | throw; 498 | } 499 | count++; 500 | CheckCancelled(); 501 | handler(false, true, (int)(count * 50.0 / schema.Tables.Count), "Added table " + dt.TableName + " to the SQLite database"); 502 | 503 | _log.Debug("added schema for SQLite table [" + dt.TableName + "]"); 504 | } // foreach 505 | 506 | // Create all views in the new database 507 | count = 0; 508 | foreach (ViewSchema vs in schema.Views) 509 | { 510 | try 511 | { 512 | AddSQLiteView(conn, vs, viewFailureHandler); 513 | } 514 | catch (Exception ex) 515 | { 516 | _log.Error("AddSQLiteView failed", ex); 517 | throw; 518 | } // catch 519 | count++; 520 | CheckCancelled(); 521 | handler(false, true, 50+(int)(count * 50.0 / schema.Views.Count), "Added view " + vs.ViewName + " to the SQLite database"); 522 | 523 | _log.Debug("added schema for SQLite view [" + vs.ViewName + "]"); 524 | 525 | } // foreach 526 | } // using 527 | 528 | _log.Debug("finished adding all table/view schemas for SQLite database"); 529 | } 530 | 531 | private static void AddSQLiteView(SQLiteConnection conn, ViewSchema vs, FailedViewDefinitionHandler handler) 532 | { 533 | // Prepare a CREATE VIEW DDL statement 534 | string stmt = vs.ViewSQL; 535 | _log.Info("\n\n" + stmt + "\n\n"); 536 | 537 | // Execute the query in order to actually create the view. 538 | SQLiteTransaction tx = conn.BeginTransaction(); 539 | try 540 | { 541 | SQLiteCommand cmd = new SQLiteCommand(stmt, conn, tx); 542 | cmd.ExecuteNonQuery(); 543 | 544 | tx.Commit(); 545 | } 546 | catch (SQLiteException ex) 547 | { 548 | tx.Rollback(); 549 | 550 | if (handler != null) 551 | { 552 | ViewSchema updated = new ViewSchema(); 553 | updated.ViewName = vs.ViewName; 554 | updated.ViewSQL = vs.ViewSQL; 555 | 556 | // Ask the user to supply the new view definition SQL statement 557 | string sql = handler(updated); 558 | 559 | if (sql == null) 560 | return; // Discard the view 561 | else 562 | { 563 | // Try to re-create the view with the user-supplied view definition SQL 564 | updated.ViewSQL = sql; 565 | AddSQLiteView(conn, updated, handler); 566 | } 567 | } 568 | else 569 | throw; 570 | } // catch 571 | } 572 | 573 | /// 574 | /// Creates the CREATE TABLE DDL for SQLite and a specific table. 575 | /// 576 | /// The SQLite connection 577 | /// The table schema object for the table to be generated. 578 | private static void AddSQLiteTable(SQLiteConnection conn, TableSchema dt) 579 | { 580 | // Prepare a CREATE TABLE DDL statement 581 | string stmt = BuildCreateTableQuery(dt); 582 | 583 | _log.Info("\n\n" + stmt + "\n\n"); 584 | 585 | // Execute the query in order to actually create the table. 586 | SQLiteCommand cmd = new SQLiteCommand(stmt, conn); 587 | cmd.ExecuteNonQuery(); 588 | } 589 | 590 | /// 591 | /// returns the CREATE TABLE DDL for creating the SQLite table from the specified 592 | /// table schema object. 593 | /// 594 | /// The table schema object from which to create the SQL statement. 595 | /// CREATE TABLE DDL for the specified table. 596 | private static string BuildCreateTableQuery(TableSchema ts) 597 | { 598 | StringBuilder sb = new StringBuilder(); 599 | 600 | sb.Append("CREATE TABLE [" + ts.TableName + "] (\n"); 601 | 602 | bool pkey = false; 603 | for(int i=0; i 0 & !pkey) 614 | { 615 | sb.Append(",\n"); 616 | sb.Append(" PRIMARY KEY ("); 617 | for (int i = 0; i < ts.PrimaryKey.Count; i++) 618 | { 619 | sb.Append("["+ts.PrimaryKey[i]+"]"); 620 | if (i < ts.PrimaryKey.Count - 1) 621 | sb.Append(", "); 622 | } // for 623 | sb.Append(")\n"); 624 | } 625 | else 626 | sb.Append("\n"); 627 | 628 | // add foreign keys... 629 | if (ts.ForeignKeys.Count > 0) 630 | { 631 | sb.Append(",\n"); 632 | for (int i = 0; i < ts.ForeignKeys.Count; i++) 633 | { 634 | ForeignKeySchema foreignKey = ts.ForeignKeys[i]; 635 | string stmt = string.Format(" FOREIGN KEY ([{0}])\n REFERENCES [{1}]([{2}])", 636 | foreignKey.ColumnName, foreignKey.ForeignTableName, foreignKey.ForeignColumnName); 637 | 638 | sb.Append(stmt); 639 | if (i < ts.ForeignKeys.Count - 1) 640 | sb.Append(",\n"); 641 | } // for 642 | } 643 | 644 | sb.Append("\n"); 645 | sb.Append(");\n"); 646 | 647 | // Create any relevant indexes 648 | if (ts.Indexes != null) 649 | { 650 | for (int i = 0; i < ts.Indexes.Count; i++) 651 | { 652 | string stmt = BuildCreateIndex(ts.TableName, ts.Indexes[i]); 653 | sb.Append(stmt + ";\n"); 654 | } // for 655 | } // if 656 | 657 | string query = sb.ToString(); 658 | return query; 659 | } 660 | 661 | /// 662 | /// Creates a CREATE INDEX DDL for the specified table and index schema. 663 | /// 664 | /// The name of the indexed table. 665 | /// The schema of the index object 666 | /// A CREATE INDEX DDL (SQLite format). 667 | private static string BuildCreateIndex(string tableName, IndexSchema indexSchema) 668 | { 669 | StringBuilder sb = new StringBuilder(); 670 | sb.Append("CREATE "); 671 | if (indexSchema.IsUnique) 672 | sb.Append("UNIQUE "); 673 | sb.Append("INDEX [" + tableName+"_"+indexSchema.IndexName + "]\n"); 674 | sb.Append("ON [" + tableName+"]\n"); 675 | sb.Append("("); 676 | for (int i = 0; i < indexSchema.Columns.Count; i++) 677 | { 678 | sb.Append("["+indexSchema.Columns[i].ColumnName+"]"); 679 | if (!indexSchema.Columns[i].IsAscending) 680 | sb.Append(" DESC"); 681 | if (i < indexSchema.Columns.Count - 1) 682 | sb.Append(", "); 683 | } // for 684 | sb.Append(")"); 685 | 686 | return sb.ToString(); 687 | } 688 | 689 | /// 690 | /// Used when creating the CREATE TABLE DDL. Creates a single row 691 | /// for the specified column. 692 | /// 693 | /// The column schema 694 | /// A single column line to be inserted into the general CREATE TABLE DDL statement 695 | private static string BuildColumnStatement(ColumnSchema col, TableSchema ts, ref bool pkey) 696 | { 697 | StringBuilder sb = new StringBuilder(); 698 | sb.Append("\t\""+col.ColumnName + "\"\t\t"); 699 | 700 | // Special treatment for IDENTITY columns 701 | if (col.IsIdentity) 702 | { 703 | if (ts.PrimaryKey.Count == 1 && (col.ColumnType == "tinyint" || col.ColumnType == "int" || col.ColumnType == "smallint" || 704 | col.ColumnType == "bigint" || col.ColumnType == "integer")) 705 | { 706 | sb.Append("integer PRIMARY KEY AUTOINCREMENT"); 707 | pkey = true; 708 | } 709 | else 710 | sb.Append("integer"); 711 | } 712 | else 713 | { 714 | if (col.ColumnType == "int") 715 | sb.Append("integer"); 716 | else 717 | { 718 | sb.Append(col.ColumnType); 719 | } 720 | if (col.Length > 0) 721 | sb.Append("(" + col.Length + ")"); 722 | } 723 | if (!col.IsNullable) 724 | sb.Append(" NOT NULL"); 725 | 726 | if (col.IsCaseSensitivite.HasValue && !col.IsCaseSensitivite.Value) 727 | sb.Append(" COLLATE NOCASE"); 728 | 729 | string defval = StripParens(col.DefaultValue); 730 | defval = DiscardNational(defval); 731 | _log.Debug("DEFAULT VALUE BEFORE [" + col.DefaultValue + "] AFTER [" + defval + "]"); 732 | if (defval != string.Empty && defval.ToUpper().Contains("GETDATE")) 733 | { 734 | _log.Debug("converted SQL Server GETDATE() to CURRENT_TIMESTAMP for column ["+col.ColumnName+"]"); 735 | sb.Append(" DEFAULT (CURRENT_TIMESTAMP)"); 736 | } 737 | else if (defval != string.Empty && IsValidDefaultValue(defval)) 738 | sb.Append(" DEFAULT " + defval); 739 | 740 | return sb.ToString(); 741 | } 742 | 743 | /// 744 | /// Discards the national prefix if exists (e.g., N'sometext') which is not 745 | /// supported in SQLite. 746 | /// 747 | /// The value. 748 | /// 749 | private static string DiscardNational(string value) 750 | { 751 | Regex rx = new Regex(@"N\'([^\']*)\'"); 752 | Match m = rx.Match(value); 753 | if (m.Success) 754 | return m.Groups[1].Value; 755 | else 756 | return value; 757 | } 758 | 759 | /// 760 | /// Check if the DEFAULT clause is valid by SQLite standards 761 | /// 762 | /// 763 | /// 764 | private static bool IsValidDefaultValue(string value) 765 | { 766 | if (IsSingleQuoted(value)) 767 | return true; 768 | 769 | double testnum; 770 | if (!double.TryParse(value, out testnum)) 771 | return false; 772 | return true; 773 | } 774 | 775 | private static bool IsSingleQuoted(string value) 776 | { 777 | value = value.Trim(); 778 | if (value.StartsWith("'") && value.EndsWith("'")) 779 | return true; 780 | return false; 781 | } 782 | 783 | /// 784 | /// Strip any parentheses from the string. 785 | /// 786 | /// The string to strip 787 | /// The stripped string 788 | private static string StripParens(string value) 789 | { 790 | Regex rx = new Regex(@"\(([^\)]*)\)"); 791 | Match m = rx.Match(value); 792 | if (!m.Success) 793 | return value; 794 | else 795 | return StripParens(m.Groups[1].Value); 796 | } 797 | 798 | /// 799 | /// Reads the entire SQL Server DB schema using the specified connection string. 800 | /// 801 | /// The connection string used for reading SQL Server schema. 802 | /// A handler for progress notifications. 803 | /// The selection handler which allows the user to select 804 | /// which tables to convert. 805 | /// database schema objects for every table/view in the SQL Server database. 806 | private static DatabaseSchema ReadSqlServerSchema(string connString, SqlConversionHandler handler, 807 | SqlTableSelectionHandler selectionHandler) 808 | { 809 | // First step is to read the names of all tables in the database 810 | List tables = new List(); 811 | using (SqlConnection conn = new SqlConnection(connString)) 812 | { 813 | conn.Open(); 814 | 815 | List tableNames = new List(); 816 | List tblschema = new List(); 817 | 818 | // This command will read the names of all tables in the database 819 | SqlCommand cmd = new SqlCommand(@"select * from INFORMATION_SCHEMA.TABLES where TABLE_TYPE = 'BASE TABLE'", conn); 820 | using (SqlDataReader reader = cmd.ExecuteReader()) 821 | { 822 | while (reader.Read()) 823 | { 824 | tableNames.Add((string)reader["TABLE_NAME"]); 825 | tblschema.Add((string)reader["TABLE_SCHEMA"]); 826 | } // while 827 | } // using 828 | 829 | // Next step is to use ADO APIs to query the schema of each table. 830 | int count = 0; 831 | for (int i=0; i updated = selectionHandler(tables); 852 | if (updated != null) 853 | tables = updated; 854 | } // if 855 | 856 | Regex removedbo = new Regex(@"dbo\.", RegexOptions.Compiled | RegexOptions.IgnoreCase); 857 | 858 | // Continue and read all of the views in the database 859 | List views = new List(); 860 | using (SqlConnection conn = new SqlConnection(connString)) 861 | { 862 | conn.Open(); 863 | 864 | SqlCommand cmd = new SqlCommand(@"SELECT TABLE_NAME, VIEW_DEFINITION from INFORMATION_SCHEMA.VIEWS", conn); 865 | using (SqlDataReader reader = cmd.ExecuteReader()) 866 | { 867 | int count = 0; 868 | while (reader.Read()) 869 | { 870 | ViewSchema vs = new ViewSchema(); 871 | vs.ViewName = (string)reader["TABLE_NAME"]; 872 | vs.ViewSQL = reader["VIEW_DEFINITION"] as string ?? ""; 873 | 874 | // Remove all ".dbo" strings from the view definition 875 | vs.ViewSQL = removedbo.Replace(vs.ViewSQL, string.Empty); 876 | 877 | views.Add(vs); 878 | 879 | count++; 880 | CheckCancelled(); 881 | handler(false, true, 50+(int)(count * 50.0 / views.Count), "Parsed view " + vs.ViewName); 882 | 883 | _log.Debug("parsed view schema for [" + vs.ViewName + "]"); 884 | } // while 885 | } // using 886 | 887 | } // using 888 | 889 | DatabaseSchema ds = new DatabaseSchema(); 890 | ds.Tables = tables; 891 | ds.Views = views; 892 | return ds; 893 | } 894 | 895 | /// 896 | /// Convenience method for checking if the conversion progress needs to be cancelled. 897 | /// 898 | private static void CheckCancelled() 899 | { 900 | if (_cancelled) 901 | throw new ApplicationException("User cancelled the conversion"); 902 | } 903 | 904 | /// 905 | /// Creates a TableSchema object using the specified SQL Server connection 906 | /// and the name of the table for which we need to create the schema. 907 | /// 908 | /// The SQL Server connection to use 909 | /// The name of the table for which we wants to create the table schema. 910 | /// A table schema object that represents our knowledge of the table schema 911 | private static TableSchema CreateTableSchema(SqlConnection conn, string tableName, string tschma) 912 | { 913 | TableSchema res = new TableSchema(); 914 | res.TableName = tableName; 915 | res.TableSchemaName = tschma; 916 | res.Columns = new List(); 917 | SqlCommand cmd = new SqlCommand(@"SELECT COLUMN_NAME,COLUMN_DEFAULT,IS_NULLABLE,DATA_TYPE, " + 918 | @" (columnproperty(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity')) AS [IDENT], "+ 919 | @"CHARACTER_MAXIMUM_LENGTH AS CSIZE "+ 920 | "FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '" + tableName + "' ORDER BY " + 921 | "ORDINAL_POSITION ASC", conn); 922 | using (SqlDataReader reader = cmd.ExecuteReader()) 923 | { 924 | while (reader.Read()) 925 | { 926 | object tmp = reader["COLUMN_NAME"]; 927 | if (tmp is DBNull) 928 | continue; 929 | string colName = (string)reader["COLUMN_NAME"]; 930 | 931 | tmp = reader["COLUMN_DEFAULT"]; 932 | string colDefault; 933 | if (tmp is DBNull) 934 | colDefault = string.Empty; 935 | else 936 | colDefault = (string)tmp; 937 | 938 | tmp = reader["IS_NULLABLE"]; 939 | bool isNullable = ((string)tmp == "YES"); 940 | string dataType = (string)reader["DATA_TYPE"]; 941 | bool isIdentity = false; 942 | if (reader["IDENT"] != DBNull.Value) 943 | isIdentity = ((int)reader["IDENT"]) == 1 ? true : false; 944 | int length = reader["CSIZE"] != DBNull.Value ? Convert.ToInt32(reader["CSIZE"]) : 0; 945 | 946 | ValidateDataType(dataType); 947 | 948 | // Note that not all data type names need to be converted because 949 | // SQLite establishes type affinity by searching certain strings 950 | // in the type name. For example - everything containing the string 951 | // 'int' in its type name will be assigned an INTEGER affinity 952 | if (dataType == "timestamp") 953 | dataType = "blob"; 954 | else if (dataType == "date") 955 | dataType = "date"; 956 | else if (dataType == "datetime" || dataType == "smalldatetime" || dataType == "datetime2") 957 | dataType = "datetime"; 958 | else if (dataType == "time") 959 | dataType = "datetime"; 960 | else if (dataType == "decimal") 961 | dataType = "numeric"; 962 | else if (dataType == "money" || dataType == "smallmoney") 963 | dataType = "numeric"; 964 | else if (dataType == "binary" || dataType == "varbinary" || 965 | dataType == "image") 966 | dataType = "blob"; 967 | else if (dataType == "tinyint") 968 | dataType = "smallint"; 969 | else if (dataType == "bigint") 970 | dataType = "integer"; 971 | else if (dataType == "sql_variant") 972 | dataType = "blob"; 973 | else if (dataType == "xml") 974 | dataType = "varchar"; 975 | else if (dataType == "uniqueidentifier") 976 | dataType = "guid"; 977 | else if (dataType == "ntext") 978 | dataType = "text"; 979 | else if (dataType == "nchar") 980 | dataType = "char"; 981 | 982 | if (dataType == "bit" || dataType == "int") 983 | { 984 | if (colDefault == "('False')") 985 | colDefault = "(0)"; 986 | else if (colDefault == "('True')") 987 | colDefault = "(1)"; 988 | } 989 | 990 | colDefault = FixDefaultValueString(colDefault); 991 | 992 | ColumnSchema col = new ColumnSchema(); 993 | col.ColumnName = colName; 994 | col.ColumnType = dataType; 995 | col.Length = length; 996 | col.IsNullable = isNullable; 997 | col.IsIdentity = isIdentity; 998 | col.DefaultValue = AdjustDefaultValue(colDefault); 999 | res.Columns.Add(col); 1000 | } // while 1001 | } // using 1002 | 1003 | // Find PRIMARY KEY information 1004 | SqlCommand cmd2 = new SqlCommand(@"EXEC sp_pkeys '" + tableName + "'", conn); 1005 | using (SqlDataReader reader = cmd2.ExecuteReader()) 1006 | { 1007 | res.PrimaryKey = new List(); 1008 | while (reader.Read()) 1009 | { 1010 | string colName = (string)reader["COLUMN_NAME"]; 1011 | res.PrimaryKey.Add(colName); 1012 | } // while 1013 | } // using 1014 | 1015 | // Find COLLATE information for all columns in the table 1016 | SqlCommand cmd4 = new SqlCommand( 1017 | @"EXEC sp_tablecollations '" + tschma + "." + tableName + "'", conn); 1018 | using (SqlDataReader reader = cmd4.ExecuteReader()) 1019 | { 1020 | while (reader.Read()) 1021 | { 1022 | bool? isCaseSensitive = null; 1023 | string colName = (string)reader["name"]; 1024 | if (reader["tds_collation"] != DBNull.Value) 1025 | { 1026 | byte[] mask = (byte[])reader["tds_collation"]; 1027 | if ((mask[2] & 0x10) != 0) 1028 | isCaseSensitive = false; 1029 | else 1030 | isCaseSensitive = true; 1031 | } // if 1032 | 1033 | if (isCaseSensitive.HasValue) 1034 | { 1035 | // Update the corresponding column schema. 1036 | foreach (ColumnSchema csc in res.Columns) 1037 | { 1038 | if (csc.ColumnName == colName) 1039 | { 1040 | csc.IsCaseSensitivite = isCaseSensitive; 1041 | break; 1042 | } 1043 | } // foreach 1044 | } // if 1045 | } // while 1046 | } // using 1047 | 1048 | try 1049 | { 1050 | // Find index information 1051 | SqlCommand cmd3 = new SqlCommand( 1052 | @"exec sp_helpindex '" + tschma + "." + tableName + "'", conn); 1053 | using (SqlDataReader reader = cmd3.ExecuteReader()) 1054 | { 1055 | res.Indexes = new List(); 1056 | while (reader.Read()) 1057 | { 1058 | string indexName = (string)reader["index_name"]; 1059 | string desc = (string)reader["index_description"]; 1060 | string keys = (string)reader["index_keys"]; 1061 | 1062 | // Don't add the index if it is actually a primary key index 1063 | if (desc.Contains("primary key")) 1064 | continue; 1065 | 1066 | IndexSchema index = BuildIndexSchema(indexName, desc, keys); 1067 | res.Indexes.Add(index); 1068 | } // while 1069 | } // using 1070 | } 1071 | catch (Exception ex) 1072 | { 1073 | _log.Warn("failed to read index information for table [" + tableName + "]"); 1074 | } // catch 1075 | 1076 | return res; 1077 | } 1078 | 1079 | /// 1080 | /// Small validation method to make sure we don't miss anything without getting 1081 | /// an exception. 1082 | /// 1083 | /// The datatype to validate. 1084 | private static void ValidateDataType(string dataType) 1085 | { 1086 | if (dataType == "int" || dataType == "smallint" || 1087 | dataType == "bit" || dataType == "float" || 1088 | dataType == "real" || dataType == "nvarchar" || 1089 | dataType == "varchar" || dataType == "timestamp" || 1090 | dataType == "varbinary" || dataType == "image" || 1091 | dataType == "text" || dataType == "ntext" || 1092 | dataType == "bigint" || 1093 | dataType == "char" || dataType == "numeric" || 1094 | dataType == "binary" || dataType == "smalldatetime" || 1095 | dataType == "smallmoney" || dataType == "money" || 1096 | dataType == "tinyint" || dataType == "uniqueidentifier" || 1097 | dataType == "xml" || dataType == "sql_variant" || 1098 | dataType == "decimal" || dataType == "nchar" || 1099 | dataType == "date" || 1100 | dataType == "time" || 1101 | dataType == "datetime" || dataType == "datetime2") 1102 | return; 1103 | throw new ApplicationException("Validation failed for data type [" + dataType + "]"); 1104 | } 1105 | 1106 | /// 1107 | /// Does some necessary adjustments to a value string that appears in a column DEFAULT 1108 | /// clause. 1109 | /// 1110 | /// The original default value string (as read from SQL Server). 1111 | /// Adjusted DEFAULT value string (for SQLite) 1112 | private static string FixDefaultValueString(string colDefault) 1113 | { 1114 | bool replaced = false; 1115 | string res = colDefault.Trim(); 1116 | 1117 | // Find first/last indexes in which to search 1118 | int first = -1; 1119 | int last = -1; 1120 | for (int i = 0; i < res.Length; i++) 1121 | { 1122 | if (res[i] == '\'' && first == -1) 1123 | first = i; 1124 | if (res[i] == '\'' && first != -1 && i > last) 1125 | last = i; 1126 | } // for 1127 | 1128 | if (first != -1 && last > first) 1129 | return res.Substring(first, last - first + 1); 1130 | 1131 | StringBuilder sb = new StringBuilder(); 1132 | for (int i = 0; i < res.Length; i++) 1133 | { 1134 | if (res[i] != '(' && res[i] != ')') 1135 | { 1136 | sb.Append(res[i]); 1137 | replaced = true; 1138 | } 1139 | } 1140 | if (replaced) 1141 | return "(" + sb.ToString() + ")"; 1142 | else 1143 | return sb.ToString(); 1144 | } 1145 | 1146 | 1147 | 1148 | /// 1149 | /// Add foreign key schema object from the specified components (Read from SQL Server). 1150 | /// 1151 | /// The SQL Server connection to use 1152 | /// The table schema to whom foreign key schema should be added to 1153 | private static void CreateForeignKeySchema(SqlConnection conn, TableSchema ts) 1154 | { 1155 | ts.ForeignKeys = new List(); 1156 | 1157 | SqlCommand cmd = new SqlCommand( 1158 | @"SELECT " + 1159 | @" ColumnName = CU.COLUMN_NAME, " + 1160 | @" ForeignTableName = PK.TABLE_NAME, " + 1161 | @" ForeignColumnName = PT.COLUMN_NAME, " + 1162 | @" DeleteRule = C.DELETE_RULE, " + 1163 | @" IsNullable = COL.IS_NULLABLE " + 1164 | @"FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS C " + 1165 | @"INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS FK ON C.CONSTRAINT_NAME = FK.CONSTRAINT_NAME " + 1166 | @"INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS PK ON C.UNIQUE_CONSTRAINT_NAME = PK.CONSTRAINT_NAME " + 1167 | @"INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE CU ON C.CONSTRAINT_NAME = CU.CONSTRAINT_NAME " + 1168 | @"INNER JOIN " + 1169 | @" ( " + 1170 | @" SELECT i1.TABLE_NAME, i2.COLUMN_NAME " + 1171 | @" FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS i1 " + 1172 | @" INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE i2 ON i1.CONSTRAINT_NAME = i2.CONSTRAINT_NAME " + 1173 | @" WHERE i1.CONSTRAINT_TYPE = 'PRIMARY KEY' " + 1174 | @" ) " + 1175 | @"PT ON PT.TABLE_NAME = PK.TABLE_NAME " + 1176 | @"INNER JOIN INFORMATION_SCHEMA.COLUMNS AS COL ON CU.COLUMN_NAME = COL.COLUMN_NAME AND FK.TABLE_NAME = COL.TABLE_NAME " + 1177 | @"WHERE FK.Table_NAME='" + ts.TableName + "'", conn); 1178 | 1179 | using (SqlDataReader reader = cmd.ExecuteReader()) 1180 | { 1181 | while (reader.Read()) 1182 | { 1183 | ForeignKeySchema fkc = new ForeignKeySchema(); 1184 | fkc.ColumnName = (string)reader["ColumnName"]; 1185 | fkc.ForeignTableName = (string)reader["ForeignTableName"]; 1186 | fkc.ForeignColumnName = (string)reader["ForeignColumnName"]; 1187 | fkc.CascadeOnDelete = (string)reader["DeleteRule"] == "CASCADE"; 1188 | fkc.IsNullable = (string)reader["IsNullable"] == "YES"; 1189 | fkc.TableName = ts.TableName; 1190 | ts.ForeignKeys.Add(fkc); 1191 | } 1192 | } 1193 | } 1194 | 1195 | /// 1196 | /// Builds an index schema object from the specified components (Read from SQL Server). 1197 | /// 1198 | /// The name of the index 1199 | /// The description of the index 1200 | /// Key columns that are part of the index. 1201 | /// An index schema object that represents our knowledge of the index 1202 | private static IndexSchema BuildIndexSchema(string indexName, string desc, string keys) 1203 | { 1204 | IndexSchema res = new IndexSchema(); 1205 | res.IndexName = indexName; 1206 | 1207 | // Determine if this is a unique index or not. 1208 | string[] descParts = desc.Split(','); 1209 | foreach (string p in descParts) 1210 | { 1211 | if (p.Trim().Contains("unique")) 1212 | { 1213 | res.IsUnique = true; 1214 | break; 1215 | } 1216 | } // foreach 1217 | 1218 | // Get all key names and check if they are ASCENDING or DESCENDING 1219 | res.Columns = new List(); 1220 | string[] keysParts = keys.Split(','); 1221 | foreach (string p in keysParts) 1222 | { 1223 | Match m = _keyRx.Match(p); 1224 | if (!m.Success) 1225 | { 1226 | throw new ApplicationException("Illegal key name [" + p + "] in index [" + 1227 | indexName + "]"); 1228 | } 1229 | 1230 | string key = m.Groups[1].Value; 1231 | IndexColumn ic = new IndexColumn(); 1232 | ic.ColumnName = key; 1233 | if (m.Groups[2].Success) 1234 | ic.IsAscending = false; 1235 | else 1236 | ic.IsAscending = true; 1237 | 1238 | res.Columns.Add(ic); 1239 | } // foreach 1240 | 1241 | return res; 1242 | } 1243 | 1244 | /// 1245 | /// More adjustments for the DEFAULT value clause. 1246 | /// 1247 | /// The value to adjust 1248 | /// Adjusted DEFAULT value string 1249 | private static string AdjustDefaultValue(string val) 1250 | { 1251 | if (val == null || val == string.Empty) 1252 | return val; 1253 | 1254 | Match m = _defaultValueRx.Match(val); 1255 | if (m.Success) 1256 | return m.Groups[1].Value; 1257 | return val; 1258 | } 1259 | 1260 | /// 1261 | /// Creates SQLite connection string from the specified DB file path. 1262 | /// 1263 | /// The path to the SQLite database file. 1264 | /// SQLite connection string 1265 | private static string CreateSQLiteConnectionString(string sqlitePath, string password) 1266 | { 1267 | SQLiteConnectionStringBuilder builder = new SQLiteConnectionStringBuilder(); 1268 | builder.DataSource = sqlitePath; 1269 | if (password != null) 1270 | builder.Password = password; 1271 | builder.PageSize = 4096; 1272 | builder.UseUTF16Encoding = true; 1273 | string connstring = builder.ConnectionString; 1274 | 1275 | return connstring; 1276 | } 1277 | #endregion 1278 | 1279 | #region Trigger related 1280 | private static void AddTriggersForForeignKeys(string sqlitePath, IEnumerable schema, 1281 | string password, SqlConversionHandler handler) 1282 | { 1283 | // Connect to the newly created database 1284 | string sqliteConnString = CreateSQLiteConnectionString(sqlitePath, password); 1285 | using (SQLiteConnection conn = new SQLiteConnection(sqliteConnString)) 1286 | { 1287 | conn.Open(); 1288 | // foreach 1289 | foreach (TableSchema dt in schema) 1290 | { 1291 | try 1292 | { 1293 | AddTableTriggers(conn, dt); 1294 | } 1295 | catch (Exception ex) 1296 | { 1297 | _log.Error("AddTableTriggers failed", ex); 1298 | throw; 1299 | } 1300 | } 1301 | 1302 | } // using 1303 | 1304 | _log.Debug("finished adding triggers to schema"); 1305 | } 1306 | 1307 | private static void AddTableTriggers(SQLiteConnection conn, TableSchema dt) 1308 | { 1309 | IList triggers = TriggerBuilder.GetForeignKeyTriggers(dt); 1310 | foreach (TriggerSchema trigger in triggers) 1311 | { 1312 | SQLiteCommand cmd = new SQLiteCommand(WriteTriggerSchema(trigger), conn); 1313 | cmd.ExecuteNonQuery(); 1314 | } 1315 | } 1316 | #endregion 1317 | 1318 | /// 1319 | /// Gets a create script for the triggerSchema in sqlite syntax 1320 | /// 1321 | /// Trigger to script 1322 | /// Executable script 1323 | public static string WriteTriggerSchema(TriggerSchema ts) 1324 | { 1325 | return @"CREATE TRIGGER [" + ts.Name + "] " + 1326 | ts.Type + " " + ts.Event + 1327 | " ON [" + ts.Table + "] " + 1328 | "BEGIN " + ts.Body + " END;"; 1329 | } 1330 | 1331 | #region Private Variables 1332 | private static bool _isActive = false; 1333 | private static bool _cancelled = false; 1334 | private static Regex _keyRx = new Regex(@"([a-zA-Z_0-9]+)(\(\-\))?"); 1335 | private static Regex _defaultValueRx = new Regex(@"\(N(\'.*\')\)"); 1336 | private static ILog _log = LogManager.GetLogger(typeof(SqlServerToSQLite)); 1337 | #endregion 1338 | } 1339 | 1340 | /// 1341 | /// This handler is called whenever a progress is made in the conversion process. 1342 | /// 1343 | /// TRUE indicates that the entire conversion process is finished. 1344 | /// TRUE indicates that the current step finished successfully. 1345 | /// Progress percent (0-100) 1346 | /// A message that accompanies the progress. 1347 | public delegate void SqlConversionHandler(bool done, bool success, int percent, string msg); 1348 | 1349 | /// 1350 | /// This handler allows the user to change which tables get converted from SQL Server 1351 | /// to SQLite. 1352 | /// 1353 | /// The original SQL Server DB schema 1354 | /// The same schema minus any table we don't want to convert. 1355 | public delegate List SqlTableSelectionHandler(List schema); 1356 | 1357 | /// 1358 | /// This handler is called in order to handle the case when copying the SQL Server view SQL 1359 | /// statement is not enough and the user needs to either update the view definition himself 1360 | /// or discard the view definition from the generated SQLite database. 1361 | /// 1362 | /// The problematic view definition 1363 | /// The updated view definition, or NULL in case the view should be discarded 1364 | public delegate string FailedViewDefinitionHandler(ViewSchema vs); 1365 | } 1366 | -------------------------------------------------------------------------------- /DbAccess/TableSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | public class TableSchema 8 | { 9 | public string TableName; 10 | 11 | public string TableSchemaName; 12 | 13 | public List Columns; 14 | 15 | public List PrimaryKey; 16 | 17 | public List ForeignKeys; 18 | 19 | public List Indexes; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /DbAccess/TriggerBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | 8 | public static class TriggerBuilder 9 | { 10 | public static IList GetForeignKeyTriggers(TableSchema dt) 11 | { 12 | IList result = new List(); 13 | 14 | foreach (ForeignKeySchema fks in dt.ForeignKeys) 15 | { 16 | StringBuilder sb = new StringBuilder(); 17 | result.Add(GenerateInsertTrigger(fks)); 18 | result.Add(GenerateUpdateTrigger(fks)); 19 | result.Add(GenerateDeleteTrigger(fks)); 20 | } 21 | return result; 22 | } 23 | 24 | private static string MakeTriggerName(ForeignKeySchema fks, string prefix) 25 | { 26 | return prefix + "_"+fks.TableName + "_" + fks.ColumnName + "_" + fks.ForeignTableName + "_" + fks.ForeignColumnName; 27 | } 28 | 29 | public static TriggerSchema GenerateInsertTrigger(ForeignKeySchema fks) 30 | { 31 | TriggerSchema trigger = new TriggerSchema(); 32 | trigger.Name = MakeTriggerName(fks, "fki"); 33 | trigger.Type = TriggerType.Before; 34 | trigger.Event = TriggerEvent.Insert; 35 | trigger.Table = fks.TableName; 36 | 37 | string nullString = ""; 38 | if (fks.IsNullable) 39 | { 40 | nullString = " NEW." + fks.ColumnName + " IS NOT NULL AND"; 41 | } 42 | 43 | trigger.Body = "SELECT RAISE(ROLLBACK, 'insert on table " + fks.TableName + 44 | " violates foreign key constraint " + trigger.Name + "')" + 45 | " WHERE" + nullString + " (SELECT " + fks.ForeignColumnName + 46 | " FROM " + fks.ForeignTableName + " WHERE " + fks.ForeignColumnName + " = NEW." + 47 | fks.ColumnName + 48 | ") IS NULL; " ; 49 | return trigger; 50 | } 51 | 52 | public static TriggerSchema GenerateUpdateTrigger(ForeignKeySchema fks) 53 | { 54 | TriggerSchema trigger = new TriggerSchema(); 55 | trigger.Name = MakeTriggerName(fks, "fku"); 56 | trigger.Type = TriggerType.Before; 57 | trigger.Event = TriggerEvent.Update; 58 | trigger.Table = fks.TableName; 59 | 60 | string triggerName = trigger.Name; 61 | string nullString = ""; 62 | if (fks.IsNullable) 63 | { 64 | nullString = " NEW." + fks.ColumnName + " IS NOT NULL AND"; 65 | } 66 | 67 | trigger.Body = "SELECT RAISE(ROLLBACK, 'update on table " + fks.TableName + 68 | " violates foreign key constraint " + triggerName + "')" + 69 | " WHERE" + nullString + " (SELECT " + fks.ForeignColumnName + 70 | " FROM " + fks.ForeignTableName + " WHERE " + fks.ForeignColumnName + " = NEW." + 71 | fks.ColumnName + 72 | ") IS NULL; "; 73 | 74 | return trigger; 75 | } 76 | 77 | public static TriggerSchema GenerateDeleteTrigger(ForeignKeySchema fks) 78 | { 79 | TriggerSchema trigger = new TriggerSchema(); 80 | trigger.Name = MakeTriggerName(fks, "fkd"); 81 | trigger.Type = TriggerType.Before; 82 | trigger.Event = TriggerEvent.Delete; 83 | trigger.Table = fks.ForeignTableName; 84 | 85 | string triggerName = trigger.Name; 86 | 87 | if (!fks.CascadeOnDelete) 88 | { 89 | trigger.Body = "SELECT RAISE(ROLLBACK, 'delete on table " + fks.ForeignTableName + 90 | " violates foreign key constraint " + triggerName + "')" + 91 | " WHERE (SELECT " + fks.ColumnName + 92 | " FROM " + fks.TableName + " WHERE " + fks.ColumnName + " = OLD." + 93 | fks.ForeignColumnName + 94 | ") IS NOT NULL; "; 95 | } 96 | else 97 | { 98 | trigger.Body = "DELETE FROM [" + fks.TableName + "] WHERE " + fks.ColumnName + " = OLD." + 99 | fks.ForeignColumnName + "; "; 100 | 101 | } 102 | return trigger; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /DbAccess/TriggerSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | public enum TriggerEvent 8 | { 9 | Delete, 10 | Update, 11 | Insert 12 | } 13 | 14 | public enum TriggerType 15 | { 16 | After, 17 | Before 18 | } 19 | 20 | public class TriggerSchema 21 | { 22 | public string Name; 23 | public TriggerEvent Event; 24 | public TriggerType Type; 25 | public string Body; 26 | public string Table; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DbAccess/ViewSchema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace DbAccess 6 | { 7 | /// 8 | /// Describes a single view schema 9 | /// 10 | public class ViewSchema 11 | { 12 | /// 13 | /// Contains the view name 14 | /// 15 | public string ViewName; 16 | 17 | /// 18 | /// Contains the view SQL statement 19 | /// 20 | public string ViewSQL; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Convert SQL Server DB to SQLite DB # 2 | 3 | Liron Levi made a great converter over on CodeProject at [http://www.codeproject.com/KB/database/convsqlservertosqlite.aspx](http://www.codeproject.com/KB/database/convsqlservertosqlite.aspx) 4 | 5 | This project was placed in the public domain, so I've forked it on GitHub and made the following changes to the 1.16 version: 6 | 7 | 1. Converted to VS2010 solution/project format 8 | 2. Added support for SQL Server 2008 datetime2 format. 9 | 10 | There's probably other minor additions to be made to the project, but those two changes got me what I needed for now. 11 | 12 | Thanks Liron! 13 | -------------------------------------------------------------------------------- /SolutionInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("SQL Server To SQLite Converter")] 9 | [assembly: AssemblyDescription("Convert SQL Server databases to SQLite databases")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("SQLite Converter")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("5c16baa6-f948-40b6-a215-d454fd8c37d8")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | [assembly: AssemblyVersion("1.16.0.*")] 32 | //[assembly: AssemblyFileVersion("1.16.0.*")] 33 | -------------------------------------------------------------------------------- /SqlConverter.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{BF532AE3-9E18-4534-BD02-F0DA395FB642}" 5 | ProjectSection(SolutionItems) = preProject 6 | SolutionInfo.cs = SolutionInfo.cs 7 | EndProjectSection 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Converter", "Converter\Converter.csproj", "{1D389047-977D-4278-8357-AC0AC751B95E}" 10 | EndProject 11 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DbAccess", "DbAccess\DbAccess.csproj", "{23AAF1EF-2EB6-43AD-8103-A687F04A7288}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Any CPU = Debug|Any CPU 16 | Release|Any CPU = Release|Any CPU 17 | EndGlobalSection 18 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 19 | {1D389047-977D-4278-8357-AC0AC751B95E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {1D389047-977D-4278-8357-AC0AC751B95E}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {1D389047-977D-4278-8357-AC0AC751B95E}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {1D389047-977D-4278-8357-AC0AC751B95E}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {23AAF1EF-2EB6-43AD-8103-A687F04A7288}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | GlobalSection(SolutionProperties) = preSolution 29 | HideSolutionNode = FALSE 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /System.Data.SQLite.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elerch/Convert-SQL-Server-to-SQLite/95436df861744d69630e642f42635f5b1669d108/System.Data.SQLite.dll -------------------------------------------------------------------------------- /log4net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elerch/Convert-SQL-Server-to-SQLite/95436df861744d69630e642f42635f5b1669d108/log4net.dll --------------------------------------------------------------------------------