├── .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
--------------------------------------------------------------------------------